@@ -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;
}
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@ti.com> --- drivers/mtd/nand/nand_base.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-)