分类: 嵌入式
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