diff --git a/drivers/mtd/nand/raw/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c
index 85d8013b1a6b..c097a2b8b94d 100644
--- a/drivers/mtd/nand/raw/sunxi_nand_spl.c
+++ b/drivers/mtd/nand/raw/sunxi_nand_spl.c
@@ -8,10 +8,12 @@
 #include <asm/io.h>
 #include <common.h>
 #include <config.h>
+#include <cpu_func.h>
 #include <nand.h>
 #include <linux/bitops.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
+#include <linux/ctype.h>
 
 /* registers */
 #define NFC_CTL                    0x00000000
@@ -69,7 +71,6 @@
 #define NFC_SEND_CMD3              (1 << 28)
 #define NFC_SEND_CMD4              (1 << 29)
 #define NFC_RAW_CMD                (0 << 30)
-#define NFC_ECC_CMD                (1 << 30)
 #define NFC_PAGE_CMD               (2 << 30)
 
 #define NFC_ST_CMD_INT_FLAG        (1 << 1)
@@ -84,6 +85,22 @@
 #define NFC_CMD_RNDOUT             0x05
 #define NFC_CMD_READSTART          0x30
 
+#define SUNXI_DMA_CFG_REG0              0x300
+#define SUNXI_DMA_SRC_START_ADDR_REG0   0x304
+#define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308
+#define SUNXI_DMA_DDMA_BC_REG0          0x30C
+#define SUNXI_DMA_DDMA_PARA_REG0        0x318
+
+#define SUNXI_DMA_DDMA_CFG_REG_LOADING  (1 << 31)
+#define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25)
+#define SUNXI_DMA_DDMA_CFG_REG_DDMA_DST_DRQ_TYPE_DRAM (1 << 16)
+#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9)
+#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5)
+#define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0)
+
+#define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0)
+#define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8)
+
 struct nfc_config {
 	int page_size;
 	int ecc_strength;
@@ -256,74 +273,86 @@ static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116};
 static int nand_read_page(const struct nfc_config *conf, u32 offs,
 			  void *dest, int len)
 {
+	dma_addr_t dst = (dma_addr_t)dest;
 	int nsectors = len / conf->ecc_size;
 	u16 rand_seed = 0;
-	int oob_chunk_sz = ecc_bytes[conf->ecc_strength];
-	int page = offs / conf->page_size;
-	u32 ecc_st;
-	int i;
+	u32 val;
+	int page;
+
+	page = offs / conf->page_size;
 
 	if (offs % conf->page_size || len % conf->ecc_size ||
 	    len > conf->page_size || len < 0)
 		return -EINVAL;
 
+	/* clear ecc status */
+	writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
+
 	/* 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;
-
-		/* Retrieve the data from SRAM */
-		memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE,
-			      conf->ecc_size);
-
-		/* Stop the ECC engine */
-		writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN,
-		       SUNXI_NFC_BASE + NFC_ECC_CTL);
-
-		if (data_off + conf->ecc_size >= len)
-			break;
+	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);
 
-	return 0;
+	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;
+	}
+
+	invalidate_dcache_range(dst,
+				ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN));
+
+	val = readl(SUNXI_NFC_BASE + NFC_ECC_ST);
+
+	/* ECC error detected. */
+	if (val & 0xffff)
+		return -EIO;
+
+	/*
+	 * Return 1 if the page is empty.
+	 * We consider the page as empty if the first ECC block is marked
+	 * empty.
+	 */
+	return (val & 0x10000) ? 1 : 0;
 }
 
 static int nand_max_ecc_strength(struct nfc_config *conf)
