📄 yynf_nand.c
字号:
/* check, if we have a fs-supplied oob-buffer */ if (oob_buf) { for (i = 0; i < mtd->oobsize; i++) { if (oob_data[i] != readb (this->IO_ADDR_R)) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); return -EIO; } } } else { if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) { 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; } for (i = 0; i < mtd->oobsize; i++) oob_data[i] = readb (this->IO_ADDR_R); 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, 0));} /* * 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, int 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 = oobsel ? this->eccmode : NAND_ECC_NONE; int *oob_config = oobconfigs[oobsel]; 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 */ nand_select (); /* 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()); } /* * 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 */ while (j < end) data_poi[j++] = readb (this->IO_ADDR_R); break; case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ while (j < end) data_poi[j++] = readb (this->IO_ADDR_R); this->calculate_ecc (&data_poi[0], &ecc_calc[0]); if (mtd->oobblock == 512) this->calculate_ecc (&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 (NAND_ECC_READ); while (j < ecc) data_poi[j++] = readb (this->IO_ADDR_R); this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */ if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */ this->enable_hwecc (NAND_ECC_READ); while (j < end) data_poi[j++] = readb (this->IO_ADDR_R); this->calculate_ecc (&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 (NAND_ECC_READ); while (j < end) data_poi[j++] = readb (this->IO_ADDR_R); this->calculate_ecc (&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] = readb (this->IO_ADDR_R); /* 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 (&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 (&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 */ nand_deselect (); /* 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 */ nand_select (); /* 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 ! */ for (i = 0; i < len; i++) { buf[i] = readb (this->IO_ADDR_R); if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1)) udelay (this->chip_delay); } /* De-select the NAND device */ nand_deselect (); /* 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;}/** 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, 0));} /* * 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, int 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_oob: Attempt to write past end of page\n"); return -EINVAL; } /* Shift to get page */ page = ((int) to) >> this->page_shift; /* Get the starting column */ 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 */ nand_select (); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); if (!(readb (this->IO_ADDR_R) & 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; /* Next write is aligned */ col = 0; /* Increment page address */ page++; }out: /* De-select the NAND device */ nand_deselect (); /* 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;}/* * 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 i, column, page, status, ret = 0; struct nand_chip *this = mtd->priv; 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 */ nand_select (); /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); if (!(readb (this->IO_ADDR_R) & 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 */ for (i = 0; i < column; i++) writeb (0xff, this->IO_ADDR_W); /* write data */ for (i = 0; i < len; i++) writeb (buf[i], this->IO_ADDR_W); /* postpad 0xff for partial programming */ for (i = len + column; i < mtd->oobsize; i++) writeb (0xff, this->IO_ADDR_W); /* Send command to program the OOB data */ this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ if (status & 0x01) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; } /* Return happy */ *retlen = len;#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ this->cmdfunc (mtd, NAND_CMD_READOOB, column, page); /* Loop through and verify the data */ for (i = 0; i < len; i++) { if (buf[i] != readb (this->IO_ADDR_R)) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); ret = -EIO; goto out; } }#endifout: /* De-select the NAND device */ nand_deselect (); /* 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 ret;}/* * NAND write with iovec */static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t * retlen){ return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0)); }static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, int oobsel){ int i, page, col, cnt, len, total_len, ret = 0, written = 0; struct nand_chip *this = mtd->priv; /* Calculate total length of data */ total_len = 0; for (i = 0; i < count; i++) total_len += (int) vecs[i].iov_len; DEBUG (MTD_DEBUG_LEVEL3, "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); /* Do not allow write past end of page */ if ((to + total_len) > mtd->size) { DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); return -EINVAL; } /* Shift to get page */ page = ((int) to) >> this->page_shift; /* Get the starting column */ col = to & (mtd->oobblock - 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -