http://www.cnblogs.com/lifexy/p/7701181.html
1、本节使用的nand flash型号为K9F2G08U0C,它的命令如下:
1.1 我们以上图的Read ID(读ID)为例,它的时序图如下:
首先需要使用CE片选
1)使能CLE
2)发出0x90命令,并发出WE写脉冲
3)复位CLE,然后使能ALE
4)发出0x00地址,并发出WE写脉冲
5)设置CLE和ALE为低电平
6)while判断nRE(读使能)是否为低电平
7)读出8个I/O的数据,并发出RE上升沿脉冲
(我们的nand flash为8个I/O口)
1.2 nand flash 控制器介绍
在2440中有个nand flash 控制器,它会自动控制CLE,ALE那些控制引脚,我们只需要配置控制器,就可以直接写命令,写地址,读写数据到它的寄存器中便能完成(读写数据之前需要判断RnB脚),如下图所示:
若在nand flash 控制器下,我们读ID就只需要如下几步(非常方便):
1)将寄存器NFCONT(0x4E000004)的bit1 = 0,来使能片选
2)写入寄存器NFCMMD(0x4E000008) = 0x90,发送命令
3)写入寄存器NFADDR(0x4E00000C) = 0x00,发送地址
4)while判断nRE(读使能)是否为低电平
5)读寄存器NFDATA(0x4E000010),来读取数据
1.3 我们在uboot中测试,通过md和mw命令来实现读id(x要小写)
刚好对用了我们nand flash手册里的数据(0xEC表示厂家ID,0xDA表示设备ID):
若我们要退出读ID命令时,只需要reset就行,同样地,要退出读数据/写数据时,也是reset。
1.4 reset的命令为0xff,它的时序图如下所示:
1.5 同样地,参考读地址时序图来看看:
其中Column Address 对应 列地址,表示某页里的2k地址
Row Address 对应 行地址,表示具体的某一页
5个地址的周期图,如下所示:
因为我们的nand flash = 256MB = (2k*128M)b
所以row Address = 128M = 2^17(A27~A11)
所以column Adress = 2k = 2^11(A10~A0)
1.7 我们现在读0地址的内容
使用命令 nand dump 0读出nand flash 0地址的内容
从这一节当中的第一张图,可以发现Read,先发出00h命令,再发出30h命令。
(md.b 后面的1表示读1次)
2、接下来我们来参考自带的nand flash,位于drivers/mtd/nand/s3c2410.c中
2.1 为什么nand在mtd目录下
因为mtd(memory technology device 存储技术设备)是用于访问memory设备(ROM、flash)的Linux子系统。MTD的主要目的是为了使新的memory设备的驱动更加简单,为此它在硬件和上层之间提供了一个抽象的接口
2.2 首先来看s3c2440.c的入口函数
static int __init s3c2410_nand_init(void)
{
printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
platform_driver_register(&s3c2412_nand_driver);
platform_driver_register(&s3c2440_nand_driver);
return platform_driver_register(&s3c2410_nand_driver);
}
在入口函数中,注册了一个platform平台设备驱动,也是说当与nand flash设备匹配时,就会调用s3c2440_nand_driver->probe()来初始化
我们进入probe函数中,看看是如何初始化
static int s3c24xx_nand_probe(struct platform_device *pdev,
enum s3c_cpu_type cpu_type)
{
... ...
err = s3c2410_nand_inithw(info, pdev); //初始化硬件hardware,设置TACLS、TWRPH0、TWRPH1通信时序等
... ...
s3c2410_nand_init_chip(info, nmtd, sets); //初始化芯片
... ...
nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1); //扫描nand flash
... ...
s3c2410_nand_add_partition(info, nmtd, sets); //来添加mtd分区
... ...
}
通过上面代码和注释,得出:驱动主要调用内核的nand_scan()函数,add_mtd_partitions()函数,来完成注册nand flash
3 上面probe()里的nand_scan()扫描函数 位于 drivers/mtd/nand/nand_base.c
它会调用nand_scan()->nand_scan_ident()->nand_get_flash_type()来获取flash存储器的类型
以及nand_scan()->nand_scan_ident()->nand_tail()来构造mtd设备的成员(实现对nand flash的读,写,擦除等)
3.1 其中nand_get_flash_type()函数如下所示:
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, int busw, int *maf_id)
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
chip->select_chip(mtd, 0);//调用nand_chip结构体的成员select_chip使能flash片选
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);//3.2调用nand_chip结构体的成员cmdfunc,发送读id命令,最后数据保存在mtd结构体里
*maf_id = chip->read_byte(mtd);//获取厂家ID
d