1、NAND FLASH的硬件连接:
实验用的NAND FLASH芯片为K9F2G08U0C,它是三星公司的存储芯片,它的大小为256M。它的接线图如下所示:
它的每个引脚的分别为LDATA0-LDATA7为数据引脚、CLE为发送命令使能引脚、ALE为发送地址使能引脚、CE为芯片使能引脚、WE为写使能引脚、WP为写保护引脚、R/B为芯片是否繁忙的状态指示引脚,如下图所示:
2、NAND FLASH的操作:
根据NAND FLASH的芯片手册可以知道需要操作NAND FLASH一般的流程是发出命令、发出地址、发出数据/读数据,下面依次分析。
a、发命令,对于NAND FLASH芯片来说需要1、选中芯片(CE为低电平);2、CLE设为高电平、ALE设为低电平;3、在DATA0-DATA7上输出命令数据;4、在WE上发出一个上升沿的信号。这样命令数据就会被写入命令的命令寄存器。而对于S3C2440来说,只要简单的令NFCMD寄存器为命令值S3C2440的NAND控制器就可以完成1-4的操作。
b、发地址,对于NAND FLASH芯片来说需要1、选中芯片(CE为低电平);2、ALE设为高电平、CLE设为低电平;3、在DATA0-DATA7上输出地址数据;4、在WE上发出一个上升沿的信号。这样地址数据就会被写入地址寄存器。分析图中可知需要5个字节的地址。而对于S3C2440来说,只要简单的令NFADDR寄存器为地址值S3C2440的NAND控制器就可以完成1-4的操作。
c、发数据/读数据,对于NAND FLASH芯片来说需要1、选中芯片(CE为低电平);2、ALE设为低电平、CLE设为低电平;3、在DATA0-DATA7上输出数据或读入数据;4、在WE上发出一个上升沿的信号,这样数据就会被写入、在RE上发出一个上升沿信号,这样数据就会被读出。而对于S3C2440来说,只要简单的令NFDATA寄存器为数据值或读NFDATA寄存器,S3C2440的NAND控制器就可以完成1-4的操作。
3、读NAND FLASH数据:
从图中可以看出要读FLASH某个地址的数据需要先发出0x00命令、在发出5字节地址、接着发出0x30命令,过一会等R/B信号不忙之后就可以连续的在RE信号的上升沿时读出数据了。
4、读芯片的ID
读芯片的ID很简单,只要先写入0x90命令,再接着写入0x00地址。接着就可以读出连续的5个字节的芯片ID了,对于K9F2G08U0C,它的芯片ID是EC DA 10 15 44,如下图:
5、NAND FLASH的驱动框架,对与NAND FLASH这个设备,LINUX已经给我们分好了框架,它将稳定的协议层等都做在一个层里面,而将与硬件相关的做在另外一个层里面,而我们写驱动只要更改与硬件相关的方面就可以了。框架如下:
下面从LINUX的启动信息可以得到“S3C24XX NAND Driver”字样,在内核源码中搜索它,可以在driversmtdnands3c2410.c文件中得到以下的一些调用层次关系:
s3c2410_nand_init
s3c2440_nand_probe
s3c2410_nand_inithw
s3c2410_nand_init_chip
nand_scan // driversmtdnandnand_base.c 根据nand_chip的底层操作函数构造mtd_info
nand_scan_ident
nand_set_defaults
if (!chip->select_chip)
chip->select_chip = nand_select_chip;/* 默认值不适用 */
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;
if (chip->waitfunc == NULL)
chip->waitfunc = nand_wait;
nand_get_flash_type
chip->select_chip(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
*maf_id = chip->read_byte(mtd)
dev_id = chip->read_byte(mtd);
nand_scan_tail
mtd->erase = nand_erase
mtd->read = nand_read;
mtd->write = nand_write;
s3c2410_nand_add_partition
add_mtd_device
list_for_each(this, &mtd_notifiers) { // 问. mtd_notifiers在哪里设置
// 答. drivers/mtd/mtd_blkdevs.c,mtdchar.c调用register_mtd_user
struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
not->add(mtd);
// mtd_notify_add 和 blktrans_notify_add
先看字符设备mtd_notify_add
class_device_create
class_device_create
再看块设备blktrans_notify_add
list_for_each(this, &blktrans_majors) { // 问. blktrans_majors在哪设置
// 答. driversmtdmdblock.c或mdblock_ro.c调用register_mtd_blktrans //注册队列
struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
tr->add_mtd(tr, mtd);
mtdblock_add_mtd
add_mtd_blktrans_dev
alloc_disk
set_capacity
gd->queue = tr->blkcore_priv->rq;//blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue
add_disk
}
}
接着搜索“end_request”这个块设备驱动程序的通用函数来找到NAND FLASH块设备的请求函数,在driversmtdmtd_blkdevs.c 文件中搜多到了它。通过这个文件可以看到块设备的通用框架的流程:
mtd_blktrans_ops->blkcore_priv-rq
gd->queue = tr->blkcore_priv->rq;
struct mtd_blktrans_ops *tr = new->tr;
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
add_mtd_blktrans_dev(dev);
mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
static void blktrans_notify_add(struct mtd_info *mtd)
static void blktrans_notify_add(struct mtd_info *mtd)
{
struct list_head *this;
if (mtd->type == MTD_ABSENT)
return;
list_for_each(this, &blktrans_majors) {
struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
tr->add_mtd(tr, mtd);
}
list_for_each(this, &mtd_notifiers) {//从头到尾访问mtd_notifiers链表
struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
not->add(mtd);//调用mtd_notifier结构体的add函数
}
add_mtd_device(struct mtd_info *mtd)
add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4);
读函数mtd_blktrans_ops->readsect
写函数mtd_blktrans_ops->writesect
首先NAND FLASH驱动框架也是采用驱动分层分离的方法
最终分析下来,NAND FLASH驱动框架涉及到的文件有:driversmtdmtdcore.c 、driversmtdmtd_blkdevs.c、driversmtdmdblock.c、driversmtdnandnand_base.c、driversmtdnands3c2410.c等
最终分析出读函数为mtd_blktrans_ops->readsect;写函数为mtd_blktrans_ops->writesect。最终定位到mtd->read与mtd->write,而这两个函数又可以定位到nand_read、nand_write;接着向下定位可以定位到nand_chip->select_chip、nand_chip->cmd_ctrl、nand_chip->IO_ADDR_R、nand_chip->IO_ADDR_W、nand_chip->dev_ready等等。
6、NAND FLASH的驱动程序的编写、测试
在第5部分最后已经分析到了需要我们提供的几个函数和参数,下面直接贴出代码:
/* 参考
* S3c2410.c (driversmtdnand)