?? nand.c
字號:
if (mtd->oobblock == 512) { this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write*/ this->write_buf(mtd, &this->data_poi[mtd->eccsize], mtd->oobblock - mtd->eccsize); this->calculate_ecc(mtd, NULL, &(ecc_code[3])); for (i = 3; i < 6; i++) oob_data[oob_config[i]] = ecc_code[i]; } break; /* Hardware ecc 3 byte / 512 byte data, write full page */ case NAND_ECC_HW3_512: this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */ this->write_buf(mtd, this->data_poi, mtd->oobblock); this->calculate_ecc(mtd, NULL, &(ecc_code[0])); for (i = 0; i < 3; i++) oob_data[oob_config[i]] = ecc_code[i]; break; /* Hardware ecc 6 byte / 512 byte data, write full page */ case NAND_ECC_HW6_512: this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */ this->write_buf(mtd, this->data_poi, mtd->oobblock); this->calculate_ecc(mtd, NULL, &(ecc_code[0])); for (i = 0; i < 6; i++) oob_data[oob_config[i]] = ecc_code[i]; break; default: printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); BUG(); } /* Write out OOB data */ this->write_buf(mtd, oob_data, mtd->oobsize); /* Send command to actually program the data */ this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); /* 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; }#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. */ /* Send command to read back the page */ this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); /* Loop through and verify the data */ if (this->verify_buf(mtd, this->data_poi, mtd->oobblock)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); return -EIO; } /* check, if we have a fs-supplied oob-buffer */ if (oob_buf) { if (this->verify_buf(mtd, oob_data, mtd->oobsize)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); return -EIO; } } else { if (eccmode != NAND_ECC_NONE) { int ecc_bytes = 0; switch (this->eccmode) { case NAND_ECC_SOFT: case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break; case NAND_ECC_HW3_512: ecc_bytes = 3; break; case NAND_ECC_HW6_512: ecc_bytes = 6; break; } this->read_buf(mtd, oob_data, mtd->oobsize); for (i = 0; i < ecc_bytes; i++) { if (oob_data[oob_config[i]] != ecc_code[i]) { DEBUG (MTD_DEBUG_LEVEL0, "%s: Failed ECC write " "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); return -EIO; } } } }#endif return 0;}/** Use NAND read ECC*/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 */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 j, col, page, end, ecc; 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[6]; u_char ecc_code[6]; int eccmode; int *oob_config; // use chip default if zero if (oobsel == NULL) oobsel = &mtd->oobinfo; eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; oob_config = oobsel->eccpos; 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); /* Select the NAND device */ this->select_chip(mtd, 0); /* First we calculate the starting page */ page = from >> this->page_shift; /* Get raw starting column */ col = from & (mtd->oobblock - 1); end = mtd->oobblock; ecc = mtd->eccsize; /* Send the read command */ this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); /* Loop until all data read */ while (read < len) { /* If we have consequent page reads, apply delay or wait for ready/busy pin */ if (read) { if (!this->dev_ready) udelay (this->chip_delay); else while (!this->dev_ready(mtd)); } /* * 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 (!col && (len - read) >= end) data_poi = &buf[read]; else data_poi = this->data_buf; /* get oob area, if we have no oob buffer from fs-driver */ if (!oob_buf) { oob_data = &this->data_buf[end]; oob = 0; } j = 0; 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); this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); if (mtd->oobblock == 512) this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]); break; case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */ this->enable_hwecc(mtd, NAND_ECC_READ); this->read_buf(mtd, data_poi, ecc); this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */ if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */ this->enable_hwecc(mtd, NAND_ECC_READ); this->read_buf(mtd, &data_poi[ecc], end-ecc); this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]); /* read from hardware */ } break; case NAND_ECC_HW3_512: case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page */ this->enable_hwecc(mtd, NAND_ECC_READ); this->read_buf(mtd, data_poi, end); this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */ break; default: printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); BUG(); } /* read oobdata */ for (j = 0; j < mtd->oobsize; j++) oob_data[oob + j] = this->read_byte(mtd); /* 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 < 6; j++) ecc_code[j] = oob_data[oob + oob_config[j]]; /* correct data, if neccecary */ ecc_status = this->correct_data(mtd, &data_poi[0], &ecc_code[0], &ecc_calc[0]); /* check, if we have a fs supplied oob-buffer */ if (oob_buf) { oob += mtd->oobsize; *((int *)&oob_data[oob]) = ecc_status; oob += sizeof(int); } if (ecc_status == -1) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) { ecc_status = this->correct_data(mtd, &data_poi[256], &ecc_code[3], &ecc_calc[3]); if (oob_buf) { *((int *)&oob_data[oob]) = ecc_status; oob += sizeof(int); } if (ecc_status == -1) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } }readdata: if (col || (len - read) < end) { for (j = col; j < end && read < len; j++) buf[read++] = data_poi[j]; } else read += mtd->oobblock; /* For subsequent reads align to page boundary. */ col = 0; /* Increment page address */ page++; } /* De-select the NAND device */ this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); /* * Return success, if no ECC failures, else -EIO * fs driver will take care of that, because * retlen == desired len and result == -EIO */ *retlen = read; return ecc_failed ? -EIO : 0;}/* * NAND read out-of-band */static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){ int i, col, page; int erase_state = 0; struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Shift to get page */ page = ((int) from) >> this->page_shift; /* Mask to get column */ col = from & 0x0f; /* Initialize return length value */ *retlen = 0; /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: 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); /* Select the NAND device */ this->select_chip(mtd, 0); /* Send the read command */ this->cmdfunc (mtd, NAND_CMD_READOOB, col, page); /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ i = 0; while (i < len) { int thislen = (mtd->oobsize - col) & (mtd->oobsize - 1); if (!thislen) thislen = mtd->oobsize; thislen = min_t(int, thislen, len); this->read_buf(mtd, &buf[i], thislen); i += thislen; col += thislen; /* Delay between pages */ udelay (this->chip_delay); } /* De-select the NAND device */ this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); /* Return happy */ *retlen = len; return 0;}//#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0/** Use NAND write ECC*/static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){ return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));} /* * NAND write with ECC */static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel){ int i, page, col, cnt, ret = 0, oob = 0, written = 0; struct nand_chip *this = mtd->priv; DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Do not allow write past end of device */ if ((to + len) > mtd->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); return -EINVAL; } /* reject writes, which are not page aligned */ // if (NOTALIGNED (to) || NOTALIGNED(len)) {// printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");// return -EINVAL;// } // if oobsel is NULL, use chip defaults if (oobsel == NULL) oobsel = &mtd->oobinfo; /* Shift to get page */ page = ((int) to) >> this->page_shift; col = to & (mtd->oobblock - 1); /* Grab the lock and see if the device is available */ nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ this->select_chip(mtd, 0); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); if (!(this->read_byte(mtd) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n"); ret = -EIO; goto out; } /* Loop until all data is written */ while (written < len) { /* * Check, if we have a full page write, then we can * use the given buffer, else we have to copy */ if (!col && (len - written) >= mtd->oobblock) { this->data_poi = (u_char*) &buf[written]; cnt = mtd->oobblock; } else { cnt = 0; for (i = col; i < len && i < mtd->oobblock; i++) { this->data_buf[i] = buf[written + i]; cnt++; } this->data_poi = this->data_buf; } /* We use the same function for write and writev !) */ if (eccbuf) { ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel); oob += mtd->oobsize; } else ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel); if (ret) goto out; /* Update written bytes count */ written += cnt; col = 0; /* Increment page address */ page++; }out: /* De-select the NAND device */ this->select_chip(mtd, -1); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); *retlen = written; return ret;}static u_char ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};/* * NAND write out-of-band */static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){ int column, page, status, ret = 0; struct nand_chip *this = mtd->priv;#ifdef CONFIG_MTD_NAND_VERIFY_WRITE int i;#endif DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Shift to get page */ page = ((int) to) >> this->page_shift; /* Mask to get column */ column = to & 0x1f; /* Initialize return length value */ *retlen = 0; /* Do not allow write past end of page */ if ((column + len) > mtd->oobsize) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ this->select_chip(mtd, 0); /* Reset the chip. Some chips (like the Toshiba TC5832DC found in one of my DiskOnChip 2000 test units) will clear the whole data page too if we don't do this. I have no clue why, but I seem to have 'fixed' it in the doc2000 driver in August 1999. dwmw2. */ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); if (!(this->read_byte(mtd) & 0x80)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n"); ret = -EIO; goto out; } /* Write out desired data */ this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page); /* prepad 0xff for partial programming */ this->write_buf(mtd, ffchars, column); /* write data */ this->write_buf(mtd, buf, len); /* postpad 0xff for partial programming */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -