- /* clear ecc status */
- writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
-
- /* Choose correct seed */
- rand_seed = random_seed[page % conf->nseeds];
-
- writel((rand_seed << 16) | (conf->ecc_strength << 12) |
- (conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
- (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) |
- NFC_ECC_EN | NFC_ECC_PIPELINE | NFC_ECC_EXCEPTION,
- SUNXI_NFC_BASE + NFC_ECC_CTL);
-
- flush_dcache_range(dst, ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
-
- /* SUNXI_DMA */
- writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
- /* read from REG_IO_DATA */
- writel(SUNXI_NFC_BASE + NFC_IO_DATA,
- SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0);
- /* read to RAM */
- writel(dst, SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0);
- writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC |
- SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE,
- SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0);
- writel(len, SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0);
- writel(SUNXI_DMA_DDMA_CFG_REG_LOADING |
- SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 |
- SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM |
- SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 |
- SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO |
- SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC,
- SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0);
-
- writel(nsectors, SUNXI_NFC_BASE + NFC_SECTOR_NUM);
- writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
- writel(NFC_DATA_TRANS | NFC_PAGE_CMD | NFC_DATA_SWAP_METHOD,
- SUNXI_NFC_BASE + NFC_CMD);
-
- if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_ST_DMA_INT_FLAG,
- DEFAULT_TIMEOUT_US)) {
- printf("Error while initializing dma interrupt\n");
- return -EIO;
- }
- writel(NFC_ST_DMA_INT_FLAG, SUNXI_NFC_BASE + NFC_ST);
-
- if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0,
- SUNXI_DMA_DDMA_CFG_REG_LOADING,
- DEFAULT_TIMEOUT_US)) {
- printf("Error while waiting for dma transfer to finish\n");
- return -EIO;
- }
+ /* Choose correct seed if randomized */
+ if (conf->randomize)
+ rand_seed = random_seed[page % conf->nseeds];
+
+ /* Retrieve data from SRAM (PIO) */
+ for (i = 0; i < nsectors; i++) {
+ int data_off = i * conf->ecc_size;
+ int oob_off = conf->page_size + (i * oob_chunk_sz);
+ u8 *data = dest + data_off;
+
+ /* Clear ECC status and restart ECC engine */
+ writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
+ writel((rand_seed << 16) | (conf->ecc_strength << 12) |
+ (conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
+ (conf->ecc_size == 512 ? NFC_ECC_BLOCK_SIZE : 0) |
+ NFC_ECC_EN | NFC_ECC_EXCEPTION,
+ SUNXI_NFC_BASE + NFC_ECC_CTL);
+
+ /* Move the data in SRAM */
+ nand_change_column(data_off);
+ writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT);
+ nand_exec_cmd(NFC_DATA_TRANS);
+
+ /*
+ * Let the ECC engine consume the ECC bytes and possibly correct
+ * the data.
+ */
+ nand_change_column(oob_off);
+ nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_CMD);
+
+ /* Get the ECC status */
+ ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST);
+
+ /* ECC error detected. */
+ if (ecc_st & 0xffff)
+ return -EIO;
+
+ /*
+ * Return 1 if the first chunk is empty (needed for
+ * configuration detection).
+ */
+ if (!i && (ecc_st & 0x10000))
+ return 1;