diff options
-rw-r--r-- | drivers/mtd/mtdconcat.c | 1 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 53 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 2 | ||||
-rw-r--r-- | include/linux/mtd/nand.h | 9 |
5 files changed, 57 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, | |||
1603 | static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | 1603 | static 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 | ||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index e34bbc98d4fe..18acb6d0033b 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -200,6 +200,8 @@ struct mtd_info { | |||
200 | 200 | ||
201 | /* ECC status information */ | 201 | /* ECC status information */ |
202 | struct mtd_ecc_stats ecc_stats; | 202 | struct mtd_ecc_stats ecc_stats; |
203 | /* Subpage shift (NAND) */ | ||
204 | int subpage_sft; | ||
203 | 205 | ||
204 | void *priv; | 206 | void *priv; |
205 | 207 | ||
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 6fc3e07497e0..1aeedf27a1ff 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
@@ -166,6 +166,9 @@ typedef enum { | |||
166 | * for all large page devices, as they do not support | 166 | * for all large page devices, as they do not support |
167 | * autoincrement.*/ | 167 | * autoincrement.*/ |
168 | #define NAND_NO_READRDY 0x00000100 | 168 | #define NAND_NO_READRDY 0x00000100 |
169 | /* Chip does not allow subpage writes */ | ||
170 | #define NAND_NO_SUBPAGE_WRITE 0x00000200 | ||
171 | |||
169 | 172 | ||
170 | /* Options valid for Samsung large page devices */ | 173 | /* Options valid for Samsung large page devices */ |
171 | #define NAND_SAMSUNG_LP_OPTIONS \ | 174 | #define NAND_SAMSUNG_LP_OPTIONS \ |
@@ -193,6 +196,9 @@ typedef enum { | |||
193 | /* Nand scan has allocated controller struct */ | 196 | /* Nand scan has allocated controller struct */ |
194 | #define NAND_CONTROLLER_ALLOC 0x80000000 | 197 | #define NAND_CONTROLLER_ALLOC 0x80000000 |
195 | 198 | ||
199 | /* Cell info constants */ | ||
200 | #define NAND_CI_CHIPNR_MSK 0x03 | ||
201 | #define NAND_CI_CELLTYPE_MSK 0x0C | ||
196 | 202 | ||
197 | /* | 203 | /* |
198 | * nand_state_t - chip states | 204 | * nand_state_t - chip states |
@@ -341,6 +347,7 @@ struct nand_buffers { | |||
341 | * @chipsize: [INTERN] the size of one chip for multichip arrays | 347 | * @chipsize: [INTERN] the size of one chip for multichip arrays |
342 | * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 | 348 | * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 |
343 | * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf | 349 | * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf |
350 | * @subpagesize: [INTERN] holds the subpagesize | ||
344 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme | 351 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme |
345 | * @bbt: [INTERN] bad block table pointer | 352 | * @bbt: [INTERN] bad block table pointer |
346 | * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup | 353 | * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup |
@@ -388,6 +395,8 @@ struct nand_chip { | |||
388 | unsigned long chipsize; | 395 | unsigned long chipsize; |
389 | int pagemask; | 396 | int pagemask; |
390 | int pagebuf; | 397 | int pagebuf; |
398 | int subpagesize; | ||
399 | uint8_t cellinfo; | ||
391 | int badblockpos; | 400 | int badblockpos; |
392 | 401 | ||
393 | nand_state_t state; | 402 | nand_state_t state; |