1. nand_init(); drivers/mtd/nand/nand.c
先来看个nand_init的简要过程图
nand初始化关键的两个函数 board_nand_init 和 nand_scan
board_nand_init 是与板级相关的,uboot中cpu/arm920t/s3c24x0/nand.c中,移植的时候要重点
查看
7 clk_power->CLKCON |= (1 << 4);
8 /* initialize hardware */
9 twrph0 = 3; twrph1 = 0; tacls = 0;
10 cfg = S3C2410_NFCONF_EN;
11 cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
12 cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
13 cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
14 NFCONF = cfg;
15 /* initialize nand_chip data structure */
16 nand->IO_ADDR_R = nand->IO_ADDR_W = 0x4e00000c;
17 /* read_buf and write_buf are default */
18 /* read_byte and write_byte are default */
19 /* hwcontrol always must be implemented */
20 nand->hwcontrol = s3c2410_hwcontrol;
21 nand->dev_ready = s3c2410_dev_ready;
9 twrph0 = 3; twrph1 = 0; tacls = 0;
10 cfg = S3C2410_NFCONF_EN;
11 cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
12 cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
13 cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
14 NFCONF = cfg;
28 nand->eccmode = NAND_ECC_SOFT;
33 nand->options = 0;
|
第7行 置CLKCON第5位,给nand控制器供电,上电默认是供电的
9~14 行,配置NFCONF ,移植时,这几个值要仔细对照数据手册算一下
16行 nand的读写I/O都设为NFDATA
NAND读时,用的肯定是NFDATA
写nand时,可能写数据、命令或地址,所以写I/O可能会为 NFDATA NFCMD NFADDR
这个在相应的操作中会被s3c2410_hwcontrol修改
19~23 填充nand_chip结构
nand_scan drivers/mtd/nand/nand_base.c 6 busw = this->options & NAND_BUSWIDTH_16;
|
上面的结果为0,这里nand为k9f1208,bus_width为8
7 /* check for proper chip_delay setup, set 20us if not */
8 if (!this->chip_delay)
9 this->chip_delay = 20;
10 /* check, if a user supplied command function given */
11 if (this->cmdfunc == NULL)
12 this->cmdfunc = nand_command;
13 /* check, if a user supplied wait function given */
14 if (this->waitfunc == NULL)
15 this->waitfunc = nand_wait;
16 if (!this->select_chip)
17 this->select_chip = nand_select_chip;
18 if (!this->write_byte)
19 this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
20 if (!this->read_byte)
21 this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
22 if (!this->write_word)
23 this->write_word = nand_write_word;
24 if (!this->read_word)
25 this->read_word = nand_read_word;
26 if (!this->block_bad)
27 this->block_bad = nand_block_bad;
28 if (!this->block_markbad)
29 this->block_markbad = nand_default_block_markbad;
30 if (!this->write_buf)
31 this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
32 if (!this->read_buf)
33 this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
34 if (!this->verify_buf)
35 this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
36 if (!this->scan_bbt)
37 this->scan_bbt = nand_default_bbt;
|
7~ 37行 判断nand_chip的成员函数是否已经初始化过,若未初始化,则给其赋相应值
38 /* Select the device */
39 this->select_chip(mtd, 0);
40 /* Send the command for reading device ID */
41 this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
42 /* Read manufacturer and device IDs */
43 nand_maf_id = this->read_byte(mtd);
44 nand_dev_id = this->read_byte(mtd);
|
38~44 使能nand => 发送读id命令和地址0x00 => 读nand芯片的id
nand_maf_id => 厂商代码 samsung为 0xec
nand_dev_id => 设备代码 k9f1208为 0x76
/* Print and store flash device information */
46 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
47 if (nand_dev_id != nand_flash_ids[i].id)
48 continue;
|
通过nand)dev_id在nand_flash_ids[]数组中找到芯片对应项,该项上含有芯片的一些信息,如对于此块
nand,读出nand_dev_id为0x76后,则在nand_flash_ids[]中匹配到下面这一项
{"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
由此可知,页面大小为512bytes, 芯片容量为64M, 擦写页面大小为16k 等
49 if (!mtd->name) mtd->name = nand_flash_ids[i].name;
50 this->chipsize = nand_flash_ids[i].chipsize << 20;
|
49 行 mtd_name就指向字符串
"NAND 64MiB 3,3V 8-bit"
50 行 芯片大小为 64M 即 0x4000000
70 /* Old devices have this data hardcoded in the
71 * device id table */
72 mtd->erasesize = nand_flash_ids[i].erasesize;
73 mtd->oobblock = nand_flash_ids[i].pagesize;
74 mtd->oobsize = mtd->oobblock / 32;
75 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
|
72 => 擦除页面16k
73 => 页大小512 bytes
74 => out of blank 大小 16 bytes
75 => busw = 0
90 /* Calculate the address shift from the page size */
91 this->page_shift = ffs(mtd->oobblock) - 1;
92 this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
93 this->chip_shift = ffs(this->chipsize) - 1;
|
#define ffs(x) generic_ffs(x)
/* Return the position of the first bit set in I, or 0 if none are set.
The least-significant bit is position 1, the most-significant 32. */
找出第一个为1的位,最低位为1
即 0x1000 0000 0000 0000 0000 0000 0000 0000 返回32
0x0001 返回1
所以这里
ffs(mtd->oobblock) = 10 , this->page_shift = 9
this->bbt_erase_shift = this->phys_erase_shift = 13
this->chip_shift = 26
94 /* Set the bad block position */
95 this->badblockpos = mtd->oobblock > 512 ?
96 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
|
判断是大页还是小页,来确定坏块标记位置 this->badblockpos大页为0, 小页为5
97 /* Get chip options, preserve non chip based options */
98 this->options &= ~NAND_CHIPOPTIONS_MSK;
99 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
100 /* Set this as a default. Board drivers can override it, if neccecary */
101 this->options |= NAND_NO_AUTOINCR;
|
暂时还看不懂上面几句 105 if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
106 this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
107 /* Check for AND chips with 4 page planes */
108 if (this->options & NAND_4PAGE_ARRAY)
109 this->erase_cmd = multi_erase_cmd;
110 else
111 this->erase_cmd = single_erase_cmd;
112 /* Do not replace user supplied command function ! */
113 if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
114 this->cmdfunc = nand_command_lp;
|
115 /* Try to identify manufacturer */
116 for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
117 if (nand_manuf_ids[j].id == nand_maf_id)
118 break;
119 }
|
122 if (!nand_flash_ids[i].name) { 123 #ifndef CFG_NAND_QUIET_TEST 124 printk (KERN_WARNING "No NAND device found!!!\n"); 125 #endif 126 this->select_chip(mtd, -1); 127 return 1; 128 }
|
上面的i到这里一直没变,仍然停在id相等的那一项上,判断那一项是否为空?因为id不匹配的话,
nand_flash_ids最后一项即为NULL
129 for (i=1; i < maxchips; i++) {
130 this->select_chip(mtd, i);
131 /* Send the command for reading device ID */
132 this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
133 /* Read manufacturer and device IDs */
134 if (nand_maf_id != this->read_byte(mtd) ||
135 nand_dev_id != this->read_byte(mtd))
136 break;
137 }
|
这里,如果有多块nand芯片,则去读它们的ID
nand_scan的调用为 nand_scan(mtd, 1) , 即maxchips == 1
所以130 ~ 136 会跳过去
140 /* Allocate buffers, if neccecary */
141 if (!this->oob_buf) {
142 size_t len;
143 len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
144 this->oob_buf = kmalloc (len, GFP_KERNEL);
145 if (!this->oob_buf) {
146 printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
147 return -ENOMEM;
148 }
149 this->options |= NAND_OOBBUF_ALLOC;
150 }
151 if (!this->data_buf) {
152 size_t len;
153 len = mtd->oobblock + mtd->oobsize;
154 this->data_buf = kmalloc (len, GFP_KERNEL);
155 if (!this->data_buf) {
156 if (this->options & NAND_OOBBUF_ALLOC)
157 kfree (this->oob_buf);
158 printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
159 return -ENOMEM;
160 }
161 this->options |= NAND_DATABUF_ALLOC;
162 }
|
141 this->oobbuf还未初始化,进入
143 len = 16 << (13 - 9) = 256 为this->oobbuf分配256bytes的空间
153 len = 512 + 16 = 528
164 this->numchips = i; //芯片数
165 mtd->size = i * this->chipsize; //总大小
167 this->pagemask = (this->chipsize >> this->page_shift) - 1; // 页数 - 1
168 /* Preset the internal oob buffer */
169 memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); // 清this->oob_buf
172 if (!this->autooob) {
175 switch (mtd->oobsize) {
176 case 8:
177 this->autooob = &nand_oob_8;
178 break;
179 case 16:
180 this->autooob = &nand_oob_16;
181 break;
182 case 64:
183 this->autooob = &nand_oob_64;
184 break;
185 case 128:
186 this->autooob = &nand_oob_128;
187 break;
188 default:
189 printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
190 mtd->oobsize);
191 }
192 }
|
195 mtd->oobavail = 0;
196 for (i=0; this->autooob->oobfree[i][1]; i++)
197 mtd->oobavail += this->autooob->oobfree[i][1];
|
203 this->eccsize = 256; /* set default eccsize */
204 this->eccbytes = 3;
|
233 case NAND_ECC_SOFT:
234 this->calculate_ecc = nand_calculate_ecc;
235 this->correct_data = nand_correct_data;
236 break
|
268 case NAND_ECC_SOFT:
269 this->eccsteps = mtd->oobblock / 256;
270 break;
|
上面填充ECC相关成员
275 /* De-select the device */
276 this->select_chip(mtd, -1);
277 /* Invalidate the pagebuffer reference */
278 this->pagebuf = -1;
279 /* Fill in remaining MTD driver data */
280 mtd->type = MTD_NANDFLASH;
281 mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
282 mtd->ecctype = MTD_ECC_SW;
283 mtd->erase = nand_erase;
284 mtd->point = NULL;
285 mtd->unpoint = NULL;
286 mtd->read = nand_read;
287 mtd->write = nand_write;
288 mtd->read_ecc = nand_read_ecc;
289 mtd->write_ecc = nand_write_ecc;
290 mtd->read_oob = nand_read_oob;
291 mtd->write_oob = nand_write_oob;
292 mtd->sync = nand_sync;
293 mtd->block_isbad = nand_block_isbad;
294 mtd->block_markbad = nand_block_markbad;
295 /* and make the autooob the default one */
296 memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
297 /* Build bad block table */
298 return this->scan_bbt (mtd);
|
276 行 禁止nand芯片
280 ~ 294 填充mtd结构
298 建立坏块列表, 返回
mtd结构和nand_chip结构是整个nand操作的关键,这两个结构体都非常复杂,重要的是不知道其中的成员(函数)
是用来干什么的,都有什么作用,在什么地方用到。
总之,从nand_scan退出之后,nand_chip和mtd结构里就记录了该块nand芯片的所有信息及对其作各种操作的函数。
最后来看一下这块k9f1208经过board_nand_init()和nand_scan()之后的情况,
下面 蓝色粗体 表示从board_nand_init中初始化
红色粗体表示从 nand_scan 中初始化
黑色粗体表示初始化之后仍会改变的值
普通字体表示暂未使用的成员
1 struct nand_chip {
2 void __iomem *IO_ADDR_R; => 0x4e00000c 即NFDATA 在board_nand_init()中初始化
3 void __iomem *IO_ADDR_W; => 会在hwcontrol函数中变化,为NFDATA、NFCMD、NFADDR之一
4 u_char (*read_byte)(struct mtd_info *mtd); => 读一个字节,在nand_scan()中初始化
5 void (*write_byte)(struct mtd_info *mtd, u_char byte); => 写一个字节,在nand_scan()中初始化
6 u16 (*read_word)(struct mtd_info *mtd); => 读一个字,在nand_scan()中初始化
7 void (*write_word)(struct mtd_info *mtd, u16 word);=> 写一个字,在nand_scan()中初始化
8 void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); => 写长度为len的buf 在nand_scan()中初始化
9 void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); => 读长度为len的buf 在nand_scan()中初始化
10 int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); => 在nand_scan()中初始化
11 void (*select_chip)(struct mtd_info *mtd, int chip); =>使能/禁止nand芯片,chip=-1 禁止, chip=0 使能 在nand_scan()中初始化
12 int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); => 在nand_scan()中初始化
13 int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); => 在nand_scan()中初始化
14 void (*hwcontrol)(struct mtd_info *mtd, int cmd); => s3c2410_hwcontrol 在board_nand_init()中初始化
15 int (*dev_ready)(struct mtd_info *mtd); => s3c2410_dev_ready 等待nand状态变为空闲,在board_nand_init()中初始化
16 void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); => 写命令及地址 在nand_scan()中初始化
17 int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); => nand_wait 在nand_scan()中初始化
18 int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); => nand_calculate_ecc 在nand_scan()中初始化
19 int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); => nand_ccorrect_data 在nand_scan()中初始化
20 void (*enable_hwecc)(struct mtd_info *mtd, int mode);
21 void (*erase_cmd)(struct mtd_info *mtd, int page); => single_erase_cmd 在nand_scan()中初始化
22 int (*scan_bbt)(struct mtd_info *mtd); => 在nand_scan()中初始化
23 int eccmode; => NAND_ECC_SOFT 在board_nand_init()中初始化
24 int eccsize; => 256 在nand_scan()中初始化
25 int eccbytes;=> 3 在nand_scan()中初始化
26 int eccsteps; => mtd->oobblock / 256 = 2
27 int chip_delay; => 20 在nand_scan()中初始化
28 int page_shift; => 页面偏移 9, 2^9 = 512 在nand_scan()中初始化
29 int phys_erase_shift; => 14 , 2^14 = 16k 一个block的大小 在nand_scan()中初始化
30 int bbt_erase_shift; => 14 , 2^14 = 16k 一个block的大小 在nand_scan()中初始化
31 int chip_shift; => 26, 2^26 = 64M 芯片大小 在nand_scan()中初始化
32 u_char *data_buf; => 分配528bytes空间 在nand_scan()中初始化
33 u_char *oob_buf; => 分配512bytes空间 在nand_scan()中初始化
34 int oobdirty;
35 u_char *data_poi;
36 unsigned int options; => 在board_nand_init()中初始为0, 在nand_scan()中被改写
37 int badblockpos; =>坏块标记的位置 在nand_scan()中初始化
38 int numchips; => 芯片数 1 在nand_scan()中初始化
39 unsigned long chipsize; => 芯片大小64M 在nand_scan()中初始化
40 int pagemask; => 页数-1 在nand_scan()中初始化
41 int pagebuf; => -1 在nand_scan()中初始化
42 struct nand_oobinfo *autooob; => &nand_oob_16 , nand_oob_16是个结构体,记录芯片oob区的相关信息
43 uint8_t *bbt;
44 struct nand_bbt_descr *bbt_td;
45 struct nand_bbt_descr *bbt_md;
46 struct nand_bbt_descr *badblock_pattern;
47 struct nand_hw_control *controller;
48 void *priv;
49 };
阅读(1276) | 评论(0) | 转发(0) |