NAND Flash驱动
Posted lilto
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NAND Flash驱动相关的知识,希望对你有一定的参考价值。
硬件原理及分析
管脚说明
? ?
? ?
Pin Name | Pin Function |
R/B(RnB) | The R/B output indicates the status of the device operation. When low, it indicates that a program, erase or random read operation is in process and returns to high state upon completion. It is an open drain output and does not float to high-z condition when the chip is deselected or when outputs are disabled. |
CLE(CLE) | The CLE input controls the activating path for commands sent to the command register. When active high, commands are latched into the command register through the I/O ports on the rising edge of the WE signal. |
CE(nFCE) | The CE input is the device selection control. When the device is in the Busy state, CE high is ignored, and the device does not return to standby mode in program or erase operation. |
ALE(ALE) | The ALE input controls the activating path for address to the internal address registers. Addresses are latched on the rising edge of WE with ALE high. |
WE(nFWE) | The WE input controls writes to the I/O port. Commands, address and data are latched on the rising edge of the WE pulse. |
RE(nFRE) | The RE input is the serial data-out control, and when active drives the data onto the I/O bus. Data is valid tREA after the falling edge of RE which also increments the internal column address counter by one. |
I/O(LDATA0-LDATA7) | The I/O pins are used to input command, address and data, and to output data during read operations. The I/O pins float to high-z when the chip is deselected or when the outputs are disabled. |
? ?
在U-BOOT上操作Nand Flash
NAND FLASH S3C2440
发命令 选中芯片
CLE设为高电平 NFCMMD=命令值
在DATA0~DATA7上输出命令值
发出一个写脉冲
?
发地址 选中芯片 NFADDR=地址值
ALE设为高电平
在DATA0~DATA7上输出地址值
发出一个写脉冲
? ?
发数据 选中芯片 NFDATA=数据值
ALE,CLE设为低电平
在DATA0~DATA7上输出数据值
发出一个写脉冲
? ?
读数据 选中芯片 val=NFDATA
发出读脉冲
读DATA0~DATA7的数据
? ?
?
OpenJTAG> help md
md [.b, .w, .l] address [# of objects]
- memory display
? ?
OpenJTAG> help mw
mw [.b, .w, .l] address value [count]
- write memory
?b????????1字节
?W????????2字节
?l????????4字节
?
? ?
1. 读ID
S3C2440 | u-boot |
选中 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 |
?
2. 读内容: 读0地址的数据
使用UBOOT命令:
nand dump 0
Page 00000000 dump:
17 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5
? ?
S3C2440 | u-boot |
选中 NFCONT的bit1设为0 | md.l 0x4E000004 1; mw.l 0x4E000004 1 |
发出命令0x00 NFCMMD=0x00 | mw.b 0x4E000008 0x00 |
发出地址0x00 NFADDR=0x00 | mw.b 0x4E00000C 0x00 |
发出地址0x00 NFADDR=0x00 | mw.b 0x4E00000C 0x00 |
发出地址0x00 NFADDR=0x00 | mw.b 0x4E00000C 0x00 |
发出地址0x00 NFADDR=0x00 | mw.b 0x4E00000C 0x00 |
发出地址0x00 NFADDR=0x00 | mw.b 0x4E00000C 0x00 |
发出命令0x30 NFCMMD=0x30 | mw.b 0x4E000008 0x30 |
读数据得到0x17 val=NFDATA | md.b 0x4E000010 1 |
读数据得到0x00 val=NFDATA | md.b 0x4E000010 1 |
读数据得到0x00 val=NFDATA | md.b 0x4E000010 1 |
读数据得到0xea val=NFDATA | md.b 0x4E000010 1 |
退出读状态 NFCMMD=0xff | mw.b 0x4E000008 0xff |
? ?
ECC的作用
?
?
?
S3C2440-Nand Flash Controller Register
?
? ?
S3C2440-Nand Flash Memory Timing
? ?
K9F2G08U0C-Key Characteristic
? ?
K9F2G08U0C-Operation Timing
? ?
? ?
驱动程序
driver.c
1 /*
2 * SAMSUNG: K9F2G08U0C
3 * 参考:
4 * .linux-2.6.22.6driversmtd
ands3c2410.c
5 * .linux-2.6.22.6driversmtd
andat91_nand.c
6 */
7 #include <linux/module.h>
8 #include <linux/types.h>
9 #include <linux/init.h>
10 #include <linux/kernel.h>
11 #include <linux/string.h>
12 #include <linux/ioport.h>
13 #include <linux/platform_device.h>
14 #include <linux/delay.h>
15 #include <linux/err.h>
16 #include <linux/slab.h>
17 #include <linux/clk.h>
18 ????????
19 #include <linux/mtd/mtd.h>
20 #include <linux/mtd/nand.h>
21 #include <linux/mtd/nand_ecc.h>
22 #include <linux/mtd/partitions.h>
23 ????????
24 #include <asm/io.h>
25 ????????
26 #include <asm/arch/regs-nand.h>
27 #include <asm/arch/nand.h>
28
29 struct regs_nand {
30 ????????unsigned long ????????NFCONF;????????????????
31 ????????unsigned long????????NFCONT; ????????????????
32 ????????unsigned long????????NFCMMD; ????????????????
33 ????????unsigned long????????NFADDR; ????????????????
34 ????????unsigned long????????NFDATA;
35 ????????unsigned long????????NFMECCD0;
36 ????????unsigned long????????NFMECCD1;
37 ????????unsigned long????????NFSECCD;
38 ????????unsigned long????????NFSTAT;
39 ????????unsigned long????????NFESTAT0; ????????
40 ????????unsigned long????????NFESTAT1;
41 ????????unsigned long????????NFMECC0;????????????????
42 ????????unsigned long????????NFMECC1;????????????????????????
43 ????????unsigned long????????NFSECC; ????????????????
44 ????????unsigned long????????NFSBLK; ????????????????
45 ????????unsigned long????????NFEBLK;
46 };
47
48 static struct nand_chip *nand;
49 static struct mtd_info *mtd;
50 static struct regs_nand *regs_nand;
51
52 //分区信息
53 static struct mtd_partition nand_parts[] = {
54 ????????[0] = {
55 ????????????????.name ????????= "bootloader",????????????????????????
56 ????????????????.size ????????= 0x00040000,????????????????????????
57 ????????????????.offset = 0,????????????????????????????????????????/* offset within the master MTD space */
58 ????????},
59
60 ????????[1] = {
61 ????????????????.name ????????= "params",????????????????????????
62 ????????????????.offset = MTDPART_OFS_APPEND,????????//紧跟着上一个分区的大小
63 ????????????????.size ????????= 0x00020000,????????????????????????
64 ????????},
65
66 ????????[2] = {
67 ????????????????.name ????????= "kernel",????????????????????????????????
68 ????????????????.offset = MTDPART_OFS_APPEND,????????//紧跟着上一个分区的大小
69 ????????????????.size ????????= 0x00200000,????????????????????????
70 ????????},
71
72 ????????[3] = {
73 ????????????????.name ????????= "root",????????????????????????????????
74 ????????????????.offset = MTDPART_OFS_APPEND,????????//紧跟着上一个分区的大小
75 ????????????????.size ????????= MTDPART_SIZ_FULL,????????????????
76 ????????},
77 };
78
79 static void nand_select_chip(struct mtd_info *mtd, int chipnr)
80 {
81 ????????if (chipnr == -1)
82 ????????{
83 ????????????????//取消选中:NFCONT[1]:0
84 ????????????????regs_nand->NFCONT |= (1<<1);
85 ????????}
86 ????????else {
87 ????????????????//选中:NFCONT[1]:1
88 ????????????????regs_nand->NFCONT &= ~(1<<1);
89 ????????}
90 ????????return;
91 }
92
93 static void nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
94 {
95 ????????if (ctrl & NAND_CLE)
96 ????????{
97 ????????????????//发命令:NFCMMD=dat
98 ????????????????regs_nand->NFCMMD = dat;
99 ????????}
100 ????????else
101 ????????{
102 ????????????????//发地址:NFADDR=dat
103 ????????????????regs_nand->NFADDR = dat;
104 ????????}
105 ????????return;
106 }
107
108 static int nand_dev_ready(struct mtd_info *mtd)
109 {
110 ????????return (regs_nand->NFSTAT & (1<<0));
111 }
112
113
114 /* 1 出、入口函数 */
115 static int __init nand_init(void)
116 {
117 ????????struct clk *clk;
118
119 ????????/* 2 分配一个nand_chip结构体 */
120 ????????nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
121 ????????/******** 2 end ********/
122
123 ????????regs_nand = ioremap(0x4E000000, sizeof(struct regs_nand));
124
125 ????????/* 3 设置:nand_chip */
126 ????????//提供:选中、发命令、发地址、发数据、读数据、判断状态的功能
127 ????????nand->select_chip ????????= nand_select_chip;????????????????//片选
128 ????????nand->cmd_ctrl????????????????= nand_cmd_ctrl;????????????????//发命令
129 ????????nand->IO_ADDR_R????????????????= ®s_nand->NFDATA;????????//读
130 ????????nand->IO_ADDR_W????????????????= ®s_nand->NFDATA;????????//写
131 ????????nand->dev_ready????????????????= nand_dev_ready;????????????????//Flash 状态(忙/空闲)
132 ????????nand->ecc.mode????????????????= NAND_ECC_SOFT;????????????????//ecc软件校验
133 ????????/******** 3 end ********/
134
135 ????????/* 4 硬件相关的操作:时序 */
136 ????????//使能时钟
137 ????????clk = clk_get(NULL, "nand");
138 ????????clk_enable(clk);
139 ????????
140 #define TACLS????????0
141 #define TWRPH0????????1
142 #define TWRPH1????????0
143 ????????//时间参数设置
144 ????????regs_nand->NFCONF????????= (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
145
146 ????????//控制---使能nand flash控制器,取消片选
147 ????????regs_nand->NFCONT????????= (1<<0) | (1<<1);
148 ????????/******** 4 end ********/
149 ????????
150
151 ????????/* 5 使用:nand_scan */
152 ????????mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
153 ????????mtd->owner????????= THIS_MODULE;
154 ????????mtd->priv????????= nand;????????????????//私有数据
155 ????????
156 ????????nand_scan(mtd, 1);????????????????//识别nand_flash,构造mtd_info结构体
157 ????????/******** 5 end ********/
158
159
160 ????????/* 6 添加分区:add_mtd_partitions */
161 ????????add_mtd_partitions(mtd, nand_parts, 4);
162
163 ????????//不分区的情形
164 ????????//add_mtd_device(mtd);
165 ????????/******** 6 end ********/
166
167 ????????return 0;
168 }
169
170 static void __exit nand_exit(void)
171 {
172 ????????del_mtd_partitions(mtd);
173 ????????kfree(nand);
174 ????????kfree(mtd);
175 ????????iounmap(regs_nand);
176 ????????return;
177 }
178
179 module_init(nand_init);
180 module_exit(nand_exit);
181 MODULE_LICENSE("GPL");
182 /******** 1 end ********/
?
Makefile
1 KERN_DIR = /work/system/linux-2.6.22.6
2
3 all:
4 ????????make -C $(KERN_DIR) M=`pwd` modules
5
6 clean:
7 ????????make -C $(KERN_DIR) M=`pwd` modules clean
8 ????????rm -rf modules.order
9
10 obj-m????????+= nand_drv.o
? ?
? ?
? ?
调试
pc-linux:
//格式化工具
tar xjf mtd-utils-05.07.23.tar.bz2
cd mtd-utils-05.07.23/util
修改Makefile:
#CROSS=arm-linux-
改为
CROSS=arm-linux-
make
cp flash_erase flash_eraseall /work/nfs_root/fs_mini/bin/
//格式化工具-----end
? ?
board-uboot:
nfs 30000000 192.168.0.103:/work/nfs_root/uImage_f
//使用NFS作为根文件系统
set bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.103:/work/nfs_root/fs_mini ip=192.168.0.33:192.168.0.103:192.168.0.1:255.255.255.0::eth0:off
bootm 30000000
? ?
board-linux:
insmod nand_drv.ko
? ?
flash_eraseall /dev/mtd3 // yaffs //格式化
mount -t yaffs /dev/mtdblock3 /mnt //挂接
以上是关于NAND Flash驱动的主要内容,如果未能解决你的问题,请参考以下文章