aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r--drivers/mtd/nand/nand_base.c133
1 files changed, 91 insertions, 42 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 41bfcae1fbf4..dfe56e03e48b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -362,7 +362,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
362 * access 362 * access
363 */ 363 */
364 ofs += mtd->oobsize; 364 ofs += mtd->oobsize;
365 chip->ops.len = 2; 365 chip->ops.len = chip->ops.ooblen = 2;
366 chip->ops.datbuf = NULL; 366 chip->ops.datbuf = NULL;
367 chip->ops.oobbuf = buf; 367 chip->ops.oobbuf = buf;
368 chip->ops.ooboffs = chip->badblockpos & ~0x01; 368 chip->ops.ooboffs = chip->badblockpos & ~0x01;
@@ -755,7 +755,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
755} 755}
756 756
757/** 757/**
758 * nand_read_page_swecc - {REPLACABLE] software ecc based page read function 758 * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
759 * @mtd: mtd info structure 759 * @mtd: mtd info structure
760 * @chip: nand chip info structure 760 * @chip: nand chip info structure
761 * @buf: buffer to store read data 761 * @buf: buffer to store read data
@@ -795,7 +795,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
795} 795}
796 796
797/** 797/**
798 * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function 798 * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
799 * @mtd: mtd info structure 799 * @mtd: mtd info structure
800 * @chip: nand chip info structure 800 * @chip: nand chip info structure
801 * @buf: buffer to store read data 801 * @buf: buffer to store read data
@@ -839,7 +839,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
839} 839}
840 840
841/** 841/**
842 * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read 842 * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
843 * @mtd: mtd info structure 843 * @mtd: mtd info structure
844 * @chip: nand chip info structure 844 * @chip: nand chip info structure
845 * @buf: buffer to store read data 845 * @buf: buffer to store read data
@@ -897,12 +897,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
897 * @chip: nand chip structure 897 * @chip: nand chip structure
898 * @oob: oob destination address 898 * @oob: oob destination address
899 * @ops: oob ops structure 899 * @ops: oob ops structure
900 * @len: size of oob to transfer
900 */ 901 */
901static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, 902static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
902 struct mtd_oob_ops *ops) 903 struct mtd_oob_ops *ops, size_t len)
903{ 904{
904 size_t len = ops->ooblen;
905
906 switch(ops->mode) { 905 switch(ops->mode) {
907 906
908 case MTD_OOB_PLACE: 907 case MTD_OOB_PLACE:
@@ -960,6 +959,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
960 int sndcmd = 1; 959 int sndcmd = 1;
961 int ret = 0; 960 int ret = 0;
962 uint32_t readlen = ops->len; 961 uint32_t readlen = ops->len;
962 uint32_t oobreadlen = ops->ooblen;
963 uint8_t *bufpoi, *oob, *buf; 963 uint8_t *bufpoi, *oob, *buf;
964 964
965 stats = mtd->ecc_stats; 965 stats = mtd->ecc_stats;
@@ -971,7 +971,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
971 page = realpage & chip->pagemask; 971 page = realpage & chip->pagemask;
972 972
973 col = (int)(from & (mtd->writesize - 1)); 973 col = (int)(from & (mtd->writesize - 1));
974 chip->oob_poi = chip->buffers->oobrbuf;
975 974
976 buf = ops->datbuf; 975 buf = ops->datbuf;
977 oob = ops->oobbuf; 976 oob = ops->oobbuf;
@@ -1007,10 +1006,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1007 1006
1008 if (unlikely(oob)) { 1007 if (unlikely(oob)) {
1009 /* Raw mode does data:oob:data:oob */ 1008 /* Raw mode does data:oob:data:oob */
1010 if (ops->mode != MTD_OOB_RAW) 1009 if (ops->mode != MTD_OOB_RAW) {
1011 oob = nand_transfer_oob(chip, oob, ops); 1010 int toread = min(oobreadlen,
1012 else 1011 chip->ecc.layout->oobavail);
1013 buf = nand_transfer_oob(chip, buf, ops); 1012 if (toread) {
1013 oob = nand_transfer_oob(chip,
1014 oob, ops, toread);
1015 oobreadlen -= toread;
1016 }
1017 } else
1018 buf = nand_transfer_oob(chip,
1019 buf, ops, mtd->oobsize);
1014 } 1020 }
1015 1021
1016 if (!(chip->options & NAND_NO_READRDY)) { 1022 if (!(chip->options & NAND_NO_READRDY)) {
@@ -1057,6 +1063,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1057 } 1063 }
1058 1064
1059 ops->retlen = ops->len - (size_t) readlen; 1065 ops->retlen = ops->len - (size_t) readlen;
1066 if (oob)
1067 ops->oobretlen = ops->ooblen - oobreadlen;
1060 1068
1061 if (ret) 1069 if (ret)
1062 return ret; 1070 return ret;
@@ -1257,12 +1265,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1257 int page, realpage, chipnr, sndcmd = 1; 1265 int page, realpage, chipnr, sndcmd = 1;
1258 struct nand_chip *chip = mtd->priv; 1266 struct nand_chip *chip = mtd->priv;
1259 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; 1267 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1260 int readlen = ops->len; 1268 int readlen = ops->ooblen;
1269 int len;
1261 uint8_t *buf = ops->oobbuf; 1270 uint8_t *buf = ops->oobbuf;
1262 1271
1263 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", 1272 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
1264 (unsigned long long)from, readlen); 1273 (unsigned long long)from, readlen);
1265 1274
1275 if (ops->mode == MTD_OOB_RAW)
1276 len = mtd->oobsize;
1277 else
1278 len = chip->ecc.layout->oobavail;
1279
1266 chipnr = (int)(from >> chip->chip_shift); 1280 chipnr = (int)(from >> chip->chip_shift);
1267 chip->select_chip(mtd, chipnr); 1281 chip->select_chip(mtd, chipnr);
1268 1282
@@ -1270,11 +1284,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1270 realpage = (int)(from >> chip->page_shift); 1284 realpage = (int)(from >> chip->page_shift);
1271 page = realpage & chip->pagemask; 1285 page = realpage & chip->pagemask;
1272 1286
1273 chip->oob_poi = chip->buffers->oobrbuf;
1274
1275 while(1) { 1287 while(1) {
1276 sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); 1288 sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
1277 buf = nand_transfer_oob(chip, buf, ops); 1289
1290 len = min(len, readlen);
1291 buf = nand_transfer_oob(chip, buf, ops, len);
1278 1292
1279 if (!(chip->options & NAND_NO_READRDY)) { 1293 if (!(chip->options & NAND_NO_READRDY)) {
1280 /* 1294 /*
@@ -1289,7 +1303,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1289 nand_wait_ready(mtd); 1303 nand_wait_ready(mtd);
1290 } 1304 }
1291 1305
1292 readlen -= ops->ooblen; 1306 readlen -= len;
1293 if (!readlen) 1307 if (!readlen)
1294 break; 1308 break;
1295 1309
@@ -1311,7 +1325,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1311 sndcmd = 1; 1325 sndcmd = 1;
1312 } 1326 }
1313 1327
1314 ops->retlen = ops->len; 1328 ops->oobretlen = ops->ooblen;
1315 return 0; 1329 return 0;
1316} 1330}
1317 1331
@@ -1332,7 +1346,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
1332 ops->retlen = 0; 1346 ops->retlen = 0;
1333 1347
1334 /* Do not allow reads past end of device */ 1348 /* Do not allow reads past end of device */
1335 if ((from + ops->len) > mtd->size) { 1349 if (ops->datbuf && (from + ops->len) > mtd->size) {
1336 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " 1350 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1337 "Attempt read beyond end of device\n"); 1351 "Attempt read beyond end of device\n");
1338 return -EINVAL; 1352 return -EINVAL;
@@ -1375,7 +1389,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
1375} 1389}
1376 1390
1377/** 1391/**
1378 * nand_write_page_swecc - {REPLACABLE] software ecc based page write function 1392 * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
1379 * @mtd: mtd info structure 1393 * @mtd: mtd info structure
1380 * @chip: nand chip info structure 1394 * @chip: nand chip info structure
1381 * @buf: data buffer 1395 * @buf: data buffer
@@ -1401,7 +1415,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
1401} 1415}
1402 1416
1403/** 1417/**
1404 * nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function 1418 * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
1405 * @mtd: mtd info structure 1419 * @mtd: mtd info structure
1406 * @chip: nand chip info structure 1420 * @chip: nand chip info structure
1407 * @buf: data buffer 1421 * @buf: data buffer
@@ -1429,7 +1443,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
1429} 1443}
1430 1444
1431/** 1445/**
1432 * nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write 1446 * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
1433 * @mtd: mtd info structure 1447 * @mtd: mtd info structure
1434 * @chip: nand chip info structure 1448 * @chip: nand chip info structure
1435 * @buf: data buffer 1449 * @buf: data buffer
@@ -1577,7 +1591,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
1577 return NULL; 1591 return NULL;
1578} 1592}
1579 1593
1580#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 1594#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
1581 1595
1582/** 1596/**
1583 * nand_do_write_ops - [Internal] NAND write with ECC 1597 * nand_do_write_ops - [Internal] NAND write with ECC
@@ -1590,15 +1604,16 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
1590static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, 1604static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1591 struct mtd_oob_ops *ops) 1605 struct mtd_oob_ops *ops)
1592{ 1606{
1593 int chipnr, realpage, page, blockmask; 1607 int chipnr, realpage, page, blockmask, column;
1594 struct nand_chip *chip = mtd->priv; 1608 struct nand_chip *chip = mtd->priv;
1595 uint32_t writelen = ops->len; 1609 uint32_t writelen = ops->len;
1596 uint8_t *oob = ops->oobbuf; 1610 uint8_t *oob = ops->oobbuf;
1597 uint8_t *buf = ops->datbuf; 1611 uint8_t *buf = ops->datbuf;
1598 int bytes = mtd->writesize; 1612 int ret, subpage;
1599 int ret;
1600 1613
1601 ops->retlen = 0; 1614 ops->retlen = 0;
1615 if (!writelen)
1616 return 0;
1602 1617
1603 /* reject writes, which are not page aligned */ 1618 /* reject writes, which are not page aligned */
1604 if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { 1619 if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
@@ -1607,8 +1622,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1607 return -EINVAL; 1622 return -EINVAL;
1608 } 1623 }
1609 1624
1610 if (!writelen) 1625 column = to & (mtd->writesize - 1);
1611 return 0; 1626 subpage = column || (writelen & (mtd->writesize - 1));
1627
1628 if (subpage && oob)
1629 return -EINVAL;
1612 1630
1613 chipnr = (int)(to >> chip->chip_shift); 1631 chipnr = (int)(to >> chip->chip_shift);
1614 chip->select_chip(mtd, chipnr); 1632 chip->select_chip(mtd, chipnr);
@@ -1626,15 +1644,29 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1626 (chip->pagebuf << chip->page_shift) < (to + ops->len)) 1644 (chip->pagebuf << chip->page_shift) < (to + ops->len))
1627 chip->pagebuf = -1; 1645 chip->pagebuf = -1;
1628 1646
1629 chip->oob_poi = chip->buffers->oobwbuf; 1647 /* If we're not given explicit OOB data, let it be 0xFF */
1648 if (likely(!oob))
1649 memset(chip->oob_poi, 0xff, mtd->oobsize);
1630 1650
1631 while(1) { 1651 while(1) {
1652 int bytes = mtd->writesize;
1632 int cached = writelen > bytes && page != blockmask; 1653 int cached = writelen > bytes && page != blockmask;
1654 uint8_t *wbuf = buf;
1655
1656 /* Partial page write ? */
1657 if (unlikely(column || writelen < (mtd->writesize - 1))) {
1658 cached = 0;
1659 bytes = min_t(int, bytes - column, (int) writelen);
1660 chip->pagebuf = -1;
1661 memset(chip->buffers->databuf, 0xff, mtd->writesize);
1662 memcpy(&chip->buffers->databuf[column], buf, bytes);
1663 wbuf = chip->buffers->databuf;
1664 }
1633 1665
1634 if (unlikely(oob)) 1666 if (unlikely(oob))
1635 oob = nand_fill_oob(chip, oob, ops); 1667 oob = nand_fill_oob(chip, oob, ops);
1636 1668
1637 ret = chip->write_page(mtd, chip, buf, page, cached, 1669 ret = chip->write_page(mtd, chip, wbuf, page, cached,
1638 (ops->mode == MTD_OOB_RAW)); 1670 (ops->mode == MTD_OOB_RAW));
1639 if (ret) 1671 if (ret)
1640 break; 1672 break;
@@ -1643,6 +1675,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1643 if (!writelen) 1675 if (!writelen)
1644 break; 1676 break;
1645 1677
1678 column = 0;
1646 buf += bytes; 1679 buf += bytes;
1647 realpage++; 1680 realpage++;
1648 1681
@@ -1655,10 +1688,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1655 } 1688 }
1656 } 1689 }
1657 1690
1658 if (unlikely(oob))
1659 memset(chip->oob_poi, 0xff, mtd->oobsize);
1660
1661 ops->retlen = ops->len - writelen; 1691 ops->retlen = ops->len - writelen;
1692 if (unlikely(oob))
1693 ops->oobretlen = ops->ooblen;
1662 return ret; 1694 return ret;
1663} 1695}
1664 1696
@@ -1714,10 +1746,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
1714 struct nand_chip *chip = mtd->priv; 1746 struct nand_chip *chip = mtd->priv;
1715 1747
1716 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", 1748 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
1717 (unsigned int)to, (int)ops->len); 1749 (unsigned int)to, (int)ops->ooblen);
1718 1750
1719 /* Do not allow write past end of page */ 1751 /* Do not allow write past end of page */
1720 if ((ops->ooboffs + ops->len) > mtd->oobsize) { 1752 if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
1721 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " 1753 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1722 "Attempt to write past end of page\n"); 1754 "Attempt to write past end of page\n");
1723 return -EINVAL; 1755 return -EINVAL;
@@ -1745,7 +1777,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
1745 if (page == chip->pagebuf) 1777 if (page == chip->pagebuf)
1746 chip->pagebuf = -1; 1778 chip->pagebuf = -1;
1747 1779
1748 chip->oob_poi = chip->buffers->oobwbuf;
1749 memset(chip->oob_poi, 0xff, mtd->oobsize); 1780 memset(chip->oob_poi, 0xff, mtd->oobsize);
1750 nand_fill_oob(chip, ops->oobbuf, ops); 1781 nand_fill_oob(chip, ops->oobbuf, ops);
1751 status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); 1782 status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
@@ -1754,7 +1785,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
1754 if (status) 1785 if (status)
1755 return status; 1786 return status;
1756 1787
1757 ops->retlen = ops->len; 1788 ops->oobretlen = ops->ooblen;
1758 1789
1759 return 0; 1790 return 0;
1760} 1791}
@@ -1774,7 +1805,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
1774 ops->retlen = 0; 1805 ops->retlen = 0;
1775 1806
1776 /* Do not allow writes past end of device */ 1807 /* Do not allow writes past end of device */
1777 if ((to + ops->len) > mtd->size) { 1808 if (ops->datbuf && (to + ops->len) > mtd->size) {
1778 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " 1809 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1779 "Attempt read beyond end of device\n"); 1810 "Attempt read beyond end of device\n");
1780 return -EINVAL; 1811 return -EINVAL;
@@ -2188,8 +2219,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2188 /* Newer devices have all the information in additional id bytes */ 2219 /* Newer devices have all the information in additional id bytes */
2189 if (!type->pagesize) { 2220 if (!type->pagesize) {
2190 int extid; 2221 int extid;
2191 /* The 3rd id byte contains non relevant data ATM */ 2222 /* The 3rd id byte holds MLC / multichip data */
2192 extid = chip->read_byte(mtd); 2223 chip->cellinfo = chip->read_byte(mtd);
2193 /* The 4th id byte is the important one */ 2224 /* The 4th id byte is the important one */
2194 extid = chip->read_byte(mtd); 2225 extid = chip->read_byte(mtd);
2195 /* Calc pagesize */ 2226 /* Calc pagesize */
@@ -2349,8 +2380,8 @@ int nand_scan_tail(struct mtd_info *mtd)
2349 if (!chip->buffers) 2380 if (!chip->buffers)
2350 return -ENOMEM; 2381 return -ENOMEM;
2351 2382
2352 /* Preset the internal oob write buffer */ 2383 /* Set the internal oob buffer location, just after the page data */
2353 memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize); 2384 chip->oob_poi = chip->buffers->databuf + mtd->writesize;
2354 2385
2355 /* 2386 /*
2356 * If no default placement scheme is given, select an appropriate one 2387 * If no default placement scheme is given, select an appropriate one
@@ -2469,6 +2500,24 @@ int nand_scan_tail(struct mtd_info *mtd)
2469 } 2500 }
2470 chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; 2501 chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
2471 2502
2503 /*
2504 * Allow subpage writes up to ecc.steps. Not possible for MLC
2505 * FLASH.
2506 */
2507 if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
2508 !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
2509 switch(chip->ecc.steps) {
2510 case 2:
2511 mtd->subpage_sft = 1;
2512 break;
2513 case 4:
2514 case 8:
2515 mtd->subpage_sft = 2;
2516 break;
2517 }
2518 }
2519 chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
2520
2472 /* Initialize state */ 2521 /* Initialize state */
2473 chip->state = FL_READY; 2522 chip->state = FL_READY;
2474 2523