diff options
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 133 |
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 | */ |
901 | static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, | 902 | static 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, | |||
1590 | static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | 1604 | static 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 | ||