[RFC PATCH 2/2] mtd: nand: refactor nand_write_subpage_hwecc to write only relevant subpage data
Pekon Gupta
pekon at ti.com
Mon Jun 30 03:34:01 PDT 2014
Current nand_write_subpage_hwecc() code extends the subpage data to page-sized
one by padding it with 0xff. And then whole chunk is written to NAND device
using normal PAGE_PROGRAM sequence as below.
<NAND_CMD_SEQIN(0x80)>
<row-addr>
<column-addr>
<data1>
<data2>
...
<dataN>
<OOB-data>
<NAND_CMD_PAGEPROG(0x10)>
However many NAND devices support NAND_CMD_RNDIN(0x85) 'Random Input' command
which allows changing the column-address during PAGE_PROGRAM operation and write
only relevant data to NAND device, thereby avoiding the need for padding. This
patch uses below sequence to optimizes data writes for devices supporting subpages.
<NAND_CMD_SEQIN(0x80)>
<row-addr>
<NAND_CMD_RNDIN(0x85)>
<column-addr = subpageX>
<data1>
<data2>
...
<dataN>
<NAND_CMD_RNDIN(0x85)>
<column-addr = subpageY>
<data1>
<data2>
...
<dataM>
...
<NAND_CMD_RNDIN(0x85)>
<column-addr = oob-offset>
<OOB-data>
<NAND_CMD_PAGEPROG(0x10)>
*Note*
nand_chip-ecc->size may be different from nand_chip->subpagesize. That means
a single subpage can be further divided into more than one ECC sectors, as per
capacity of ECC engine. nand_chip->ecc->size is an attribute of ECC engine and
not NAND device. However same is not take care for reads in nand_read_subpage()
Signed-off-by: Pekon Gupta <pekon at ti.com>
---
drivers/mtd/nand/nand_base.c | 37 ++++++++++++++++---------------------
1 file changed, 16 insertions(+), 21 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index fdbd8c6..41b844d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2110,40 +2110,35 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
uint32_t *eccpos = chip->ecc.layout->eccpos;
uint32_t start_step = offset / ecc->size;
uint32_t end_step = (offset + data_len - 1) / ecc->size;
- int oob_bytes = mtd->oobsize / ecc->steps;
int step, i;
- for (step = 0; step < ecc->steps; step++) {
+ buf += (start_step * ecc->size);
+ ecc_calc += (start_step * ecc->bytes);
+ eccpos += (start_step * ecc->bytes);
+ for (step = start_step; step < end_step; step++) {
/* configure controller for WRITE access */
chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- /* write data (untouched subpages already masked by 0xFF) */
+ /* write data */
+ chip->cmdfunc(mtd, NAND_CMD_RNDIN, (step * ecc->size), -1);
chip->write_buf(mtd, buf, ecc->size);
- /* mask ECC of un-touched subpages by padding 0xFF */
- if ((step < start_step) || (step > end_step))
- memset(ecc_calc, 0xff, ecc->bytes);
- else
- chip->ecc.calculate(mtd, buf, ecc_calc);
+ /* calculate ECC */
+ chip->ecc.calculate(mtd, buf, ecc_calc);
- /* mask OOB of un-touched subpages by padding 0xFF */
- /* if oob_required, preserve OOB metadata of written subpage */
- if (!oob_required || (step < start_step) || (step > end_step))
- memset(oob_buf, 0xff, oob_bytes);
+ /* copy calculated ECC to OOB buffer as per ecc-layout */
+ for (i = 0; i < ecc->bytes; i++)
+ oob_buf[eccpos[i]] = ecc_calc[i];
buf += ecc->size;
ecc_calc += ecc->bytes;
- oob_buf += oob_bytes;
+ eccpos += ecc->bytes;
}
- /* copy calculated ECC for whole page to chip->buffer->oob */
- /* this include masked-value(0xFF) for unwritten subpages */
- ecc_calc = chip->buffers->ecccalc;
- for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
- /* write OOB buffer to NAND device */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ /* write _complete_ OOB buffer to NAND device,
+ * unused OOB bytes are already padded with 0xFF */
+ chip->cmdfunc(mtd, NAND_CMD_RNDIN, mtd->writesize, -1);
+ chip->write_buf(mtd, oob_buf, mtd->oobsize);
return 0;
}
--
1.8.5.1.163.gd7aced9
More information about the linux-mtd
mailing list