《Linux驱动: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 起来之后将被丢弃。
各个成员函数在不同时期被调用:

  1. .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。
  2. init_irq在start_kernel() -> init_IRQ() -> init_arch_irq() 被调用
  3. 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 flash
    s3c_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])                                                          │   
  │         -> NAND Device Support (MTD_NAND [
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程界的小学生、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值