uboot中nand flash代码分析(1)
来源:互联网 发布:mac系统截图 编辑:程序博客网 时间:2024/05/21 07:08
本文主要分析uboot中nand flash初始化部分的代码,主要是driver/mtd/nand/nand.c中的nand_init()函数。nand flash bbt建立部分的代码后面再分析。
(一)和nand flash 相关的参数
#define CONFIG_CMD_NAND 1#define CONFIG_SYS_MAX_NAND_DEVICE 1#define CONFIG_SYS_NAND_BASE 0xB0000000#define CONFIG_SYS_NAND_ALE_ADDR (1 << 10)#define CONFIG_SYS_NAND_CLE_ADDR (1 << 12)#define CONFIG_SYS_NO_FLASH 1#define CONFIG_ENV_IS_IN_NAND 1#define CONFIG_ENV_OFFSET 0x40000#define CONFIG_ENV_OFFSET_REDUND 0x60000#define CONFIG_ENV_OVERWRITE 1#define NAND_MAX_CHIPS 1#define CONFIG_SYS_NAND_RB_BIT 18#define CONFIG_SYS_NAND_RB_PORT 0xC2104200(二)初始化
初始化流程如下:
start_armboot
-->nand_init driver/mtd/nand/nand.c
-->nand_init_chip driver/mtd/nand/nand.c
-->board_nand_init (和具体开发板有关,board/xxx/yyy/nand.c)
-->nand_scan driver/mtd/nand/nand_base.c
一、start_armboot()和nand_init()
void start_armboot (void) { ... #if defined(CONFIG_CMD_NAND) puts ("NAND: ")//注释1 nand_init(); /* go init the NAND */ #endif ... } void nand_init(void) { int i; unsigned int size = 0; for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { //注释2 nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);//注释 3 4 5 size += nand_info[i].size / 1024; //注释6 if (nand_curr_device == -1) //注释7 nand_curr_device = i; } printf("%u MiB\n", size / 1024);//注释1}
1.上述两行打印语句,会在串口上打印”NAND: XXX MiB”字样,如”NAND: 128 MiB”
2. CONFIG_SYS_MAX_NAND_DEVICE表示系统有几块nand设备,一般只有1块。
该宏定义会影响下面数组的大小:
nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE];
3.有两个主要的数据结构struct mtd_info和 struct nand_chip。里面存放着nand flash
的size,erasesize,writesize,oobsize,ecc布局等属性,和操作nand flash所需
的read,write,erase等函数。nand_chip中变量的含义的详细注释在
Include/linux/mtd/nand.h中。初始化的目的就是初始化这两个数据结构。
4. Nand_info和mtd_info同义,typedef struct mtd_info nand_info_t;
5. base_address是nand flash的基地址,和硬件有关。可以通过定义
CONFIG_SYS_NAND_BASE_LIST或者 CONFIG_SYS_NAND_BASE
来设置 base_address的值。
6.nand_info.size是整个MTD的大小(Total size of the MTD),单位是Byte。
当系统只有一个nand flash作为静态存储器时,该变量等于nand flash的总大小。
7.nand_curr_device表示正在使用的nand flash在数组nand_info[]中的位置。
用户想要显示当前nand flash的信息时,可以在uboot命令行输入
#nand device
Uboot就会调用nand_print_info(nand_curr_device);函数来显示当前nand flash的信息。
二、nand_init_chip()
static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr){int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;int __attribute__((unused)) i = 0; if (maxchips < 1)maxchips = 1;//建立两个重要数据结构之间的关系。mtd_info的priv指针指向nand_chipmtd->priv = nand; nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;//设置读写地址//初始化与硬件相关的函数,如片选,cmd_ctrl等函数if (board_nand_init(nand) == 0) {//利用片选,cmd_ctrl等函数,读取nand flash的信息,并存放在mtd_info和nand_chip数据结构中。 if (nand_scan(mtd, maxchips) == 0) { if (!mtd->name) //nand_scan会设置该变量,若没设置,就用默认值 mtd->name = (char *)default_nand_name;#ifndef CONFIG_RELOC_FIXUP_WORKS else mtd->name += gd->reloc_off;#endif #ifdef CONFIG_MTD_DEVICE /* * Add MTD device so that we can reference it later * via the mtdcore infrastructure (e.g. ubi). */ //若定义 CONFIG_MTD_DEVICE,则强制修改mtd->name为”nandx” sprintf(dev_name[i], "nand%d", i); mtd->name = dev_name[i++]; add_mtd_device(mtd);//在数组mtd_table中查找一个空闲位置,并占用之。#endif } else mtd->name = NULL; } else { mtd->name = NULL; mtd->size = 0; }}三、board_nand_init()
board_nand_init()函数主要初始化与硬件相关的函数,如片选,cmd_ctrl等函数。
当我们移植uboot nand flash代码时,主要工作就是修改或者重写该函数。
下面代码中的”yyy”,一般是指板子型号或者具体nand flash的型号。
int board_nand_init(struct nand_chip *nand){ nand->cmd_ctrl = yyy_nand_hwcontrol;// 注释1 nand->dev_ready = yyy_nand_readybusy;// 注释2 nand->select_chip = yyy_nand_select_chip; nand->chip_delay = 100; // 注释3 nand->ecc.mode = NAND_ECC_SOFT; // 注释4 nand->options = NAND_USE_FLASH_BBT | NAND_NO_READRDY;// 注释5}
1.当向nand flash发送命令或数据时,需要拉高CLE或者ALE,该动作
就是由nand->cmd_ctrl函数来实现。
本例中,yyy_nand_hwcontrol()源码大致如下:
static void yyy_nand_hwcontrol(struct mtd_info *mtd, int dat,unsigned int ctrl){ struct nand_chip *chip = mtd->priv; void *IO_ADDR_W = chip->IO_ADDR_W; if (ctrl & NAND_CLE) // flash的CLE引脚接在CPU的ADDR21引脚 IO_ADDR_W += CONFIG_SYS_NAND_CLE_ADDR; if (ctrl & NAND_ALE) // flash的ALE引脚接在CPU的ADDR24引脚 IO_ADDR_W += CONFIG_SYS_NAND_ALE_ADDR; if (dat != NAND_CMD_NONE) { if (chip->options & NAND_BUSWIDTH_16)//flash数据线宽度是8 还是16 writew((unsigned short)dat, IO_ADDR_W); else writeb((unsigned char)dat, IO_ADDR_W); }}
如发送reset指令,需调用chip->cmd_ctrl(mtd,NAND_CMD_RESET, NAND_CLE);
因为ctrl 等于NAND_CLE,所以NAND_CMD_RESET会发到
(IO_ADDR_W + CONFIG_SYS_NAND_CLE_ADDR)地址上,即ADDR21会出现高电平,
刚好满足发送命令时,CLE引脚是高电平的条件。
2.该函数可以为空,即不检测nand flash的R/B引脚。而通过读取状态寄存器
来判断flash是否空闲,或者不检测flash是否空闲,而仅仅等待一段时间。
3.等待时间,需要参考flash的数据手册,不能太小,否则会出错。
有次设置太小,导致读取环境变量和内核时总是提示ecc错误。
4.计算ECC的方式,很重要
5.设置BBT存放方式,读操作时是否检测R/B状态等,很重要。
四、Nand_scan()
Nand_scan()函数分为两部分。
int nand_scan(struct mtd_info *mtd, int maxchips){ int ret; ret = nand_scan_ident(mtd, maxchips); if (!ret) ret = nand_scan_tail(mtd); return ret;}
首先将mtd_info和 nand_chip中还没初始化的函数,初始化为默认函数,
然后读取flash的ID,获取flash的信息,并计算出flash的总容量,块大小等信息,
并根据这些信息将mtd_info和 nand_chip设置为合适的值。
int nand_scan_ident(struct mtd_info *mtd, int maxchips){ int i, busw, nand_maf_id; struct nand_chip *chip = mtd->priv; struct nand_flash_dev *type; /* Get buswidth to select the correct functions */ busw = chip->options & NAND_BUSWIDTH_16;//判断flash数据总线的宽度 /* Set the default functions */ nand_set_defaults(chip, busw);见六 /* Read the flash type */ type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);见七 if (IS_ERR(type)) { chip->select_chip(mtd, -1); return PTR_ERR(type); } /* Check for a chip array */ for (i = 1; i < maxchips; i++) { chip->select_chip(mtd, i); /* See comment in nand_get_flash_type for reset */ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != chip->read_byte(mtd) || type->id != chip->read_byte(mtd)) break; } /* Store the number of chips and calc total size for mtd */ chip->numchips = i; mtd->size = i * chip->chipsize; //只有一块nand flash时,i等于1,mtd总大小就等于flash的总容量。 return 0;}
六、nand_set_defaults()
将nand_chip中还没初始化的函数初始化为默认值。
static void nand_set_defaults(struct nand_chip *chip, int busw){ /* check for proper chip_delay setup, set 20us if not */ if (!chip->chip_delay) chip->chip_delay = 20; /* check, if a user supplied command function given */ //仔细研究下nand_command,会有助于理解chip->chip_delay和chip->dev_ready函数的 //含义,如果是大页flash,nand_get_flash_type()会将chip->cmdfunc 修改为 //nand_command_lp() if (chip->cmdfunc == NULL) chip->cmdfunc = nand_command; /* check, if a user supplied wait function given */ if (chip->waitfunc == NULL) chip->waitfunc = nand_wait; if (!chip->select_chip) chip->select_chip = nand_select_chip; if (!chip->read_byte) chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; if (!chip->read_word) chip->read_word = nand_read_word; if (!chip->block_bad) chip->block_bad = nand_block_bad; if (!chip->block_markbad) chip->block_markbad = nand_default_block_markbad; if (!chip->write_buf) chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; if (!chip->read_buf) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; if (!chip->verify_buf) chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; if (!chip->scan_bbt) chip->scan_bbt = nand_default_bbt; if (!chip->controller) { chip->controller = &chip->hwcontrol; }}七、nand_get_flash_type()
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, int busw, int *maf_id){struct nand_flash_dev *type = NULL;int i, dev_id, maf_idx;int tmp_id, tmp_manf;/* Select the device */chip->select_chip(mtd, 0); /** Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)* after power-up*///调用nand_command(),reset flash。chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Send the command for reading device ID */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);//读取 flash ID/* Read manufacturer and device IDs */*maf_id = chip->read_byte(mtd);dev_id = chip->read_byte(mtd);/* Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a * possibly credible NAND flash to appear. If the two results do * not match, ignore the device completely. *///再次读取 flash IDchip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ tmp_manf = chip->read_byte(mtd);tmp_id = chip->read_byte(mtd); //比较两次所读的 flash ID是否一致if (tmp_manf != *maf_id || tmp_id != dev_id) {printk(KERN_INFO "%s: second ID read did not match " "%02x,%02x against %02x,%02x\n", __func__, *maf_id, dev_id, tmp_manf, tmp_id);return ERR_PTR(-ENODEV);} /*nand_flash_ids[]保存着uboot所支持的nand flash的*name,id,pagesize,chipsize,erasesize,options 等信息。*下面的for循环,从该数组中查找和自身ID相等的元素*//* Lookup the flash id */for (i = 0; nand_flash_ids[i].name != NULL; i++) {if (dev_id == nand_flash_ids[i].id) {type = &nand_flash_ids[i];break;}} if (!type) {/* supress warning if there is no nand */if (*maf_id != 0x00 && *maf_id != 0xff && dev_id != 0x00 && dev_id != 0xff)printk(KERN_INFO "%s: unknown NAND device: ""Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",__func__, *maf_id, dev_id);return ERR_PTR(-ENODEV);}//找到了,如“ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},”//设置mtd->name,该变量有可能被强制修改为nandx if (!mtd->name)mtd->name = type->name;//根据数组中的参数,设置flash的总容量,128Mchip->chipsize = (uint64_t)type->chipsize << 20;//若pagesize为0,表示需要继续读取ID,从ID中计算其他参数,而不是从 //nand_flash_ids[]中获取。/* Newer devices have all the information in additional id bytes */if (!type->pagesize) {int extid;/* The 3rd id byte holds MLC / multichip data */chip->cellinfo = chip->read_byte(mtd);/* The 4th id byte is the important one */// 4th id byte的含义见图一,本例用的nand flash是K9F1G08Q0A,读取到的是0x15,extid = chip->read_byte(mtd); /* Calc pagesize *///bit0,bit1为0,pagesize就是1024<<1=1024;为1,pagesize就是1024<<1=2048//writesize等于pagesize,因为每次写都是以页为单位。2048mtd->writesize = 1024 << (extid & 0x3);extid >>= 2;/* Calc oobsize *///writesize>>9算出几个512bytes,每512bytes对应8个还是16个oob区是由//(8 << (extid & 0x01))算得,两者相乘就得oob的总大小,16*4=64mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);extid >>= 2;/* Calc blocksize. Blocksize is multiples of 64KiB *///块大小或者擦除大小 64*1024*2=128KBmtd->erasesize = (64 * 1024) << (extid & 0x03);extid >>= 2;/* Get buswidth information *///总线宽度为8busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;} else {/* * Old devices have chip data hardcoded in the device id table */mtd->erasesize = type->erasesize;mtd->writesize = type->pagesize;mtd->oobsize = mtd->writesize / 32;busw = type->options & NAND_BUSWIDTH_16;} /* Try to identify manufacturer *///根据制造商ID,获取制造商名称,0xec对应Samsungfor (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {if (nand_manuf_ids[maf_idx].id == *maf_id)break;} /* * Check, if buswidth is correct. Hardware drivers should set * chip correct ! */if (busw != (chip->options & NAND_BUSWIDTH_16)) {printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, nand_manuf_ids[maf_idx].name, mtd->name);printk(KERN_WARNING "NAND bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8);return ERR_PTR(-EINVAL);} /* Calculate the address shift from the page size *///给出一个地址,利用该变量可以直接得出 该地址是第几页。//如 realpage = (int)(address>> chip->page_shift);chip->page_shift = ffs(mtd->writesize) - 1;/* Convert chipsize to number of pages per chip -1. *///chip->pagemask是总页数减1,用来防止要读写的页号不超过总页数// page = realpage & chip->pagemask;chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; //给出一个地址,利用该变量可以直接得出 该地址是第几块。chip->bbt_erase_shift = chip->phys_erase_shift =ffs(mtd->erasesize) - 1; //给出一个地址,利用该变量可以直接得出 该地址是第几个flash设备。if (chip->chipsize & 0xffffffff)chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;elsechip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31; /* Set the bad block position *///坏块位置,后面讲到ECC时会用到chip->badblockpos = mtd->writesize > 512 ?NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; //设置chip->options/* Get chip options, preserve non chip based options */chip->options &= ~NAND_CHIPOPTIONS_MSK;chip->options |= type->options & NAND_CHIPOPTIONS_MSK; /* * Set chip as a default. Board drivers can override it, if necessary */chip->options |= NAND_NO_AUTOINCR; /* Check if chip is a not a samsung device. Do not clear the * options for chips which are not having an extended id. */if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; //修改默认的函数为合适的函数/* Check for AND chips with 4 page planes */if (chip->options & NAND_4PAGE_ARRAY)chip->erase_cmd = multi_erase_cmd;elsechip->erase_cmd = single_erase_cmd;//如果是大页flash,则修改chip->cmdfunc 为 nand_command_lp()/* Do not replace user supplied command function ! */if (mtd->writesize > 512 && chip->cmdfunc == nand_command)chip->cmdfunc = nand_command_lp; MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, nand_manuf_ids[maf_idx].name, type->name); return type;}
图一
七、nand_scan_tail()
nand_scan_tail()继续初始化mtd_info和nand_info数据结构,主要初始化和ECC有关的变量和函数。
int nand_scan_tail(struct mtd_info *mtd){int i;struct nand_chip *chip = mtd->priv; //分配buffers,用于临时存放从flash读取的数据,见nand_do_read_ops()函数if (!(chip->options & NAND_OWN_BUFFERS))chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);if (!chip->buffers)return -ENOMEM; //oob紧跟着数据存放/* Set the internal oob buffer location, just after the page data */chip->oob_poi = chip->buffers->databuf + mtd->writesize; /* * If no default placement scheme is given, select an appropriate one */if (!chip->ecc.layout) {switch (mtd->oobsize) {case 8:chip->ecc.layout = &nand_oob_8;break;case 16:chip->ecc.layout = &nand_oob_16;break;case 64:chip->ecc.layout = &nand_oob_64;//注释1break;case 128:chip->ecc.layout = &nand_oob_128;break;default:printk(KERN_WARNING "No oob scheme defined for " "oobsize %d\n", mtd->oobsize);}}//初始化和ECC有关的函数if (!chip->write_page)chip->write_page = nand_write_page; /* * check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ switch (chip->ecc.mode) {case NAND_ECC_HW_OOB_FIRST:/* Similar to NAND_ECC_HW, but a separate read_page handle */if (!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) {printk(KERN_WARNING "No ECC functions supplied, " "Hardware ECC not possible\n");BUG();}if (!chip->ecc.read_page)chip->ecc.read_page = nand_read_page_hwecc_oob_first; case NAND_ECC_HW:/* Use standard hwecc read page function ? */if (!chip->ecc.read_page)chip->ecc.read_page = nand_read_page_hwecc;if (!chip->ecc.write_page)chip->ecc.write_page = nand_write_page_hwecc;if (!chip->ecc.read_page_raw)chip->ecc.read_page_raw = nand_read_page_raw;if (!chip->ecc.write_page_raw)chip->ecc.write_page_raw = nand_write_page_raw;if (!chip->ecc.read_oob)chip->ecc.read_oob = nand_read_oob_std;if (!chip->ecc.write_oob)chip->ecc.write_oob = nand_write_oob_std; case NAND_ECC_HW_SYNDROME:if ((!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) && (!chip->ecc.read_page || chip->ecc.read_page == nand_read_page_hwecc || !chip->ecc.write_page || chip->ecc.write_page == nand_write_page_hwecc)) {printk(KERN_WARNING "No ECC functions supplied, " "Hardware ECC not possible\n");BUG();}/* Use standard syndrome read/write page function ? */if (!chip->ecc.read_page)chip->ecc.read_page = nand_read_page_syndrome;if (!chip->ecc.write_page)chip->ecc.write_page = nand_write_page_syndrome;if (!chip->ecc.read_page_raw)chip->ecc.read_page_raw = nand_read_page_raw_syndrome;if (!chip->ecc.write_page_raw)chip->ecc.write_page_raw = nand_write_page_raw_syndrome;if (!chip->ecc.read_oob)chip->ecc.read_oob = nand_read_oob_syndrome;if (!chip->ecc.write_oob)chip->ecc.write_oob = nand_write_oob_syndrome; if (mtd->writesize >= chip->ecc.size)break;printk(KERN_WARNING "%d byte HW ECC not possible on " "%d byte page size, fallback to SW ECC\n", chip->ecc.size, mtd->writesize);chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT:chip->ecc.calculate = nand_calculate_ecc;chip->ecc.correct = nand_correct_data;chip->ecc.read_page = nand_read_page_swecc;chip->ecc.read_subpage = nand_read_subpage;chip->ecc.write_page = nand_write_page_swecc;chip->ecc.read_page_raw = nand_read_page_raw;chip->ecc.write_page_raw = nand_write_page_raw;chip->ecc.read_oob = nand_read_oob_std;chip->ecc.write_oob = nand_write_oob_std;chip->ecc.size = 256;//每256bit 产生3bit的ECCchip->ecc.bytes = 3;break; case NAND_ECC_NONE:printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " "This is not recommended !!\n");chip->ecc.read_page = nand_read_page_raw;chip->ecc.write_page = nand_write_page_raw;chip->ecc.read_oob = nand_read_oob_std;chip->ecc.read_page_raw = nand_read_page_raw;chip->ecc.write_page_raw = nand_write_page_raw;chip->ecc.write_oob = nand_write_oob_std;chip->ecc.size = mtd->writesize;chip->ecc.bytes = 0;break; default:printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", chip->ecc.mode);BUG();} /* * The number of bytes available for a client to place data into * the out of band area *///可用的oob大小,即nand_oob_64中所设置的>oobfree的总和,本例是38bitchip->ecc.layout->oobavail = 0;for (i = 0; chip->ecc.layout->oobfree[i].length&& i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)chip->ecc.layout->oobavail +=chip->ecc.layout->oobfree[i].length;mtd->oobavail = chip->ecc.layout->oobavail; /* * Set the number of read / write steps for one page depending on ECC * mode */chip->ecc.steps = mtd->writesize / chip->ecc.size;if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {printk(KERN_WARNING "Invalid ecc parameters\n");BUG();}chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; /* * Allow subpage writes up to ecc.steps. Not possible for MLC * FLASH. */if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {switch(chip->ecc.steps) {case 2:mtd->subpage_sft = 1;break;case 4:case 8:case 16:mtd->subpage_sft = 2;break;}}//计算子页大小,即每次读flash时,最小需要读取的数据。为了检测数据是否有误,需//要至少读取一个单位的ECC对应的数据大小。chip->subpagesize = mtd->writesize >> mtd->subpage_sft; /* Initialize state */chip->state = FL_READY; /* De-select the device */chip->select_chip(mtd, -1); //该变量应该是表示chip->buffers中的数据是第几页的数据。//读flash之前,需要先判断所读的页的数据是否已在chip->buffers中,是则,直接从 //buffers中读取/* Invalidate the pagebuffer reference */chip->pagebuf = -1; //设置默认函数和变量/* Fill in remaining MTD driver data */mtd->type = MTD_NANDFLASH;mtd->flags = MTD_CAP_NANDFLASH;mtd->erase = nand_erase;mtd->point = NULL;mtd->unpoint = NULL;mtd->read = nand_read;mtd->write = nand_write;mtd->read_oob = nand_read_oob;mtd->write_oob = nand_write_oob;mtd->sync = nand_sync;mtd->lock = NULL;mtd->unlock = NULL;mtd->suspend = nand_suspend;mtd->resume = nand_resume;mtd->block_isbad = nand_block_isbad;mtd->block_markbad = nand_block_markbad; /* propagate ecc.layout to mtd_info */mtd->ecclayout = chip->ecc.layout; //如果定义NAND_SKIP_BBTSCAN,则设置BBT“已扫描过”。以后会跳过BBT扫描,/* Check, if we should skip the bad block table scan */if (chip->options & NAND_SKIP_BBTSCAN)chip->options |= NAND_BBT_SCANNED; return 0;}
1.本例oobsize等于64,从下面结构可以看出oob区的结构
static struct nand_ecclayout nand_oob_64 = { .eccbytes = 24, .eccpos = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {.offset = 2, .length = 38}} };
前两位有其他作用,从第2位开始,到第39位,一共38位是空闲的。从40位到63位共24位存放ECC数据,每256bytes对应3bytesECC,一页2048bytes,共24bytesECC。
- uboot中nand flash代码分析(1)
- uboot中nand flash代码分析(2)
- uboot中nand flash代码分析(3)
- [NAND]UBOOT从NAND FLASH启动分析
- [NAND]UBOOT从NAND FLASH启动分析
- uboot下的nand flash驱动分析
- MPC8313ERDB在Linux从NAND FLASH读取UBoot环境变量的代码分析
- uboot之nand flash相关(1)
- uboot之nand flash相关(1)
- nand flash uboot 启动
- uboot中nand详细分析(一)
- Uboot启动分析之stage1-Nand-Flash启动部分详解
- NAND FLASH (1 .结构分析)
- Linux NAND FLASH驱动代码分析
- Linux NAND FLASH驱动代码分析
- Linux NAND FLASH驱动代码分析
- Linux NAND FLASH驱动代码分析
- Linux NAND FLASH驱动代码分析
- 为什么要定义interface
- 操作系统——动态分区存储管理(首次适应算法)
- XML(Extenxible Markup Language)可扩展标记语言,DTD(Document Type Definition)文档类型定义
- Linux下Socket编程
- 转自matrix67 十个利用矩阵乘法解决的经典问题
- uboot中nand flash代码分析(1)
- 二级指针
- sleep_on_timeout() -- 内核模块睡眠
- proguard.cfg和proguard-project.txt 混淆文件的用法与配置
- KMP字符串模式匹配详解
- 关于IT项目灾备思考
- UVALive 6525 Attacking rooks
- Java 文件格式
- C中堆管理——浅谈malloc,calloc,realloc函数之间的区别