编者:linux中的nand的移植由于使用了MTD技术,所以就没有想象的那么复杂了。
1 Linux-2.6.32.2 内核所支持的Nand Flash 类型
Linux2.6.32.2 已经自带了大部分Nand Flash 驱动, 在linux-2.6.32.2/drivers/mtd/nand/nand_ids.c 文件中,定义了所支持的各种Nand Flash 类型。
2 修改Nand Flash 分区表
但是系统默认的分区不是我们所需的,所以要自已修改,除此之外,还有Nand Flash的结构信息需要增加填写,以便能够适合系统自带的Nand Flash 驱动接口,这可以参考SMDK2440 中关于Nand Flash 设备注册的一些信息。
打开/arch/arm/plat-24xx/common-smdk.c,可以看到这样一个结构体:
static
struct mtd_partition smdk_default_nand_part[] = {
[ 0] = {
.name = " Boot Agent ",
.size = SZ_16K,
.offset = 0,
},
[ 1] = {
.name = " S3C2410 flash partition 1 ",
.offset = 0,
.size = SZ_2M,
},
[ 2] = {
.name = " S3C2410 flash partition 2 ",
.offset = SZ_4M,
.size = SZ_4M,
},
[ 3] = {
.name = " S3C2410 flash partition 3 ",
.offset = SZ_8M,
.size = SZ_2M,
},
[ 4] = {
.name = " S3C2410 flash partition 4 ",
.offset = SZ_1M * 10,
.size = SZ_4M,
},
[ 5] = {
.name = " S3C2410 flash partition 5 ",
.offset = SZ_1M * 14,
.size = SZ_1M * 10,
},
[ 6] = {
.name = " S3C2410 flash partition 6 ",
.offset = SZ_1M * 24,
.size = SZ_1M * 24,
},
[ 7] = {
.name = " S3C2410 flash partition 7 ",
.offset = SZ_1M * 48,
.size = SZ_16M,
}
};
[ 0] = {
.name = " Boot Agent ",
.size = SZ_16K,
.offset = 0,
},
[ 1] = {
.name = " S3C2410 flash partition 1 ",
.offset = 0,
.size = SZ_2M,
},
[ 2] = {
.name = " S3C2410 flash partition 2 ",
.offset = SZ_4M,
.size = SZ_4M,
},
[ 3] = {
.name = " S3C2410 flash partition 3 ",
.offset = SZ_8M,
.size = SZ_2M,
},
[ 4] = {
.name = " S3C2410 flash partition 4 ",
.offset = SZ_1M * 10,
.size = SZ_4M,
},
[ 5] = {
.name = " S3C2410 flash partition 5 ",
.offset = SZ_1M * 14,
.size = SZ_1M * 10,
},
[ 6] = {
.name = " S3C2410 flash partition 6 ",
.offset = SZ_1M * 24,
.size = SZ_1M * 24,
},
[ 7] = {
.name = " S3C2410 flash partition 7 ",
.offset = SZ_1M * 48,
.size = SZ_16M,
}
};
这其实就是Nand Flash 的分区表,在Linux-2.6.32.2 中,nand 驱动是被注册为平台设备的,这同样在/arch/arm/plat-24xx/common-smdk.c 文件中看出,如下:
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,
};
/* devices we initialise */
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
};
.tacls = 20,
.twrph0 = 60,
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(smdk_nand_sets),
.sets = smdk_nand_sets,
};
/* devices we initialise */
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
};
参考以上结构信息,我们也在自己的mach-mini2440.c 中照此添加实现,同时需要参考友善之臂原厂内核中的Nand 分区表,如下图所示:
加入头文件 arch/arm/mach-s3c2440/mach-mini2440.c
#include <plat/nand.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
在mach-mini2440.c 中加入以下代码;
static
struct mtd_partition mini2440_default_nand_part[] = {
[ 0] = {
.name = " supervivi ", // 这里是bootloader 所在的分区,可以放置u-boot, supervivi 等内容,对应/dev/mtdblock0
.size = 0x00040000, //256K
.offset = 0,
},
[ 1] = {
.name = " param ", // 这里是supervivi 的参数区,其实也属于bootloader 的一部分,如果u-boot 比较大,可以把此区域覆盖掉,不会影响系统启动,对应/dev/mtdblock1
.offset = 0x00040000,
.size = 0x00020000,//128K
},
[ 2] = {
.name = " Kernel ", // 内核所在的分区,大小为5M,足够放下大部分自己定制的巨型内核了,比如内核使用了更大的Linux Logo 图片等,对应/dev/mtdblock2
.offset = 0x00060000,
.size = 0x00500000,//5M
},
[ 3] = {
.name = " root ", // 文件系统分区,友善之臂主要用来存放yaffs2 文件系统内容,对应/dev/mtdblock3
.offset = 0x00560000,
.size = 1024 * 1024 * 1024, //1G
},
[ 4] = {
.name = " nand ", // 此区域代表了整片的nand flash,主要是预留使用,比如以后可以通过应用程序访问读取/dev/mtdblock4 就能实现备份整片nand flash 了。
.offset = 0x00000000,
.size = 1024 * 1024 * 1024, //
}
};
[ 0] = {
.name = " supervivi ", // 这里是bootloader 所在的分区,可以放置u-boot, supervivi 等内容,对应/dev/mtdblock0
.size = 0x00040000, //256K
.offset = 0,
},
[ 1] = {
.name = " param ", // 这里是supervivi 的参数区,其实也属于bootloader 的一部分,如果u-boot 比较大,可以把此区域覆盖掉,不会影响系统启动,对应/dev/mtdblock1
.offset = 0x00040000,
.size = 0x00020000,//128K
},
[ 2] = {
.name = " Kernel ", // 内核所在的分区,大小为5M,足够放下大部分自己定制的巨型内核了,比如内核使用了更大的Linux Logo 图片等,对应/dev/mtdblock2
.offset = 0x00060000,
.size = 0x00500000,//5M
},
[ 3] = {
.name = " root ", // 文件系统分区,友善之臂主要用来存放yaffs2 文件系统内容,对应/dev/mtdblock3
.offset = 0x00560000,
.size = 1024 * 1024 * 1024, //1G
},
[ 4] = {
.name = " nand ", // 此区域代表了整片的nand flash,主要是预留使用,比如以后可以通过应用程序访问读取/dev/mtdblock4 就能实现备份整片nand flash 了。
.offset = 0x00000000,
.size = 1024 * 1024 * 1024, //
}
};
;这里是开发板的nand flash 设置表,因为板子上只有一片,因此也就只有一个表
static
struct s3c2410_nand_set mini2440_nand_sets[] = {
[ 0] = {
.name = " NAND ",
.nr_chips = 1,
.nr_partitions = ARRAY_SIZE(mini2440_default_nand_part),
.partitions = mini2440_default_nand_part,
},
};
[ 0] = {
.name = " NAND ",
.nr_chips = 1,
.nr_partitions = ARRAY_SIZE(mini2440_default_nand_part),
.partitions = mini2440_default_nand_part,
},
};
;这里是nand flash 本身的一些特性,一般需要对照datasheet 填写,大部分情况下按照以下参数填写即可
static
struct s3c2410_platform_nand mini2440_nand_info = {
.tacls = 20,
.twrph0 = 60,
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(mini2440_nand_sets),
.sets = mini2440_nand_sets,
.ignore_unset_ecc = 1,
};
.tacls = 20,
.twrph0 = 60,
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(mini2440_nand_sets),
.sets = mini2440_nand_sets,
.ignore_unset_ecc = 1,
};
除此之外,还需要把nand flash 设备注册到系统中,
static
struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_nand, //把nand flash 设备添加到开发板的设备列表结构
};
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_nand, //把nand flash 设备添加到开发板的设备列表结构
};
3 从启动信息中查看分区表
至此,就完成了nand flash 驱动的移植,此时在内核根目录执行“make zImage”,把生成的zImage 烧写到开发板,可以在启动时看到信息,它们正是我们刚刚添加的nandflash 分区信息,以及开发板本身nand flash 的一些信息,这里可以看到是256M 的nand flash。
PS:上面是按手册介绍的,说了一大堆,但是很明显我们刚才声明的结构体信息没有和s3c_device_nand产生任何关联,这样肯定就不会正常工作了。同样使在这个文件里面,一定要在下面的这个函数中加上一句这样的话:
static
void __init mini2440_machine_init(
void)
{
#if defined (LCD_WIDTH)
s3c24xx_fb_set_platdata(&mini2440_fb_info);
#endif
s3c_i2c0_set_platdata(NULL);
s3c2410_gpio_cfgpin(S3C2410_GPC( 0), S3C2410_GPC0_LEND);
s3c_device_nand.dev.platform_data = &mini2440_nand_info;
s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
s3c_pm_init();
}
{
#if defined (LCD_WIDTH)
s3c24xx_fb_set_platdata(&mini2440_fb_info);
#endif
s3c_i2c0_set_platdata(NULL);
s3c2410_gpio_cfgpin(S3C2410_GPC( 0), S3C2410_GPC0_LEND);
s3c_device_nand.dev.platform_data = &mini2440_nand_info;
s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
s3c_pm_init();
}
这样才把这个信息关联到设备,就可以正常工作了。
进制换算 1M= 210K= 220B
0x500000=5 × 24×5 = 5 × 220 = 5M
0x40000 =4 × 24×4 = 4 × 216 = 4 × 26 × 210 = 256 × 210 = 256K