aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorGupta, Pekon <pekon@ti.com>2013-03-15 08:25:53 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2013-04-05 08:22:59 -0400
commit837a6ba4f3b6d23026674e6af6b6849a4634fff9 (patch)
treec13590363e4e146627a0074b2c7efa60386c5a18 /drivers/mtd/nand
parent4ff6772b5bb17ef40e64abf2c0d5f6aefd104b06 (diff)
mtd: nand: subpage write support for hardware based ECC schemes
This patch adds support for subpage (partial-page) writes when using hardware based ECC schemes. Advantages: (1) reduces storage overhead when using file-systems like UBIFS, which store LEB header at page-size granularity. (2) allows independent subpage writes, thereby increasing NAND storage efficiency for non-page aligned data. + updated cafe_nand and lpc32xx_mlc NAND drivers for change in chip->write_page interface. Signed-off-by: Gupta, Pekon <pekon@ti.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/cafe_nand.c4
-rw-r--r--drivers/mtd/nand/lpc32xx_mlc.c4
-rw-r--r--drivers/mtd/nand/nand_base.c99
3 files changed, 90 insertions, 17 deletions
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index a01ccb970102..c34985a55101 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -530,8 +530,8 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
530} 530}
531 531
532static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, 532static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
533 const uint8_t *buf, int oob_required, int page, 533 uint32_t offset, int data_len, const uint8_t *buf,
534 int cached, int raw) 534 int oob_required, int page, int cached, int raw)
535{ 535{
536 int status; 536 int status;
537 537
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index 0ca22ae9135c..a94facb46e5c 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -540,8 +540,8 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
540} 540}
541 541
542static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip, 542static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip,
543 const uint8_t *buf, int oob_required, int page, 543 uint32_t offset, int data_len, const uint8_t *buf,
544 int cached, int raw) 544 int oob_required, int page, int cached, int raw)
545{ 545{
546 int res; 546 int res;
547 547
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ae9790b659b1..dfcd0a565c5b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1110,7 +1110,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
1110} 1110}
1111 1111
1112/** 1112/**
1113 * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function 1113 * nand_read_subpage - [REPLACEABLE] ECC based sub-page read function
1114 * @mtd: mtd info structure 1114 * @mtd: mtd info structure
1115 * @chip: nand chip info structure 1115 * @chip: nand chip info structure
1116 * @data_offs: offset of requested data within the page 1116 * @data_offs: offset of requested data within the page
@@ -1978,6 +1978,67 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
1978 return 0; 1978 return 0;
1979} 1979}
1980 1980
1981
1982/**
1983 * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
1984 * @mtd: mtd info structure
1985 * @chip: nand chip info structure
1986 * @column: column address of subpage within the page
1987 * @data_len: data length
1988 * @oob_required: must write chip->oob_poi to OOB
1989 */
1990static int nand_write_subpage_hwecc(struct mtd_info *mtd,
1991 struct nand_chip *chip, uint32_t offset,
1992 uint32_t data_len, const uint8_t *data_buf,
1993 int oob_required)
1994{
1995 uint8_t *oob_buf = chip->oob_poi;
1996 uint8_t *ecc_calc = chip->buffers->ecccalc;
1997 int ecc_size = chip->ecc.size;
1998 int ecc_bytes = chip->ecc.bytes;
1999 int ecc_steps = chip->ecc.steps;
2000 uint32_t *eccpos = chip->ecc.layout->eccpos;
2001 uint32_t start_step = offset / ecc_size;
2002 uint32_t end_step = (offset + data_len - 1) / ecc_size;
2003 int oob_bytes = mtd->oobsize / ecc_steps;
2004 int step, i;
2005
2006 for (step = 0; step < ecc_steps; step++) {
2007 /* configure controller for WRITE access */
2008 chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
2009
2010 /* write data (untouched subpages already masked by 0xFF) */
2011 chip->write_buf(mtd, data_buf, ecc_size);
2012
2013 /* mask ECC of un-touched subpages by padding 0xFF */
2014 if ((step < start_step) || (step > end_step))
2015 memset(ecc_calc, 0xff, ecc_bytes);
2016 else
2017 chip->ecc.calculate(mtd, data_buf, ecc_calc);
2018
2019 /* mask OOB of un-touched subpages by padding 0xFF */
2020 /* if oob_required, preserve OOB metadata of written subpage */
2021 if (!oob_required || (step < start_step) || (step > end_step))
2022 memset(oob_buf, 0xff, oob_bytes);
2023
2024 data_buf += ecc_size;
2025 ecc_calc += ecc_bytes;
2026 oob_buf += oob_bytes;
2027 }
2028
2029 /* copy calculated ECC for whole page to chip->buffer->oob */
2030 /* this include masked-value(0xFF) for unwritten subpages */
2031 ecc_calc = chip->buffers->ecccalc;
2032 for (i = 0; i < chip->ecc.total; i++)
2033 chip->oob_poi[eccpos[i]] = ecc_calc[i];
2034
2035 /* write OOB buffer to NAND device */
2036 chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
2037
2038 return 0;
2039}
2040
2041
1981/** 2042/**
1982 * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write 2043 * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write
1983 * @mtd: mtd info structure 2044 * @mtd: mtd info structure
@@ -2030,6 +2091,8 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
2030 * nand_write_page - [REPLACEABLE] write one page 2091 * nand_write_page - [REPLACEABLE] write one page
2031 * @mtd: MTD device structure 2092 * @mtd: MTD device structure
2032 * @chip: NAND chip descriptor 2093 * @chip: NAND chip descriptor
2094 * @offset: address offset within the page
2095 * @data_len: length of actual data to be written
2033 * @buf: the data to write 2096 * @buf: the data to write
2034 * @oob_required: must write chip->oob_poi to OOB 2097 * @oob_required: must write chip->oob_poi to OOB
2035 * @page: page number to write 2098 * @page: page number to write
@@ -2037,15 +2100,25 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,
2037 * @raw: use _raw version of write_page 2100 * @raw: use _raw version of write_page
2038 */ 2101 */
2039static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, 2102static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
2040 const uint8_t *buf, int oob_required, int page, 2103 uint32_t offset, int data_len, const uint8_t *buf,
2041 int cached, int raw) 2104 int oob_required, int page, int cached, int raw)
2042{ 2105{
2043 int status; 2106 int status, subpage;
2107
2108 if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
2109 chip->ecc.write_subpage)
2110 subpage = offset || (data_len < mtd->writesize);
2111 else
2112 subpage = 0;
2044 2113
2045 chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); 2114 chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
2046 2115
2047 if (unlikely(raw)) 2116 if (unlikely(raw))
2048 status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required); 2117 status = chip->ecc.write_page_raw(mtd, chip, buf,
2118 oob_required);
2119 else if (subpage)
2120 status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
2121 buf, oob_required);
2049 else 2122 else
2050 status = chip->ecc.write_page(mtd, chip, buf, oob_required); 2123 status = chip->ecc.write_page(mtd, chip, buf, oob_required);
2051 2124
@@ -2159,7 +2232,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
2159 2232
2160 uint8_t *oob = ops->oobbuf; 2233 uint8_t *oob = ops->oobbuf;
2161 uint8_t *buf = ops->datbuf; 2234 uint8_t *buf = ops->datbuf;
2162 int ret, subpage; 2235 int ret;
2163 int oob_required = oob ? 1 : 0; 2236 int oob_required = oob ? 1 : 0;
2164 2237
2165 ops->retlen = 0; 2238 ops->retlen = 0;
@@ -2174,10 +2247,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
2174 } 2247 }
2175 2248
2176 column = to & (mtd->writesize - 1); 2249 column = to & (mtd->writesize - 1);
2177 subpage = column || (writelen & (mtd->writesize - 1));
2178
2179 if (subpage && oob)
2180 return -EINVAL;
2181 2250
2182 chipnr = (int)(to >> chip->chip_shift); 2251 chipnr = (int)(to >> chip->chip_shift);
2183 chip->select_chip(mtd, chipnr); 2252 chip->select_chip(mtd, chipnr);
@@ -2226,9 +2295,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
2226 /* We still need to erase leftover OOB data */ 2295 /* We still need to erase leftover OOB data */
2227 memset(chip->oob_poi, 0xff, mtd->oobsize); 2296 memset(chip->oob_poi, 0xff, mtd->oobsize);
2228 } 2297 }
2229 2298 ret = chip->write_page(mtd, chip, column, bytes, wbuf,
2230 ret = chip->write_page(mtd, chip, wbuf, oob_required, page, 2299 oob_required, page, cached,
2231 cached, (ops->mode == MTD_OPS_RAW)); 2300 (ops->mode == MTD_OPS_RAW));
2232 if (ret) 2301 if (ret)
2233 break; 2302 break;
2234 2303
@@ -3414,6 +3483,10 @@ int nand_scan_tail(struct mtd_info *mtd)
3414 chip->ecc.read_oob = nand_read_oob_std; 3483 chip->ecc.read_oob = nand_read_oob_std;
3415 if (!chip->ecc.write_oob) 3484 if (!chip->ecc.write_oob)
3416 chip->ecc.write_oob = nand_write_oob_std; 3485 chip->ecc.write_oob = nand_write_oob_std;
3486 if (!chip->ecc.read_subpage)
3487 chip->ecc.read_subpage = nand_read_subpage;
3488 if (!chip->ecc.write_subpage)
3489 chip->ecc.write_subpage = nand_write_subpage_hwecc;
3417 3490
3418 case NAND_ECC_HW_SYNDROME: 3491 case NAND_ECC_HW_SYNDROME:
3419 if ((!chip->ecc.calculate || !chip->ecc.correct || 3492 if ((!chip->ecc.calculate || !chip->ecc.correct ||