NAND FLASH是一个存储芯片。
在芯片上的DATA0~DATA7上既能传输数据也能传输地址。
当ALE为高电平时传输的是地址。
当CLE为高电平时传输的是命令。
当ALE和CLE都为低电平时传输的是数据。
将数据发给nand Flash后,在发送第二次数据之前还要判断芯片是否处于空闲状态。一般是通过引脚RnB来判断,一般是高电平代表就绪,低电平代表正忙。
操作Nand Flash的一般步骤是:
1. 发命令
选中芯片
CLE设置为高电平
在DATA0~DATA7上输出命令值
发出一个写脉冲
2. 发地址
选中芯片
ALE为高电平
在DATA0~DATA7上传输数据
发出一个写脉冲
3. 发数据
选中芯片
发出读脉冲
读取DATA0~DATA7上的数据。
使用UBOOT来体验NAND FLASH的操作:
读ID
选中 NFCONT的bit1设置为0 md.l 0x4e000004 1; mw.l 0x4e000004 1
发出命令0x90 NFCMMD=0X90 mw.b 0x4e000008 0x90;
发出地址0x00 NFADDR=0X00 mw.b 0x4e00000C 0x00;
读取数据得到0XEC val=NFDATA md.b 0x4e000010 1
读取数据得到device code val=NFDATA md.b 0x4e000010 1
退出读ID的状态 NFCMMD=0XFF mw.b 0x4e000008 0xff
NAND FLASH驱动程序层次
看内核启动信息
S3C24XX NAND Driver, (c)2004Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=330ns
NAND device: Manufacturer ID:0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
Scanning deviceforbad blocks
Bad eraseblock256 at 0x02000000Bad eraseblock257 at 0x02020000Bad eraseblock319 at 0x027e0000Bad eraseblock606 at 0x04bc0000Bad eraseblock608 at 0x04c00000Creating4 MTD partitions on "NAND 256MiB 3,3V 8-bit":0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"搜"S3C24XX NAND Driver"S3c2410.c (drivers\mtd\nand)
s3c2410_nand_inithw
s3c2410_nand_init_chip
nand_scan//drivers/mtd/nand/nand_base.c 根据nand_chip的底层操作函数识别NAND FLASH,构造mtd_info
nand_scan_ident
nand_set_defaultsif (!chip->select_chip)
chip->select_chip = nand_select_chip; //默认值不适用
if (chip->cmdfunc ==NULL)
chip->cmdfunc =nand_command;
chip->cmd_ctrl(mtd, command, ctrl);if (!chip->read_byte)
chip->read_byte =nand_read_byte;
readb(chip->IO_ADDR_R);if (chip->waitfunc ==NULL)
chip->waitfunc =nand_wait;
chip->dev_ready
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_partitions
add_mtd_device
list_for_each(this, &mtd_notifiers) { //问. mtd_notifiers在哪设置//答. drivers/mtd/mtdchar.c,mtd_blkdev.c调用register_mtd_user
struct mtd_notifier *not = list_entry(this, structmtd_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在哪设置//答. drivers\mtd\mdblock.c或mtdblock_ro.c register_mtd_blktrans
struct mtd_blktrans_ops *tr = list_entry(this, structmtd_blktrans_ops, list);
tr->add_mtd(tr, mtd);
mtdblock_add_mtd (drivers\mtd\mdblock.c)
add_mtd_blktrans_dev
alloc_disk
gd->queue = tr->blkcore_priv->rq; //tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
add_disk
驱动程序代码:
/** drivers\mtd\nand\s3c2410.c
* drivers\mtd\nand\at91_nand.c*/#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include
struct nand_chip *s3c_nand;struct mtd_info *s3c_mtd;struct clk *clk;structs3c_nand_regs{
unsignedlongnfconf;
unsignedlongnfcont;
unsignedlongnfcmd;
unsignedlongnfaddr;
unsignedlongnfdata;
unsignedlongnfeccd0;
unsignedlongnfeccd1;
unsignedlongnfeccd;
unsignedlongnfstat;
unsignedlongnfestat0;
unsignedlongnfestat1;
unsignedlongnfeecc0;
unsignedlongnfeecc1;
unsignedlongnfsecc;
unsignedlongnfsblk;
unsignedlongnfeblk;
};static struct mtd_partition s3c_nand_parts[] ={
[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,
}
};static volatile struct s3c_nand_regs *nand_regs;static void s3c2440_select_chip(struct mtd_info *mtd, intchipnr )
{if(chipnr == -1)
{/*取消选中*/nand_regs->nfcont |= (1<<1);
}else{/*选中 NFCONT^1 设置为1*/nand_regs->nfcont &= ~(1<<1);
}
}static void s3c2440_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned intctrl)
{if (cmd ==NAND_CMD_NONE)return;if (ctrl &NAND_CLE)
{/*发命令*/nand_regs->nfcmd =cmd;
}else{/*发地址*/nand_regs->nfaddr =cmd;
}
}static int s3c2440_dev_ready(struct mtd_info *mtd)
{/* */
return (nand_regs->nfstat & (1<<0));
}static int s3c_nand_init(void)
{/*分配一个nand_chip结构体*/s3c_nand= kzalloc(sizeof(structnand_chip), GFP_KERNEL);
nand_regs= ioremap(0x4e000000,sizeof(structs3c_nand_regs));
clk= clk_get(NULL,"nand");
clk_enable(clk);/*设置*/s3c_nand->select_chip =s3c2440_select_chip;
s3c_nand->cmd_ctrl =s3c2440_nand_cmd_ctrl;
s3c_nand->IO_ADDR_R = (void *)&nand_regs->nfdata;
s3c_nand->IO_ADDR_W = (void *)&nand_regs->nfdata;
s3c_nand->dev_ready =s3c2440_dev_ready;
s3c_nand->ecc.mode =NAND_ECC_SOFT;/*硬件相关的操作:根据nand Flash的手册设置时间参数*/
/*HCLK = 100MHz*/
/*TACLS: 发出cle/ale之后多长时间才发出nWE信号*/
/*TWRPHO: nWE的脉冲宽度*/nand_regs->nfconf = (1<<8);
nand_regs->nfcont = 0x03;/*使用:nand_scan*/s3c_mtd= kzalloc( sizeof(structmtd_info), GFP_KERNEL );
s3c_mtd->owner =THIS_MODULE;
s3c_mtd->priv =s3c_nand;
nand_scan(s3c_mtd,1); /*扫描识别*/
/*add_mtd_partitions*/add_mtd_partitions(s3c_mtd,s3c_nand_parts,4);//add_mtd_device(s3c_mtd);//整个flash只有一个分区的话可以用这个
return 0;
}static void s3c_nand_exit(void)
{
del_mtd_partitions(s3c_mtd);
kfree(s3c_mtd);
iounmap(nand_regs);
kfree(s3c_nand);
}
module_init(s3c_nand_init);
module_exit(s3c_nand_exit);
MODULE_LICENSE("GPL");
在添加这个内核模块的时候,首先卸载内核中的nand Flash驱动。
->Device Drivers
->Memory Technology Device (MTD) support
->NAND Device Support
sd