aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2006-09-28 09:38:36 -0400
committerArtem Bityutskiy <dedekind@infradead.org>2006-11-29 10:03:52 -0500
commit29072b96078ffde36f03d51e6b5d0cff1ba8c7df (patch)
tree1353a27ae7e594044c521e28abf558e3796f98c9 /drivers
parentf6a7ecb18dabd88bd9f28e7bece564cabe8ffe82 (diff)
[MTD] NAND: add subpage write support
Many SLC NANDs support up to 4 writes at one NAND page. Add support of this feature. Signed-off-by: Artem Bityutskiy <dedekind@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/mtdconcat.c1
-rw-r--r--drivers/mtd/mtdpart.c1
-rw-r--r--drivers/mtd/nand/nand_base.c53
3 files changed, 46 insertions, 9 deletions
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index ec51483b1c51..06902683bc2a 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -772,6 +772,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
772 concat->mtd.ecc_stats.badblocks += 772 concat->mtd.ecc_stats.badblocks +=
773 subdev[i]->ecc_stats.badblocks; 773 subdev[i]->ecc_stats.badblocks;
774 if (concat->mtd.writesize != subdev[i]->writesize || 774 if (concat->mtd.writesize != subdev[i]->writesize ||
775 concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
775 concat->mtd.oobsize != subdev[i]->oobsize || 776 concat->mtd.oobsize != subdev[i]->oobsize ||
776 concat->mtd.ecctype != subdev[i]->ecctype || 777 concat->mtd.ecctype != subdev[i]->ecctype ||
777 concat->mtd.eccsize != subdev[i]->eccsize || 778 concat->mtd.eccsize != subdev[i]->eccsize ||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 89692f898ef4..bafd2fba87bd 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -340,6 +340,7 @@ int add_mtd_partitions(struct mtd_info *master,
340 slave->mtd.oobsize = master->oobsize; 340 slave->mtd.oobsize = master->oobsize;
341 slave->mtd.ecctype = master->ecctype; 341 slave->mtd.ecctype = master->ecctype;
342 slave->mtd.eccsize = master->eccsize; 342 slave->mtd.eccsize = master->eccsize;
343 slave->mtd.subpage_sft = master->subpage_sft;
343 344
344 slave->mtd.name = parts[i].name; 345 slave->mtd.name = parts[i].name;
345 slave->mtd.bank_size = master->bank_size; 346 slave->mtd.bank_size = master->bank_size;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 5dcb2e066ce7..eed3271b99cc 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1590,7 +1590,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
1590 return NULL; 1590 return NULL;
1591} 1591}
1592 1592
1593#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 1593#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
1594 1594
1595/** 1595/**
1596 * nand_do_write_ops - [Internal] NAND write with ECC 1596 * nand_do_write_ops - [Internal] NAND write with ECC
@@ -1603,15 +1603,16 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
1603static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, 1603static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1604 struct mtd_oob_ops *ops) 1604 struct mtd_oob_ops *ops)
1605{ 1605{
1606 int chipnr, realpage, page, blockmask; 1606 int chipnr, realpage, page, blockmask, column;
1607 struct nand_chip *chip = mtd->priv; 1607 struct nand_chip *chip = mtd->priv;
1608 uint32_t writelen = ops->len; 1608 uint32_t writelen = ops->len;
1609 uint8_t *oob = ops->oobbuf; 1609 uint8_t *oob = ops->oobbuf;
1610 uint8_t *buf = ops->datbuf; 1610 uint8_t *buf = ops->datbuf;
1611 int bytes = mtd->writesize; 1611 int ret, subpage;
1612 int ret;
1613 1612
1614 ops->retlen = 0; 1613 ops->retlen = 0;
1614 if (!writelen)
1615 return 0;
1615 1616
1616 /* reject writes, which are not page aligned */ 1617 /* reject writes, which are not page aligned */
1617 if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { 1618 if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
@@ -1620,8 +1621,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1620 return -EINVAL; 1621 return -EINVAL;
1621 } 1622 }
1622 1623
1623 if (!writelen) 1624 column = to & (mtd->writesize - 1);
1624 return 0; 1625 subpage = column || (writelen & (mtd->writesize - 1));
1626
1627 if (subpage && oob)
1628 return -EINVAL;
1625 1629
1626 chipnr = (int)(to >> chip->chip_shift); 1630 chipnr = (int)(to >> chip->chip_shift);
1627 chip->select_chip(mtd, chipnr); 1631 chip->select_chip(mtd, chipnr);
@@ -1644,12 +1648,24 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1644 memset(chip->oob_poi, 0xff, mtd->oobsize); 1648 memset(chip->oob_poi, 0xff, mtd->oobsize);
1645 1649
1646 while(1) { 1650 while(1) {
1651 int bytes = mtd->writesize;
1647 int cached = writelen > bytes && page != blockmask; 1652 int cached = writelen > bytes && page != blockmask;
1653 uint8_t *wbuf = buf;
1654
1655 /* Partial page write ? */
1656 if (unlikely(column || writelen < (mtd->writesize - 1))) {
1657 cached = 0;
1658 bytes = min_t(int, bytes - column, (int) writelen);
1659 chip->pagebuf = -1;
1660 memset(chip->buffers->databuf, 0xff, mtd->writesize);
1661 memcpy(&chip->buffers->databuf[column], buf, bytes);
1662 wbuf = chip->buffers->databuf;
1663 }
1648 1664
1649 if (unlikely(oob)) 1665 if (unlikely(oob))
1650 oob = nand_fill_oob(chip, oob, ops); 1666 oob = nand_fill_oob(chip, oob, ops);
1651 1667
1652 ret = chip->write_page(mtd, chip, buf, page, cached, 1668 ret = chip->write_page(mtd, chip, wbuf, page, cached,
1653 (ops->mode == MTD_OOB_RAW)); 1669 (ops->mode == MTD_OOB_RAW));
1654 if (ret) 1670 if (ret)
1655 break; 1671 break;
@@ -1658,6 +1674,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1658 if (!writelen) 1674 if (!writelen)
1659 break; 1675 break;
1660 1676
1677 column = 0;
1661 buf += bytes; 1678 buf += bytes;
1662 realpage++; 1679 realpage++;
1663 1680
@@ -2201,8 +2218,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2201 /* Newer devices have all the information in additional id bytes */ 2218 /* Newer devices have all the information in additional id bytes */
2202 if (!type->pagesize) { 2219 if (!type->pagesize) {
2203 int extid; 2220 int extid;
2204 /* The 3rd id byte contains non relevant data ATM */ 2221 /* The 3rd id byte holds MLC / multichip data */
2205 extid = chip->read_byte(mtd); 2222 chip->cellinfo = chip->read_byte(mtd);
2206 /* The 4th id byte is the important one */ 2223 /* The 4th id byte is the important one */
2207 extid = chip->read_byte(mtd); 2224 extid = chip->read_byte(mtd);
2208 /* Calc pagesize */ 2225 /* Calc pagesize */
@@ -2482,6 +2499,24 @@ int nand_scan_tail(struct mtd_info *mtd)
2482 } 2499 }
2483 chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; 2500 chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
2484 2501
2502 /*
2503 * Allow subpage writes up to ecc.steps. Not possible for MLC
2504 * FLASH.
2505 */
2506 if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
2507 !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
2508 switch(chip->ecc.steps) {
2509 case 2:
2510 mtd->subpage_sft = 1;
2511 break;
2512 case 4:
2513 case 8:
2514 mtd->subpage_sft = 2;
2515 break;
2516 }
2517 }
2518 chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
2519
2485 /* Initialize state */ 2520 /* Initialize state */
2486 chip->state = FL_READY; 2521 chip->state = FL_READY;
2487 2522