diff options
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 156 |
1 files changed, 81 insertions, 75 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 61b2363f9324..49bca242610b 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -1270,86 +1270,91 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
1270 | * | 1270 | * |
1271 | * NAND read out-of-band data from the spare area | 1271 | * NAND read out-of-band data from the spare area |
1272 | */ | 1272 | */ |
1273 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) | 1273 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, |
1274 | size_t *retlen, uint8_t *buf) | ||
1274 | { | 1275 | { |
1275 | int i, col, page, chipnr; | 1276 | int col, page, realpage, chipnr, sndcmd = 1; |
1276 | struct nand_chip *chip = mtd->priv; | 1277 | struct nand_chip *chip = mtd->priv; |
1277 | int blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | 1278 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; |
1278 | 1279 | int readlen = len; | |
1279 | DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len); | ||
1280 | |||
1281 | /* Shift to get page */ | ||
1282 | page = (int)(from >> chip->page_shift); | ||
1283 | chipnr = (int)(from >> chip->chip_shift); | ||
1284 | 1280 | ||
1285 | /* Mask to get column */ | 1281 | DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", |
1286 | col = from & (mtd->oobsize - 1); | 1282 | (unsigned int)from, (int)len); |
1287 | 1283 | ||
1288 | /* Initialize return length value */ | 1284 | /* Initialize return length value */ |
1289 | *retlen = 0; | 1285 | *retlen = 0; |
1290 | 1286 | ||
1291 | /* Do not allow reads past end of device */ | 1287 | /* Do not allow reads past end of device */ |
1292 | if ((from + len) > mtd->size) { | 1288 | if ((from + len) > mtd->size) { |
1293 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); | 1289 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " |
1294 | *retlen = 0; | 1290 | "Attempt read beyond end of device\n"); |
1295 | return -EINVAL; | 1291 | return -EINVAL; |
1296 | } | 1292 | } |
1297 | 1293 | ||
1298 | /* Grab the lock and see if the device is available */ | ||
1299 | nand_get_device(chip, mtd, FL_READING); | 1294 | nand_get_device(chip, mtd, FL_READING); |
1300 | 1295 | ||
1301 | /* Select the NAND device */ | 1296 | chipnr = (int)(from >> chip->chip_shift); |
1302 | chip->select_chip(mtd, chipnr); | 1297 | chip->select_chip(mtd, chipnr); |
1303 | 1298 | ||
1304 | /* Send the read command */ | 1299 | /* Shift to get page */ |
1305 | chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page & chip->pagemask); | 1300 | realpage = (int)(from >> chip->page_shift); |
1306 | /* | 1301 | page = realpage & chip->pagemask; |
1307 | * Read the data, if we read more than one page | ||
1308 | * oob data, let the device transfer the data ! | ||
1309 | */ | ||
1310 | i = 0; | ||
1311 | while (i < len) { | ||
1312 | int thislen = mtd->oobsize - col; | ||
1313 | thislen = min_t(int, thislen, len); | ||
1314 | chip->read_buf(mtd, &buf[i], thislen); | ||
1315 | i += thislen; | ||
1316 | |||
1317 | /* Read more ? */ | ||
1318 | if (i < len) { | ||
1319 | page++; | ||
1320 | col = 0; | ||
1321 | 1302 | ||
1322 | /* Check, if we cross a chip boundary */ | 1303 | /* Mask to get column */ |
1323 | if (!(page & chip->pagemask)) { | 1304 | col = from & (mtd->oobsize - 1); |
1324 | chipnr++; | 1305 | |
1325 | chip->select_chip(mtd, -1); | 1306 | while(1) { |
1326 | chip->select_chip(mtd, chipnr); | 1307 | int bytes = min((int)(mtd->oobsize - col), readlen); |
1327 | } | 1308 | |
1309 | if (likely(sndcmd)) { | ||
1310 | chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page); | ||
1311 | sndcmd = 0; | ||
1312 | } | ||
1313 | |||
1314 | chip->read_buf(mtd, buf, bytes); | ||
1328 | 1315 | ||
1329 | /* Apply delay or wait for ready/busy pin | 1316 | readlen -= bytes; |
1330 | * Do this before the AUTOINCR check, so no problems | 1317 | if (!readlen) |
1331 | * arise if a chip which does auto increment | 1318 | break; |
1332 | * is marked as NOAUTOINCR by the board driver. | 1319 | |
1320 | if (!(chip->options & NAND_NO_READRDY)) { | ||
1321 | /* | ||
1322 | * Apply delay or wait for ready/busy pin. Do this | ||
1323 | * before the AUTOINCR check, so no problems arise if a | ||
1324 | * chip which does auto increment is marked as | ||
1325 | * NOAUTOINCR by the board driver. | ||
1333 | */ | 1326 | */ |
1334 | if (!chip->dev_ready) | 1327 | if (!chip->dev_ready) |
1335 | udelay(chip->chip_delay); | 1328 | udelay(chip->chip_delay); |
1336 | else | 1329 | else |
1337 | nand_wait_ready(mtd); | 1330 | nand_wait_ready(mtd); |
1331 | } | ||
1338 | 1332 | ||
1339 | /* Check, if the chip supports auto page increment | 1333 | buf += bytes; |
1340 | * or if we have hit a block boundary. | 1334 | bytes = mtd->oobsize; |
1341 | */ | 1335 | col = 0; |
1342 | if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck)) { | 1336 | |
1343 | /* For subsequent page reads set offset to 0 */ | 1337 | /* Increment page address */ |
1344 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x0, page & chip->pagemask); | 1338 | realpage++; |
1345 | } | 1339 | |
1340 | page = realpage & chip->pagemask; | ||
1341 | /* Check, if we cross a chip boundary */ | ||
1342 | if (!page) { | ||
1343 | chipnr++; | ||
1344 | chip->select_chip(mtd, -1); | ||
1345 | chip->select_chip(mtd, chipnr); | ||
1346 | } | 1346 | } |
1347 | |||
1348 | /* Check, if the chip supports auto page increment | ||
1349 | * or if we have hit a block boundary. | ||
1350 | */ | ||
1351 | if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) | ||
1352 | sndcmd = 1; | ||
1347 | } | 1353 | } |
1348 | 1354 | ||
1349 | /* Deselect and wake up anyone waiting on the device */ | 1355 | /* Deselect and wake up anyone waiting on the device */ |
1350 | nand_release_device(mtd); | 1356 | nand_release_device(mtd); |
1351 | 1357 | ||
1352 | /* Return happy */ | ||
1353 | *retlen = len; | 1358 | *retlen = len; |
1354 | return 0; | 1359 | return 0; |
1355 | } | 1360 | } |
@@ -1676,6 +1681,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1676 | return ret; | 1681 | return ret; |
1677 | } | 1682 | } |
1678 | 1683 | ||
1684 | |||
1679 | /** | 1685 | /** |
1680 | * nand_write_oob - [MTD Interface] NAND write out-of-band | 1686 | * nand_write_oob - [MTD Interface] NAND write out-of-band |
1681 | * @mtd: MTD device structure | 1687 | * @mtd: MTD device structure |
@@ -1686,40 +1692,40 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1686 | * | 1692 | * |
1687 | * NAND write out-of-band | 1693 | * NAND write out-of-band |
1688 | */ | 1694 | */ |
1689 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) | 1695 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, |
1696 | size_t *retlen, const uint8_t *buf) | ||
1690 | { | 1697 | { |
1691 | int column, page, status, ret = -EIO, chipnr; | 1698 | int column, page, status, ret = -EIO, chipnr; |
1692 | struct nand_chip *chip = mtd->priv; | 1699 | struct nand_chip *chip = mtd->priv; |
1693 | 1700 | ||
1694 | DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); | 1701 | DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", |
1695 | 1702 | (unsigned int)to, (int)len); | |
1696 | /* Shift to get page */ | ||
1697 | page = (int)(to >> chip->page_shift); | ||
1698 | chipnr = (int)(to >> chip->chip_shift); | ||
1699 | |||
1700 | /* Mask to get column */ | ||
1701 | column = to & (mtd->oobsize - 1); | ||
1702 | 1703 | ||
1703 | /* Initialize return length value */ | 1704 | /* Initialize return length value */ |
1704 | *retlen = 0; | 1705 | *retlen = 0; |
1705 | 1706 | ||
1706 | /* Do not allow write past end of page */ | 1707 | /* Do not allow write past end of page */ |
1708 | column = to & (mtd->oobsize - 1); | ||
1707 | if ((column + len) > mtd->oobsize) { | 1709 | if ((column + len) > mtd->oobsize) { |
1708 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); | 1710 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " |
1711 | "Attempt to write past end of page\n"); | ||
1709 | return -EINVAL; | 1712 | return -EINVAL; |
1710 | } | 1713 | } |
1711 | 1714 | ||
1712 | /* Grab the lock and see if the device is available */ | ||
1713 | nand_get_device(chip, mtd, FL_WRITING); | 1715 | nand_get_device(chip, mtd, FL_WRITING); |
1714 | 1716 | ||
1715 | /* Select the NAND device */ | 1717 | chipnr = (int)(to >> chip->chip_shift); |
1716 | chip->select_chip(mtd, chipnr); | 1718 | chip->select_chip(mtd, chipnr); |
1717 | 1719 | ||
1718 | /* Reset the chip. Some chips (like the Toshiba TC5832DC found | 1720 | /* Shift to get page */ |
1719 | in one of my DiskOnChip 2000 test units) will clear the whole | 1721 | page = (int)(to >> chip->page_shift); |
1720 | data page too if we don't do this. I have no clue why, but | 1722 | |
1721 | I seem to have 'fixed' it in the doc2000 driver in | 1723 | /* |
1722 | August 1999. dwmw2. */ | 1724 | * Reset the chip. Some chips (like the Toshiba TC5832DC found in one |
1725 | * of my DiskOnChip 2000 test units) will clear the whole data page too | ||
1726 | * if we don't do this. I have no clue why, but I seem to have 'fixed' | ||
1727 | * it in the doc2000 driver in August 1999. dwmw2. | ||
1728 | */ | ||
1723 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | 1729 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); |
1724 | 1730 | ||
1725 | /* Check, if it is write protected */ | 1731 | /* Check, if it is write protected */ |
@@ -1731,8 +1737,8 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r | |||
1731 | chip->pagebuf = -1; | 1737 | chip->pagebuf = -1; |
1732 | 1738 | ||
1733 | if (NAND_MUST_PAD(chip)) { | 1739 | if (NAND_MUST_PAD(chip)) { |
1734 | /* Write out desired data */ | 1740 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, |
1735 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page & chip->pagemask); | 1741 | page & chip->pagemask); |
1736 | /* prepad 0xff for partial programming */ | 1742 | /* prepad 0xff for partial programming */ |
1737 | chip->write_buf(mtd, ffchars, column); | 1743 | chip->write_buf(mtd, ffchars, column); |
1738 | /* write data */ | 1744 | /* write data */ |
@@ -1740,9 +1746,8 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r | |||
1740 | /* postpad 0xff for partial programming */ | 1746 | /* postpad 0xff for partial programming */ |
1741 | chip->write_buf(mtd, ffchars, mtd->oobsize - (len + column)); | 1747 | chip->write_buf(mtd, ffchars, mtd->oobsize - (len + column)); |
1742 | } else { | 1748 | } else { |
1743 | /* Write out desired data */ | 1749 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, |
1744 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, page & chip->pagemask); | 1750 | page & chip->pagemask); |
1745 | /* write data */ | ||
1746 | chip->write_buf(mtd, buf, len); | 1751 | chip->write_buf(mtd, buf, len); |
1747 | } | 1752 | } |
1748 | /* Send command to program the OOB data */ | 1753 | /* Send command to program the OOB data */ |
@@ -1752,11 +1757,11 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r | |||
1752 | 1757 | ||
1753 | /* See if device thinks it succeeded */ | 1758 | /* See if device thinks it succeeded */ |
1754 | if (status & NAND_STATUS_FAIL) { | 1759 | if (status & NAND_STATUS_FAIL) { |
1755 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); | 1760 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " |
1761 | "Failed write, page 0x%08x\n", page); | ||
1756 | ret = -EIO; | 1762 | ret = -EIO; |
1757 | goto out; | 1763 | goto out; |
1758 | } | 1764 | } |
1759 | /* Return happy */ | ||
1760 | *retlen = len; | 1765 | *retlen = len; |
1761 | 1766 | ||
1762 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 1767 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
@@ -1764,7 +1769,8 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r | |||
1764 | chip->cmdfunc(mtd, NAND_CMD_READOOB, column, page & chip->pagemask); | 1769 | chip->cmdfunc(mtd, NAND_CMD_READOOB, column, page & chip->pagemask); |
1765 | 1770 | ||
1766 | if (chip->verify_buf(mtd, buf, len)) { | 1771 | if (chip->verify_buf(mtd, buf, len)) { |
1767 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); | 1772 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " |
1773 | "Failed write verify, page 0x%08x\n", page); | ||
1768 | ret = -EIO; | 1774 | ret = -EIO; |
1769 | goto out; | 1775 | goto out; |
1770 | } | 1776 | } |