IO空间的静态映射基本过程
扫描二维码
随时随地手机看文章
IO端口与IO内存的概念:外设中的寄存器称为是IO端口,外设中的内存称为是IO内存。二者统称为IO空间。Linux内核是通过虚拟地址访问外设的。所以需要先将虚拟地址映射到相应外设的物理地址上,linux的映射方式有两种:静态映射(map_desc)和动态映射(ioremap),其实也是内核访问外设资源的方式。
2、静态映射基本过程:在驱动中配置寄存器,可以调用类似于s3c_gpio_cfgpin、s3c_gpio_setpull、gpio_direction_output等直接配置IO寄存器的函数。这些函数访问的虚拟地址,这些虚拟地址都是已经在启动启动的时候通过静态映射方式映射到IO寄存器的物理地址上。
静态映射概念:所谓的静态映射是指,虚拟地址到物理地址的转换所需要的页表在操作系统启动时已经配置好,不需要用户进行配置,虚拟地址到物理地址的查表转换可直接完成(fromnet)。
以s5pv210为例讲述:
MACHINE_START(SMDKV210,"SMDKV210")
/* Maintainer: Kukjin Kim
.boot_params =S5P_PA_SDRAM + 0x100,
.init_irq =s5pv210_init_irq,
.map_io = smdkv210_map_io,
.init_machine = smdkv210_machine_init,
#ifdefCONFIG_S5P_HIGH_RES_TIMERS
.timer = &s5p_systimer,
#else
.timer =&s5p_timer,
#endif
MACHINE_END
其中IO映射函数是smdkv210_map_io实现:
staticvoid __init smdkv210_map_io(void)
{
s5p_init_io(NULL,0, S5P_VA_CHIPID);
s3c24xx_init_clocks(24000000);
s5pv210_gpiolib_init();
s3c24xx_init_uarts(smdkv210_uartcfgs,
ARRAY_SIZE(smdkv210_uartcfgs));
#ifndefCONFIG_S5P_HIGH_RES_TIMERS
s5p_set_timer_source(S5P_PWM2, S5P_PWM4);
#endif
s5p_reserve_bootmem(s5pv210_media_devs,
ARRAY_SIZE(s5pv210_media_devs),
S5P_RANGE_MFC);
}
该函数中调用s5p_init_io进行地址的映射,
/*read cpu identification code */
void__inits5p_init_io(struct map_desc*mach_desc,
int size, void __iomem *cpuid_addr)
{
unsigned long idcode;
/* initialize the io descriptors we need forinitialization */
iotable_init(s5p_iodesc, ARRAY_SIZE(s5p_iodesc));
if (mach_desc)
iotable_init(mach_desc, size);
idcode = __raw_readl(cpuid_addr);
s3c_init_cpu(idcode,cpu_ids, ARRAY_SIZE(cpu_ids));
}
其中最重要是struct map_desc s5p_iodesc[]结构体 和 staticstruct map_desc s5pv210_iodesc[]:
structmap_desc{
unsigned long virtual; // IO空间映射后的虚拟地址
unsigned long pfn; // IO空间的物理地址所在的页帧号
unsigned long length; // IO空间的长度
unsigned int type; // IO空间的类型
};
/*minimal IO mapping这部分是最小系统层次的映射*/
staticstruct map_desc s5p_iodesc[] __initdata = {
{
.virtual =(unsigned long)S5P_VA_CHIPID,
.pfn =__phys_to_pfn(S5P_PA_CHIPID),
.length =SZ_4K,
.type =MT_DEVICE,
}, {
.virtual = (unsigned long)S3C_VA_SYS,
.pfn = __phys_to_pfn(S5P_PA_SYSCON),
.length = SZ_64K,
.type = MT_DEVICE,
},{
.virtual =(unsigned long)S3C_VA_TIMER,
.pfn =__phys_to_pfn(S5P_PA_TIMER),
.length =SZ_16K,
.type =MT_DEVICE,
},{
.virtual =(unsigned long)S3C_VA_WATCHDOG,
.pfn =__phys_to_pfn(S3C_PA_WDT),
.length =SZ_4K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)S5P_VA_SROMC,
.pfn =__phys_to_pfn(S5P_PA_SROMC),
.length =SZ_4K,
.type =MT_DEVICE,
},
};
/*Initial IO mappings*/
staticstruct map_desc s5pv210_iodesc[] __initdata = {
{
.virtual =(unsigned long)S5P_VA_SYSTIMER,
.pfn =__phys_to_pfn(S5PV210_PA_SYSTIMER),
.length =SZ_4K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)S5P_VA_GPIO,
.pfn =__phys_to_pfn(S5PV210_PA_GPIO),
.length =SZ_4K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)VA_VIC0,
.pfn =__phys_to_pfn(S5PV210_PA_VIC0),
.length =SZ_16K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)VA_VIC1,
.pfn =__phys_to_pfn(S5PV210_PA_VIC1),
.length =SZ_16K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)VA_VIC2,
.pfn =__phys_to_pfn(S5PV210_PA_VIC2),
.length =SZ_16K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)VA_VIC3,
.pfn =__phys_to_pfn(S5PV210_PA_VIC3),
.length =SZ_16K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)S3C_VA_UART,
.pfn =__phys_to_pfn(S3C_PA_UART),
.length =SZ_512K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)S5P_VA_DMC0,
.pfn =__phys_to_pfn(S5PV210_PA_DMC0),
.length =SZ_4K,
.type =MT_DEVICE,
}, {
.virtual =(unsigned long)S5P_VA_DMC1,
.pfn =__phys_to_pfn(S5PV210_PA_DMC1),
.length =SZ_4K,
.type =MT_DEVICE,
},{
.virtual = (unsigned long)S5P_VA_BUS_AXI_DSYS,
.pfn = __phys_to_pfn(S5PV210_PA_BUS_AXI_DSYS),
.length= SZ_4K,
.type = MT_DEVICE,