一、板級文件
通常會由MACHINE_START到板級文件
MACHINE_START(Chipname, "Chipname")
.atag_offset ?= 0x100,
.map_io ?= Chipname_map_io,
.init_early = Chipname_init_early,
.init_irq = Chipname_gic_init_irq,
.handle_irq = gic_handle_irq,
.timer ? = &Chipname_sys_timer,
.init_machine = Chipname_init,
.reserve ?= Chipname_reserve,
.restart ?= Chipname_restart,
MACHINE_END
.map_io是一個(gè)函數(shù)指針,這里指定了Chipname_map_io。函數(shù)實(shí)體為:
void __init Chipname_map_io(void)
{
...
}
二、內(nèi)存映射
芯片IO口操作分為兩類:
1.寄存器與內(nèi)存統(tǒng)一編址,又稱IO內(nèi)存
2.寄存器與內(nèi)存不統(tǒng)一編址,又稱IO端口
ARM芯片基本上是統(tǒng)一編址,訪問寄存器(包括系統(tǒng)寄存器、外設(shè)寄存器、IO口寄存器等)直接訪問該地址即可。
其中linux支持的寄存器地址尋址方式為內(nèi)存映射,即將內(nèi)核內(nèi)存1G的某一些地址映射給寄存器,這樣操作內(nèi)核虛擬內(nèi)存地址就是操作寄存器。
三、映射方式
linux內(nèi)核提供的映射方式有兩種:
1.靜態(tài)映射
使用map_desc結(jié)構(gòu)體進(jìn)行映射,其中map_desc結(jié)構(gòu)體為:
struct map_desc {
unsigned long virtual; //虛擬地址
unsigned long pfn; //__phys_to_pfn(物理地址) , 就是物理頁框號
unsigned long length; //長度
unsigned int type; //類型
};
舉例,填充一個(gè)映射信息結(jié)構(gòu)體,映射兩塊連續(xù)的地址空間,出現(xiàn)保留字就再映射一個(gè),或者遇到不需要控制的地址,否則一直連續(xù)映射:
static struct map_desc Chipname_io_desc[] __initdata = {
{
.virtual = 0xFE000000,
.pfn = __phys_to_pfn(0x10000000),
.length = 0xD0000,
.type = MT_DEVICE
},
{
.virtual = 0xFE100000,
.pfn = __phys_to_pfn(0x20000000),
.length = 0x700000,
.type = MT_DEVICE
}
};
然后調(diào)用iotable_init(Chipname_io_desc, ARRAY_SIZE(Chipname_io_desc));建立映射的函數(shù)
以后直接*(volatile unsigned int *)0xFE000000就能使用了。
2.動態(tài)映射
驅(qū)動中手動映射某一個(gè)地址
#define ioremap(cookie,size) ?__arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_nocache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_cached(cookie,size) ?__arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) ?__arm_ioremap((cookie), (size), MT_DEVICE_WC)
#define iounmap ? __arm_iounmap
cookie:物理地址
size:要映射的空間的大??;
返回虛擬地址
頭文件io.h
以后直接*(volatile unsigned int *)虛擬地址就能使用了。
擴(kuò)展:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) //include/linux/kernel.h,ARRAY_SIZE為計(jì)算數(shù)組的一維維度,計(jì)算方法為數(shù)組大小和數(shù)組單成員大小之商
#ifdef __CHECKER__
#define __must_be_array(arr) 0
#else
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) //include/linux/compiler-gcc.h
#endif
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))?//include/linux/bug.h,BUILD_BUG_ON_ZERO的作用在于將返回值轉(zhuǎn)化為編譯錯誤信息。顯然當(dāng)內(nèi)嵌函數(shù)返回值為0時(shí),也即類型相同時(shí),由于BUILD_BUG_ON_ZERO參數(shù)為非0而導(dǎo)致char[-1]而發(fā)出編譯器警告。
#ifndef __same_type
# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) //include/linux/compiler.h,gcc編譯器內(nèi)嵌的函數(shù),判斷一個(gè)變量的類型是否為某指定的類型,假如是就返回1,否則返回0。這里通過判斷指針和指針指向的第一個(gè)元素的指針是否是相同類型來判斷是否為數(shù)組。
#endif
arch/arm/mm/mmu.c
void __init iotable_init(struct map_desc *io_desc, int nr)
{
struct map_desc *md;
struct vm_struct *vm;
if (!nr)?return;
/*early_alloc_aligned
*
*/
vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
for (md = io_desc; nr; md++, nr--)
{
create_mapping(md, false);
vm->addr = (void *)(md->virtual & PAGE_MASK);
vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
vm->phys_addr = __pfn_to_phys(md->pfn);?
vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;?
vm->flags |= VM_ARM_MTYPE(md->type);
vm->caller = iotable_init;
vm_area_add_early(vm++);
}
}
?
電子發(fā)燒友App





































評論