aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/mtdconcat.c1
-rw-r--r--drivers/mtd/mtdpart.c1
-rw-r--r--drivers/mtd/nand/nand_base.c53
-rw-r--r--include/linux/mtd/mtd.h2
-rw-r--r--include/linux/mtd/nand.h9
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,
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
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;