📄 nand.c
字号:
if (this->chipsize > (128 << 20)) this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff)); } /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } /* * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: return; case NAND_CMD_RESET: if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); while ( !(this->read_byte(mtd) & 0x40)); return; case NAND_CMD_READ0: /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the start read command */ this->write_byte(mtd, NAND_CMD_READSTART); /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); /* Fall through into ready check */ /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; } } /* wait until command is processed */ while (!this->dev_ready(mtd));}/* * Get chip for selected access */static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state){ /* * Grab the lock and see if the device is available */}/* * Wait for command done. This applies to erase and program only * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs **/static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state){ int status; this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); while (1) { if (this->dev_ready) { if (this->dev_ready(mtd)) break; } if (this->read_byte(mtd) & 0x40) break; } status = (int) this->read_byte(mtd); return status;}/* * Nand_page_program function is used for write and writev ! * This function will always program a full page of data * If you call it with a non page aligned buffer, you're lost :) * * @mtd: MTD device structure * @this: NAND chip structure * @page: startpage inside the chip, must be called with (page & this->pagemask) * @oob_buf: out of band data buffer * @oobsel: out of band selecttion structre * @cached: 1 = enable cached programming if supported by chip */static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int cached){ int i, status; u_char ecc_code[6]; int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; int *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; /* FIXME: Enable cached programming */ cached = 0; /* Send command to begin auto page programming */ this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); /* Write out complete page of data, take care of eccmode */ switch (eccmode) { /* No ecc, write all */ case NAND_ECC_NONE: printk ("Writing data without ECC to NAND-FLASH is not recommended\n"); this->write_buf(mtd, this->data_poi, mtd->oobblock); break; /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); for (i = 0; i < 3; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; datidx += mtd->eccsize; } this->write_buf(mtd, this->data_poi, mtd->oobblock); break; /* Hardware ecc 3 byte / 256 data, write 256 byte */ /* Hardware ecc 3 byte / 512 byte data, write 512 bytee */ case NAND_ECC_HW3_256: case NAND_ECC_HW3_512: for (; eccsteps; eccsteps--) { this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write */ this->write_buf(mtd, &this->data_poi[datidx], mtd->eccsize); this->calculate_ecc(mtd, NULL, ecc_code); for (i = 0; i < 3; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; datidx += mtd->eccsize; } break; /* Hardware ecc 6 byte / 512 byte data, write 512 byte */ case NAND_ECC_HW6_512: for (; eccsteps; eccsteps--) { this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write */ this->write_buf(mtd, &this->data_poi[datidx], mtd->eccsize); this->calculate_ecc(mtd, NULL, ecc_code); for (i = 0; i < 6; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; datidx += mtd->eccsize; } break; default: printk ("Invalid NAND_ECC_MODE %d\n", this->eccmode); //BUG(); } /* Write out OOB data */ this->write_buf(mtd, oob_buf, mtd->oobsize); /* Send command to actually program the data */ this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1); if (!cached) { /* call wait ready function */ status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ if (status & 0x01) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); return -EIO; } } else { /* FIXME: Implement cached programming ! */ /* wait until cache is ready*/ // status = this->waitfunc (mtd, this, FL_CACHEDRPG); } return 0; }#ifdef CONFIG_MTD_NAND_VERIFY_WRITE/* * The NAND device assumes that it is always writing to a cleanly erased page. * Hence, it performs its internal write verification only on bits that * transitioned from 1 to 0. The device does NOT verify the whole page on a * byte by byte basis. It is possible that the page was not completely erased * or the page is becoming unusable due to wear. The read with ECC would catch * the error later when the ECC page check fails, but we would rather catch * it early in the page write stage. Better to write no data than invalid data. * * @mtd: MTD device structure * @this: NAND chip structure * @page: startpage inside the chip, must be called with (page & this->pagemask) * @numpages: number of pages to verify * @oob_buf: out of band data buffer * @oobsel: out of band selecttion structre * @chipnr: number of the current chip * @oobmode: 1 = full buffer verify, 0 = ecc only */static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode){ int i, datidx = 0, oobofs = 0, res = -EIO; u_char oobdata[64]; /* Send command to read back the first page */ this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); for(;;) { /* Loop through and verify the data */ if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->oobblock)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } datidx += mtd->oobblock; /* check, if we must compare all data or if we just have to * compare the ecc bytes */ if (oobmode) { if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); goto out; } } else { /* Read always, else autoincrement fails */ this->read_buf(mtd, oobdata, mtd->oobsize); if (oobsel->useecc != MTD_NANDECC_OFF) { int ecc_bytes = oobsel->eccbytes; for (i = 0; i < ecc_bytes; i++) { int idx = oobsel->eccpos[i]; if (oobdata[idx] != oob_buf[oobofs + idx] ) { DEBUG (MTD_DEBUG_LEVEL0, "%s: Failed ECC write " "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); goto out; } } } } oobofs += mtd->oobsize; page++; numpages--; if (!numpages) break; /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ if (!this->dev_ready) udelay (this->chip_delay); else while (!this->dev_ready(mtd)); /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this)) this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); } res = 0; /* * Terminate the read command. This is faster than sending a reset command or * applying a 20us delay before issuing the next programm sequence. * This is not a problem for all chips, but I have found a bunch of them. */out: this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); return res;}#endif/* * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL * * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data */static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){ return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);} /* * NAND read with ECC * * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data * @oob_buf: filesystem supplied oob data buffer * @oobsel: oob selection structure */static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel){ int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int erase_state = 0; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; u_char *data_poi, *oob_data = oob_buf; u_char ecc_calc[24]; u_char ecc_code[24]; int eccmode, eccsteps; int *oob_config, datidx; int blockcheck = (mtd->erasesize >> this->page_shift) - 1; DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ nand_get_chip (this, mtd ,FL_READING, &erase_state); /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) oobsel = &mtd->oobinfo; /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) oobsel = this->autooob; eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; oob_config = oobsel->eccpos; /* Select the NAND device */ chipnr = (int)((unsigned long)from / this->chipsize); this->select_chip(mtd, chipnr); /* First we calculate the starting page */ realpage = from >> this->page_shift; page = realpage & this->pagemask; /* Get raw starting column */ col = from & (mtd->oobblock - 1); end = mtd->oobblock; ecc = mtd->eccsize; /* Loop until all data read */ while (read < len) { int aligned = (!col && (len - read) >= end); /* * If the read is not page aligned, we have to read into data buffer * due to ecc, else we read into return buffer direct */ if (aligned) data_poi = &buf[read]; else data_poi = this->data_buf; /* Check, if we have this page in the buffer * * FIXME: Make it work when we must provide oob data too, * check the usage of data_buf oob field */ if (realpage == this->pagebuf && !oob_buf) { /* aligned read ? */ if (aligned) memcpy (data_poi, this->data_buf, end); goto readdata; } /* Check, if we must send the read command */ if (sndcmd) { this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); sndcmd = 0; } /* get oob area, if we have no oob buffer from fs-driver */ if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE) oob_data = &this->data_buf[end]; eccsteps = this->eccsteps; switch (eccmode) { case NAND_ECC_NONE: { /* No ECC, Read in a page */ this->read_buf(mtd, data_poi, end); break; } case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ this->read_buf(mtd, data_poi, end); for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); break; case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data */ case NAND_ECC_HW3_512: /* Hardware ECC 3 byte /512 byte data */ for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) { this->enable_hwecc(mtd, NAND_ECC_READ); this->read_buf(mtd, &data_poi[datidx], ecc); this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); /* read from hardware */ } break; case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data */ for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=6, datidx += ecc) { this->enable_hwecc(mtd, NAND_ECC_READ); this->read_buf(mtd, &data_poi[datidx], ecc); this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); /* read from hardware */ } break; default: printk ("Invalid NAND_ECC_MODE %d\n", this->eccmode); //BUG(); } /* read oobdata */ this->read_buf(mtd, oob_data, mtd->oobsize); /* Skip ECC, if not active */ if (eccmode == NAND_ECC_NONE) goto readdata; /* Pick the ECC bytes out of the oob data */ for (j = 0; j < oobsel->eccbytes; j++) ecc_code[j] = oob_data[oob_config[j]]; /* correct data, if neccecary */ for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); /* Get next chunk of ecc bytes */ j += eccmode == NAND_ECC_HW6_512 ? 6 : 3; /* check, if we have a fs supplied oob-buffer, * This is the legacy mode. Used by YAFFS1 */ if (oob_buf && oobsel->useecc != MTD_NANDECC_AUTOPLACE) { int *p = (int *)(&oob_data[mtd->oobsize]); p[i] = ecc_status; } if (ecc_status == -1) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -