@@ -1079,6 +1079,16 @@ static void sunxi_nfc_hw_ecc_update_stats(struct nand_chip *nand,
}
}
+static int sunxi_nfc_read_column(struct nand_chip *nand, int page,
+ unsigned int column, void *buf, unsigned int len)
+{
+ /* Small-page NAND needs a new READ0/READ1/READOOB and the page address. */
+ if (nand_to_mtd(nand)->writesize <= 512)
+ return nand_read_page_op(nand, page, column, buf, len);
+
+ return nand_change_read_column_op(nand, column, buf, len, false);
+}
+
/*
* Return 1 for an erased chunk or 0 for an uncorrectable chunk, with ECC
* statistics updated in either case. Negative values report transport errors.
@@ -1087,7 +1097,7 @@ static int sunxi_nfc_hw_ecc_read_error(struct nand_chip *nand,
u8 *data, int data_off,
u8 *oob, int oob_off,
unsigned int user_data_sz,
- unsigned int *max_bitflips)
+ unsigned int *max_bitflips, int page)
{
struct nand_ecc_ctrl *ecc = &nand->ecc;
unsigned int oob_len = ecc->bytes + user_data_sz;
@@ -1095,13 +1105,12 @@ static int sunxi_nfc_hw_ecc_read_error(struct nand_chip *nand,
/* Check the physical representation for bitflips in erased pages. */
if (nand->options & NAND_NEED_SCRAMBLING) {
- ret = nand_change_read_column_op(nand, data_off, data,
- ecc->size, false);
+ ret = sunxi_nfc_read_column(nand, page, data_off, data, ecc->size);
if (ret)
return ret;
}
- ret = nand_change_read_column_op(nand, oob_off, oob, oob_len, false);
+ ret = sunxi_nfc_read_column(nand, page, oob_off, oob, oob_len);
if (ret)
return ret;
@@ -1169,7 +1178,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
const int nfc_step = 0;
if (*cur_off != data_off) {
- ret = nand_change_read_column_op(nand, data_off, NULL, 0, false);
+ ret = sunxi_nfc_read_column(nand, page, data_off, NULL, 0);
if (ret)
return ret;
}
@@ -1179,7 +1188,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
return ret;
if (data_off + ecc->size != oob_off) {
- ret = nand_change_read_column_op(nand, oob_off, NULL, 0, false);
+ ret = sunxi_nfc_read_column(nand, page, oob_off, NULL, 0);
if (ret)
return ret;
}
@@ -1217,13 +1226,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
return sunxi_nfc_hw_ecc_read_error(nand, data, data_off,
oob, oob_off, user_data_sz,
- max_bitflips);
+ max_bitflips, page);
} else {
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
if (oob_required) {
- ret = nand_change_read_column_op(nand, oob_off, NULL, 0,
- false);
+ ret = sunxi_nfc_read_column(nand, page, oob_off, NULL, 0);
if (ret)
return ret;
ret = sunxi_nfc_randomizer_read_buf(nand, oob,
@@ -1285,8 +1293,8 @@ static int sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand,
return 0;
if (!cur_off || *cur_off != (offset + mtd->writesize)) {
- ret = nand_change_read_column_op(nand, mtd->writesize + offset,
- NULL, 0, false);
+ ret = sunxi_nfc_read_column(nand, page, mtd->writesize + offset,
+ NULL, 0);
if (ret)
return ret;
}
@@ -1386,9 +1394,8 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
if (oob_required && !erased) {
/* TODO: use DMA to retrieve OOB */
- ret = nand_change_read_column_op(nand, mtd->writesize + oob_off,
- oob, ecc->bytes + user_data_sz,
- false);
+ ret = sunxi_nfc_read_column(nand, page, mtd->writesize + oob_off,
+ oob, ecc->bytes + user_data_sz);
if (ret)
goto err_stats;
@@ -1416,7 +1423,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
ret = sunxi_nfc_hw_ecc_read_error(nand, data, data_off, oob,
mtd->writesize + oob_off,
user_data_sz,
- &max_bitflips);
+ &max_bitflips, page);
if (ret < 0)
goto err_stats;
if (ret)
@@ -2305,7 +2312,8 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
ecc->write_oob = sunxi_nfc_hw_ecc_write_oob;
mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
- if (nfc->dmac || nfc->use_mdma) {
+ /* The DMA page sequencer uses large-page random-column commands. */
+ if (mtd->writesize > 512 && (nfc->dmac || nfc->use_mdma)) {
ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;