响应式网站 推广效果地推团队接单平台
文章目录
- 一,前言
- 二,硬件电路
- 2.1 Nand flash相关
- 2.2 S3c2440相关
- 2.3 Nand flash 位反转
- 三,Nand flash驱动框架
- 四,S3c2440 Nand Flash驱动的加载过程
- 4.1 S3c2440 Nand Flash -- 设备注册
- 4.2 S3c2440 Nand Flash -- 驱动注册
- 4.3 S3c2440 Nand Flash -- 设备-驱动匹配
- 4.3.1 设备注册到平台总线时的匹配
- 4.3.2 驱动注册到平台总线时的匹配
- 4.4 S3c2440 Nand Flash -- 调用驱动的probe函数
- 五,驱动的probe函数分析
- 5.1 使能时钟
- 5.2 端口映射
- 5.3 s3c2440 nand flash控制器设置
- 5.3.1 设置脉冲宽度和间隔
- 5.4 设置struct nand_chip
- 5.5 nand_scan流程分析
- 5.6 添加分区
- 5.6.1 遍历mtd_notifiers,通过其add接口添加分区
- 5.6.2 设置mtd_notifiers链表
- 5.6.2.1 nand flash 字符设备
- 5.6.2.2 nand flash的块设备
- 5.6.3 块设备初始化请求队列
- 六,总结
- 6.1 nand flash字符设备创建过程
- 6.2 nand flash块设备创建过程
- 6.3 一次应用层读取Nand Flash数据的过程
一,前言
nand flash驱动开发总结,涉及到s3c2440芯片nand flash控制器的设置及操作、K9F2G08U0C nand flash的设置及操作、平台总线-驱动-设备模型等相关知识。
二,硬件电路
2.1 Nand flash相关
LDATA0~LDATA7:传输命令、地址和数据。
RnB:nand flash的工作状态,0表示就绪,1表示正忙。
CLE:决定DATA0~DATA7传输的是数据还是命令,1为命令,0为数据。
nFCE:nand flash的片选,1表示选中,0表示未选中(选中才能对其进行操作)。
ALE:决定DATA0~DATA7传输的是数据还是地址,1为地址,0为数据(CLE和ALE为0)。
nFWE:为0表示写操作(写命令、地址、数据)。
nFRE:为0表示读操作。
2.2 S3c2440相关
根据Nand Flash的芯片书册知,其需要五个字节表示地址,即五个地址周期,其一页的大小为2KB,8位数据/地址传输。根据S3c2440芯片书册可知,需要NCON、GPG13、GPG14为1,GPG15为0,即前者加上拉电阻,后者加下拉电阻。
2.3 Nand flash 位反转
由于Nand Flash的固有特性,在读写数据过程中,偶然会产生一位或几位数据错误(这种概率很低),bit位从“1”变为“0”,或者从“1”变为“0”。当位反转发生在关键的代码、数据上时,有可能导致系统崩溃。当仅仅是报告位反转,重新读取即可。如果确实发生了位反转,则必须有相应的错误检测/恢复措施。在NAND Flash上发生位反转的概率很高,推荐使用EDC/ECC进行错误检测和恢复。
三,Nand flash驱动框架
四,S3c2440 Nand Flash驱动的加载过程
S3c2440 Nand Flash驱动使用了平台总线-驱动-设备模型。
4.1 S3c2440 Nand Flash – 设备注册
linux-2.6.22.6/.config
CONFIG_ARCH_S3C2440=y
linux-2.6.22.6/arch/arm/mach-s3c2440/mach-smdk2440.c
MACHINE_START(S3C2440, "SMDK2440")/* Maintainer: Ben Dooks <ben@fluff.org> */.phys_io = S3C2410_PA_UART,.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,.boot_params = S3C2410_SDRAM_PA + 0x100,.init_irq = s3c24xx_init_irq,.map_io = smdk2440_map_io,.init_machine = smdk2440_machine_init,.timer = &s3c24xx_timer,
MACHINE_END
将上面的宏展开
static const struct machine_desc __mach_desc_SMDK2440__attribute_used____attribute__((__section__(".arch.info.init"))) = {.nr = MACH_TYPE_SMDK2410, /* architecture number */.name = "SMDK2440", /* architecture name *//* Maintainer: Jonas Dietsche */.phys_io = S3C2410_PA_UART, /* start of physical io */.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,.boot_params = S3C2410_SDRAM_PA + 0x100, /* tagged list */.map_io = smdk2440_map_io, /* IO mapping function */.init_irq = s3c24xx_init_irq,.init_machine = smdk2440_machine_init,.timer = &s3c24xx_timer,
}
MACHINE_START主要是定义了"struct machine_desc"的类型,放在 section(“.arch.info.init”),是初始化数据,Kernel 起来之后将被丢弃。
各个成员函数在不同时期被调用:
- .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。
- init_irq在start_kernel() -> init_IRQ() -> init_arch_irq() 被调用
- map_io 在 setup_arch() -> paging_init() -> devicemaps_init()被调用
其他主要都在 setup_arch() 中用到。
系统初始化时,会调用smdk2440_machine_init
// linux-2.6.22.6/arch/arm/mach-s3c2440/mach-smdk2440.c
static void __init smdk2440_machine_init(void)
{s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));smdk_machine_init();
}// linux-2.6.22.6/arch/arm/plat-s3c24xx/common-smdk.c
void __init smdk_machine_init(void)
{......// 配置nand flashs3c_device_nand.dev.platform_data = &smdk_nand_info;......// 注册到平台总线platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));......
}// 配置了nand flash各信号脉冲宽度或时间间隔,以及分区
static struct s3c2410_platform_nand smdk_nand_info = {.tacls = 20,.twrph0 = 60,.twrph1 = 20,.nr_sets = ARRAY_SIZE(smdk_nand_sets),.sets = smdk_nand_sets,
};
// 设置nand flash的分区
static struct s3c2410_nand_set smdk_nand_sets[] = {[0] = {.name = "NAND",.nr_chips = 1,.nr_partitions = ARRAY_SIZE(smdk_default_nand_part),.partitions = smdk_default_nand_part,},
};
// 配置nand flash的具体分区,四个分区
static struct mtd_partition smdk_default_nand_part[] = {[0] = {.name = "bootloader",.size = 0x00040000,.offset = 0,},[1] = {.name = "params",.offset = MTDPART_OFS_APPEND,.size = 0x00020000,},[2] = {.name = "kernel",.offset = MTDPART_OFS_APPEND,.size = 0x00200000,},[3] = {.name = "root",.offset = MTDPART_OFS_APPEND,.size = MTDPART_SIZ_FULL,}
};// linux-2.6.22.6/arch/arm/plat-s3c24xx/common-smdk.c
static struct platform_device __initdata *smdk_devs[] = {&s3c_device_nand,......
};// linux-2.6.22.6/arch/arm/plat-s3c24xx/devs.c
struct platform_device s3c_device_nand = {.name = "s3c2410-nand",.id = -1,.num_resources = ARRAY_SIZE(s3c_nand_resource),.resource = s3c_nand_resource,
};static struct resource s3c_nand_resource[] = {[0] = {.start = S3C2410_PA_NAND,.end = S3C2410_PA_NAND + S3C24XX_SZ_NAND - 1,.flags = IORESOURCE_MEM,}
};// 将s3c_device_nand设备注册到平台总线
// linux-2.6.22.6/drivers/base/platform.c
int platform_add_devices(struct platform_device **devs, int num)
{int i, ret = 0;for (i = 0; i < num; i++) {ret = platform_device_register(devs[i]);if (ret) {while (--i >= 0)platform_device_unregister(devs[i]);break;}}return ret;
}
4.2 S3c2440 Nand Flash – 驱动注册
make menuconfig,将s3c2440 nand flash驱动加载到内核中,系统启动时便会自动加载驱动。
-> Device Drivers │ │ -> Memory Technology Device (MTD) support (MTD [=y]