驱动09.nand flash
1 nand flash的操作
目的:读地址A的数据,把数据B写到地址A。
问1. 原理图上NAND FLASH和S3C2440之间只有数据线,怎么传输地址?答1.在DATA0~DATA7上既传输数据,又传输地址,当ALE为高电平时传输的是地址。
问2. 从NAND FLASH芯片手册可知,要操作NAND FLASH需要先发出命令 怎么传入命令?答2.在DATA0~DATA7上既传输数据,又传输地址,也传输命令 当ALE为高电平时传输的是地址, 当CLE为高电平时传输的是命令 当ALE和CLE都为低电平时传输的是数据问3. 数据线既接到NAND FLASH,也接到NOR FLASH,还接到SDRAM、DM9000等等,那么怎么避免干扰?答3. 这些设备,要访问之必须"选中",没有选中的芯片不会工作,相当于没接一样。(内存控制器)问4. 假设烧写NAND FLASH,把命令、地址、数据发给它之后, NAND FLASH肯定不可能瞬间完成烧写的,怎么判断烧写完成?答4. 通过状态引脚RnB来判断:它为高电平表示就绪,它为低电平表示正忙
问5. 怎么操作NAND FLASH呢?答5. 根据NAND FLASH的芯片手册,一般的过程是: 发出命令 发出地址 发出数据/读数据



2 分析nand flash的启动过程
搜"S3C24XX NAND Driver"S3c2410.c (drivers\mtd\nand)
s3c2410_nand_inithws3c2410_nand_init_chipnand_scan // 根据nand_chip的底层操作函数识别NAND FLASH,构造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; 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, 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在哪设置 // 答. drivers\mtd\mdblock.c或mtdblock_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 (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 3 nand flash驱动程序框架
(1)分配一个nand_chip/mtd_info结构体
(2)设置
(3)硬件相关的操作
(4)使用nand_scan/add_mtd_partitions
4 写代码
参考drivers\mtd\nand\s3c2410.c


1 /*参考drivers\mtd\nand\at91_nand.c*/
2
3
4 #include <linux/module.h>
5 #include <linux/types.h>
6 #include <linux/init.h>
7 #include <linux/kernel.h>
8 #include <linux/string.h>
9 #include <linux/ioport.h>
10 #include <linux/platform_device.h>
11 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/slab.h>
14 #include <linux/clk.h>
15
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/nand.h>
18 #include <linux/mtd/nand_ecc.h>
19 #include <linux/mtd/partitions.h>
20
21 #include <asm/io.h>
22
23 #include <asm/arch/regs-nand.h>
24 #include <asm/arch/nand.h>
25
26
27 struct s3c_nand_regs {
28 unsigned long nfconf ;
29 unsigned long nfcont ;
30 unsigned long nfcmd ;
31 unsigned long nfaddr ;
32 unsigned long nfdata ;
33 unsigned long nfeccd0 ;
34 unsigned long nfeccd1 ;
35 unsigned long nfeccd ;
36 unsigned long nfstat ;
37 unsigned long nfestat0;
38 unsigned long nfestat1;
39 unsigned long nfmecc0 ;
40 unsigned long nfmecc1 ;
41 unsigned long nfsecc ;
42 unsigned long nfsblk ;
43 unsigned long nfeblk ;
44 };
45
46 static struct mtd_info *s3c_mtd;
47 static struct nand_chip *s3c_nand;
48
49
50 static struct mtd_partition s3c_nand_parts[] = {
51 [0] = {
52 .name = "bootloader",
53 .size = 0x00040000,
54 .offset = 0,
55 },
56 [1] = {
57 .name = "params",
58 .offset = MTDPART_OFS_APPEND,
59 .size = 0x00020000,
60 },
61 [2] = {
62 .name = "kernel",
63 .offset = MTDPART_OFS_APPEND,
64 .size = 0x00200000,
65 },
66 [3] = {
67 .name = "root",
68 .offset = MTDPART_OFS_APPEND,
69 .size = MTDPART_SIZ_FULL,
70 }
71 };
72
73 static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
74 {
75 if (chipnr == -1)
76 {
77 /* 取消选中: NFCONT[1]设为1 */
78 s3c_nand_regs->nfcont |= (1<<1);
79 }
80 else
81 {
82 /* 选中: NFCONT[1]设为0 */
83 s3c_nand_regs->nfcont &= ~(1<<1);
84 }
85 }
86
87 static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
88 {
89 if (ctrl & NAND_CLE)
90 {
91 /* 发命令: NFCMMD=dat */
92 s3c_nand_regs->nfcmd = dat;
93 }
94 else
95 {
96 /* 发地址: NFADDR=dat */
97 s3c_nand_regs->nfaddr = dat;
98 }
99 }
100
101 static int s3c2440_dev_ready(struct mtd_info *mtd)
102 {
103 return (s3c_nand_regs->nfstat & (1<<0));
104 }
105
106
107 static int s3c_nand_init(void)
108 {
109 struct clk *clk;
110 s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
111
112 s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));
113
114 s3c_nand->select_chip = s3c2440_select_chip;
115 s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl;
116 s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata;
117 s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata;
118 s3c_nand->dev_ready = s3c2440_dev_ready;
119 s3c_nand->ecc.mode = NAND_ECC_SOFT;//enable ECC
120
121 clk = clk_get(NULL, "nand");
122 clk_enable(clk);
123
124 #define TACLS 0
125 #define TWRPH0 1
126 #define TWRPH1 0
127 s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
128 s3c_nand_regs->nfcont = (1<<1) | (1<<0);
129
130 s3c_mtd = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
131 s3c_mtd->owner = THIS_MODULE;
132 s3c_mtd->priv = s3c_nand;
133 nand_scan(s3c_mtd, 1);//识别nand falsh,构造mtd_info
134
135 add_mtd_partitions(s3c_mtd, s3c_nand_parts,4);
136
137 return 0;
138 }
139
140
141 static void s3c_nand_exit(void)
142 {
143 del_mtd_partitions(s3c_mtd);
144 kfree(s3c_mtd);
145 iounmap(s3c_nand_regs);
146 kfree(s3c_nand);
147 }
148
149 module_init(s3c_nand_init);
150 module_exit(s3c_nand_exit);
151
152 MODULE_LICENSE("GPL"); s3c_nand.c