s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0);
我们可以这样控制外设寄存器,想过它怎么实现的吗?
首先分析下 struct machine_desc (include/asm-arm/Mach/Arch.h)
这是一个非常重要的结构体,内核通过 machine_desc 来控制体系架构相关部分的初始化,包括map_io,init_irq,init_machine,pthys_io,timer等
struct machine_desc { /* * Note! The first five elements are used * by assembler code in head-armv.S */ unsigned int nr; /* architecture number */ unsigned int phys_ram; /* start of physical ram */ unsigned int phys_io; /* start of physical io */ unsigned int io_pg_offst; /* byte offset for io * page tabe entry */ const char *name; /* architecture name */ unsigned long boot_params; /* tagged list */ unsigned int video_start; /* start of video RAM */ unsigned int video_end; /* end of video RAM */ unsigned int reserve_lp0 :1; /* never has lp0 */ unsigned int reserve_lp1 :1; /* never has lp1 */ unsigned int reserve_lp2 :1; /* never has lp2 */ unsigned int soft_reboot :1; /* soft reboot */ void (*fixup)(struct machine_desc *, struct tag *, char **, struct meminfo *); void (*map_io)(void);/* IO mapping function */ void (*init_irq)(void); struct sys_timer *timer; /* system tick timer */ void (*init_machine)(void); }; |
那我们怎么创建自己的
machine_desc呢?
内核给我们提供了一个宏:
#define MACHINE_START(_type,_name) / const struct machine_desc __mach_desc_##_type / __attribute__((__section__(".arch.info.init"))) = { / .nr = MACH_TYPE_##_type, / .name = _name, #define MACHINE_END / }; |
这样我们就可以定义自己的machine_desc了
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch * to SMDK2410 */ /* Maintainer: Jonas Dietsche */ .phys_ram = S3C2410_SDRAM_PA, .phys_io = S3C2410_PA_UART, .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = smdk2410_map_io, .init_irq = smdk2410_init_irq, .init_machine = sdmk2410_init, .timer = &s3c24xx_timer, MACHINE_END |
这里我们创建了 machine_desc,并给其中一些成员赋了值,这相当于是内核给我们提供的编程接口,这样就可以调用自己的函数了。
这其中map_io 在 setup_arch 中调用调用,我们跟进去会发现:
在smdk2410_map_io-->s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc))->iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)) 看到:
void __init iotable_init(struct map_desc *io_desc, int nr) { int i; for (i = 0; i < nr; i++) create_mapping(io_desc + i); }
|
就是在这里调用create_mapping()创建的页表,这里的第一个参数,map_desc 定义如下:
struct map_desc { unsigned long virtual; unsigned long physical; unsigned long length; unsigned int type; }; |
create_mapping()就是通过这个结构体创建的映射表,这样我们可以通过创建 map_desc 然后传给这个函数就可以创建相应的 虚拟地址-->物理地址 映射.
在 inlcude/asm-arch/Arch-s3c2410/Map.h
定义了每一种资源用于 map_desc 变量的宏定义,如:
/* MMC controller - available on the S3C2400 */ #define S3C2400_VA_MMC S3C2400_ADDR(0x00700000) #define S3C2400_PA_MMC (0x15A00000) #define S3C2400_SZ_MMC SZ_1M
/* UARTs */ #define S3C24XX_VA_UART S3C2410_ADDR(0x00800000) #define S3C2400_PA_UART (0x15000000) #define S3C2410_PA_UART (0x50000000) #define S3C24XX_SZ_UART SZ_1M
/* Timers */ #define S3C24XX_VA_TIMER S3C2410_ADDR(0x00900000) #define S3C2400_PA_TIMER (0x15100000) #define S3C2410_PA_TIMER (0x51000000) #define S3C24XX_SZ_TIMER SZ_1M
|
然后针对具体的某个外设,有具体寄存器的定义,如:
include/asm/arch-s3c2410/regs-timer.h
#ifndef __ASM_ARCH_REGS_TIMER_H #define __ASM_ARCH_REGS_TIMER_H "$Id: timer.h,v 1.4 2003/05/06 19:30:50 ben Exp $"
#define S3C2410_TIMERREG(x) (S3C24XX_VA_TIMER + (x)) #define S3C2410_TIMERREG2(tmr,reg) S3C2410_TIMERREG((reg)+0x0c+((tmr)*0x0c))
#define S3C2410_TCFG0 S3C2410_TIMERREG(0x00) #define S3C2410_TCFG1 S3C2410_TIMERREG(0x04) #define S3C2410_TCON S3C2410_TIMERREG(0x08)
#define S3C2410_TCFG_PRESCALER0_MASK (255<<0) #define S3C2410_TCFG_PRESCALER1_MASK (255<<8) #define S3C2410_TCFG_PRESCALER1_SHIFT (8) #define S3C2410_TCFG_DEADZONE_MASK (255<<16) #define S3C2410_TCFG_DEADZONE_SHIFT (16) ......................... |
我分析的只是一个大概,具体请参考:ARM Linux静态映射分析--易松华
http://www.docin.com/p-63183730.html