Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1749395
  • 博文数量: 143
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2016-08-23 11:14
文章分类

全部博文(143)

文章存档

2022年(3)

2021年(13)

2020年(21)

2019年(8)

2018年(28)

2017年(7)

2016年(63)

我的朋友

分类: 嵌入式

2016-08-25 14:58:48

  文章背景:在ICETEK OMAPL138的开发板中,由于arm的大部分Pin脚是复用Pin脚,如SPI0、SPI1和GPIO是复用Pin脚,UART0、UART1和GPIO也是复用Pin脚等等,所以开发人员在写GPIO、SPI、UART等等驱动时,不可避免地需要优先配置PinMux。那么,本文以EMA_CLK Pin的配置,来分析TI提供内核中 PinMux代码的设计实现。

  1.首先,我们在PCB图中查看到我们需要研究的Pin脚名称:EMA_CLK。

  2.接着,我们就可以到内核的BSP(linux-kernel.sdk/arm/arch/mach-davinci/)中搜索并分析。
  第一阶段,搜索EMA_CLK。
  唯一被调用的地方只有1个:(注释[1]注释[2])
static const struct mux_config da850_pins[] = {
...
        MUX_CFG(DA850, EMA_CLK,         6,      0,      15,     1,      false)
...
}
  被放到:

static struct davinci_soc_info davinci_soc_info_da850 = {
...
        .pinmux_pins            = da850_pins,
        .pinmux_pins_num        = ARRAY_SIZE(da850_pins),
...
}
  再被调用:
davinci_common_init(&davinci_soc_info_da850);
  在_init davinci_common_init(struct davinci_soc_info *soc_info)中,soc_info被保存到davinci_soc_info,后者可被extern。

  第二阶段,搜索davinci_soc_info_da850下的pinmux_pins是如何被使用的。
  唯一被调用的函数,也是真正初始化的地方:
int __init_or_module davinci_cfg_reg(const unsigned long index)
  阅读函数可以看出是通过外部变量"davinci_soc_info"和入参"index"控制da850_pins中的某一条。要想知道EMA_CLK被谁掉用,还得接着继续看index的值。查看谁调用此函数?调用的地方有很多,排除非da850板子的,剩就是:
int da8xx_pinmux_setup(const short pins[])
{
...
       error = davinci_cfg_reg(pins[i]);
...
}
  查询调用的地方有很多,以da850_nor_pins为例(事实上也就仅da850_nor_pins下挂有DA850_EMA_CLK,这不是猜测的,在第一阶段中搜索EMA_CLK时就发现了):
ret = da8xx_pinmux_setup(da850_nor_pins);(其被da850_evm_init调用。其实所有复用pin的配置da8xx_pinmux_setup同是如此)
  接着查看da850_nor_pins中有什么:
const short da850_nor_pins[] __initdata = {
...
       DA850_EMA_CLK
...
}
  找到
enum davinci_da850_index {
...
       DA850_EMA_CLK,
...
}
  很明显DA850_EMA_CLK的值就是第一阶段中MUX_CFG(DA850, EMA_CLK,         6,      0,      15,     1,      false)所对应的da850_pins[]的下标,实在不信你自己数一数(注意:事实上da850_pins[]比davinci_da850_index数一数时少2个,但其实被kernel以补丁形式增加了,补丁:linux-kernel.sdk/patches/0001-DA850-OMAP-L138-Enable-UART1-RTS-CTS-line-pinmuxing.patch)。
  到此就首尾相接了,即在norflash相关的内核初始化代码中,通过调用da8xx_pinmux_setup(),再调到davinci_cfg_reg()中通过pinmux_pins对da850_pins中涉及EMA_CLK的总线做配置。即真正对复用pin脚做处理的函数是davinci_cfg_reg()中。

  3.最后,我们总结下,PinMux的配置。
  PinMux的配置表:
        MUX_CFG(DA850, EMA_CLK,         6,      0,     15,     1,      false)
  PinMux真正使配置表生效的地方:
int __init_or_module davinci_cfg_reg(const unsigned long index)
{

       void __iomem *base = soc_info->pinmux_base;


       if (cfg->mask) {
               unsigned        tmp1, tmp2;

               spin_lock_irqsave(&mux_spin_lock, flags);
               reg_orig = __raw_readl(base + cfg->mux_reg);

               mask = (cfg->mask << cfg->mask_offset);
               tmp1 = reg_orig & mask;
               reg = reg_orig & ~mask;

               tmp2 = (cfg->mode << cfg->mask_offset);
               reg |= tmp2;

               if (tmp1 != tmp2)
                       warn = 1;

               __raw_writel(reg, base + cfg->mux_reg);
               spin_unlock_irqrestore(&mux_spin_lock, flags);
       }
}
  函数中除了pinmux_base,其他mask_offset,mask,mode,mux_reg即是PinMux配置表中的值。而pinmux_base:(通过如下代码,不难看出pinmux_base的地址就是:首先在内核态中映射了起始地址为0x01c14000大小为SZ_4K的物理地址名为syscfg0,而pinmux_base取0x01c14120到结束的这段地址。查询芯片手册,PinMux正是处于SYSCFG0中)
       davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG0_VIRT(0x120);

       #define DA8XX_SYSCFG0_VIRT(x)        (da8xx_syscfg0_base + (x))

       da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);

       #define DA8XX_SYSCFG0_BASE        (IO_PHYS + 0x14000)

       #define IO_PHYS                                0x01c00000

备注[1]:
struct mux_config {
       const char *name;
       const char *mux_reg_name;
       const unsigned char mux_reg;
       const unsigned char mask_offset;
       const unsigned char mask;
       const unsigned char mode;
       bool debug;
};
备注[2]:
define MUX_CFG(soc, desc, muxreg, mode_offset, mode_mask, mux_mode, dbg)\
[soc##_##desc] = {                                                      \
                       .name =  #desc,                                 \
                       .debug = dbg,                                   \
                       .mux_reg_name = "PINMUX"#muxreg,                \
                       .mux_reg = PINMUX##muxreg,                      \
                       .mask_offset = mode_offset,                     \
                       .mask = mode_mask,                              \
                       .mode = mux_mode,                               \
               },
备注[3]:
#define PINMUX0                 0x00
#define PINMUX1                 0x04
#define PINMUX2                 0x08
#define PINMUX3                 0x0c
#define PINMUX4                 0x10
#define PINMUX5                 0x14
#define PINMUX6                 0x18
#define PINMUX7                 0x1c
#define PINMUX8                 0x20
#define PINMUX9                 0x24
#define PINMUX10                0x28
#define PINMUX11                0x2c
#define PINMUX12                0x30
#define PINMUX13                0x34
#define PINMUX14                0x38
#define PINMUX15                0x3c
#define PINMUX16                0x40
#define PINMUX17                0x44
#define PINMUX18                0x48
#define PINMUX19                0x4c

阅读(1460) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~