分类:
2012-11-09 16:41:07
原文地址:Linux-IO内存-静态映射 作者:Cheney-Xu
Linux-IO内存-静态映射
通常来说,BSP需要提供芯片级驱动,并要为板级驱动提供一些服务,在为具体芯片移植linux内核时,通常都会建立芯片级外设I/O内存物理地址到虚拟地址的静态映射,这通常是通过板文件中的MACHINE_START宏中的map_io函数来实现的,map_io函数中通常通过调用 iotable_init函数来建立页映射关系,如:iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));这种静态映射关系通常通过map_desc结构体来描述,map_desc结构定义如下: |
struct map_desc { unsigned long virtual; unsigned long physical; unsigned long length; unsigned int type; }; #define MT_DEVICE 0 #define MT_CACHECLEAN 1 #define MT_MINICLEAN 2 #define MT_LOW_VECTORS 3 #define MT_HIGH_VECTORS 4 #define MT_MEMORY 5 #define MT_ROM 6 #define MT_IXP2000_DEVICE 7 |
我们来看一下BSP怎样使用map_desc |
static struct map_desc s3c_iodesc[] __initdata = { IODESC_ENT(GPIO), IODESC_ENT(IRQ), IODESC_ENT(MEMCTRL), IODESC_ENT(UART) }; |
其中IODESC_ENT定义如下(##为连接符,它会##两边的字符连接起来): |
#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE } IODESC_ENT(GPIO),展开如下: { (unsigned long)S3C24XX_VA_GPIO, S3C2410_PA_GPIO, S3C24XX_SZ_GPIO, MT_DEVICE }
|
其中include/asm-arm/arch-s3c2410/map.h中定义了外设IO内存中要使用的宏 |
这样便把芯片级外设IO内存物理地址与虚拟地址连接起来了 |
在GPIO的驱动程序,通常会这样使用GPIO口 |
void __init smdk2440_machine_init(void) { /* Configure the LEDs (even if we have no LED support)*/ s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP); s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF4, 0); s3c2410_gpio_setpin(S3C2410_GPF5, 0); s3c2410_gpio_setpin(S3C2410_GPF6, 0); s3c2410_gpio_setpin(S3C2410_GPF7, 0); s3c2410_pm_init(); } |
其中S3C2410_GPF4等定义如下: |
#define S3C2410_GPF4 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 4) #define S3C2410_GPF4_INP (0x00 << 8) #define S3C2410_GPF4_OUTP (0x01 << 8) #define S3C2410_GPF4_EINT4 (0x02 << 8)
#define S3C2410_GPF5 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 5) #define S3C2410_GPF5_INP (0x00 << 10) #define S3C2410_GPF5_OUTP (0x01 << 10) #define S3C2410_GPF5_EINT5 (0x02 << 10)
#define S3C2410_GPF6 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 6) #define S3C2410_GPF6_INP (0x00 << 12) #define S3C2410_GPF6_OUTP (0x01 << 12) #define S3C2410_GPF6_EINT6 (0x02 << 12)
#define S3C2410_GPF7 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 7) #define S3C2410_GPF7_INP (0x00 << 14) #define S3C2410_GPF7_OUTP (0x01 << 14) #define S3C2410_GPF7_EINT7 (0x02 << 14) |
其中S3C2410_GPIONO等定义如下: |
#define S3C2410_GPIONO(bank,offset) ((bank) + (offset)) #define S3C2410_GPIO_BANKA (32*0) #define S3C2410_GPIO_BANKB (32*1) #define S3C2410_GPIO_BANKC (32*2) #define S3C2410_GPIO_BANKD (32*3) #define S3C2410_GPIO_BANKE (32*4) #define S3C2410_GPIO_BANKF (32*5) #define S3C2410_GPIO_BANKG (32*6) #define S3C2410_GPIO_BANKH (32*7) |
所以,算出的S3C2410_GPF4 =》S3C2410_GPIONO(S3C2410_GPIO_BANKF, 4)=》S3C2410_GPIONO(32*5, 4)=》32*5+ 4 |
我们现来看一下s3c2410_gpio_cfgpin和s3c2410_gpio_setpin函数 |
s3c2410_gpio_cfgpin函数定义如下 |
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) { void __iomem *base = S3C2410_GPIO_BASE(pin); unsigned long mask; unsigned long con; unsigned long flags;
if (pin < S3C2410_GPIO_BANKB) { mask = 1 << S3C2410_GPIO_OFFSET(pin); } else { mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; }
local_irq_save(flags);
con = __raw_readl(base + 0x00); con &= ~mask; con |= function;
__raw_writel(con, base + 0x00);
local_irq_restore(flags); } |
s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP); 便是s3c2410_gpio_cfgpin(32*5+ 4,0x01 << 8) |
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO) #define S3C2410_GPIO_OFFSET(pin) ((pin) & 31) |
#define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000) #define S3C2400_PA_GPIO (0x15600000) #define S3C2410_PA_GPIO (0x56000000) #define S3C24XX_SZ_GPIO SZ_1M |
*base=((((32*5+ 4) & ~31) >> 1) + S3C24XX_VA_GPIO)=》((((32*5+ 4) & ~31) >> 1) + S3C2410_ADDR(0x00E00000)) |
其中S3C2410_ADDR定义如 下 |
|
#ifndef __ASSEMBLY__ #define S3C2410_ADDR(x) ((void __iomem *)0xF0000000 + (x)) #else #define S3C2410_ADDR(x) (0xF0000000 + (x)) #endif |
因此*base= ((((32*5+ 4) & ~31) >> 1) + 0xF0E00000) |
GPIOF的控制寄存器物理地址如下: |
|