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                = &regs_nand->NFDATA;        //读
130         nand->IO_ADDR_W                = &regs_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 //挂接

原文地址:https://www.cnblogs.com/lilto/p/11877991.html