[PATCH] [PATCH] sunxi-nand: Undo removal of DMA that breaks NAND SPL

Chris Morgan macroalpha82 at gmail.com
Wed Mar 30 22:45:43 CEST 2022


From: Chris Morgan <macromorgan at hotmail.com>

For the sun5i based NAND, removal of the DMA specific code from the SPL
driver caused it to no longer function.

These patches revert the changes made here, specifically patches 13/20
and 14/20:
https://lore.kernel.org/u-boot/20210624120540.7oyhdmerjndsylbq@gilmour/

These patches only apply for sun5i based boards. Tested on my NTC CHIP
(an R8/A13 based device) and it is able to boot U-Boot properly with
these patches.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 board/sunxi/board.c                   |   3 +
 drivers/mtd/nand/raw/sunxi_nand_spl.c | 105 ++++++++++++++++++++++++++
 2 files changed, 108 insertions(+)

diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 28f702bc29..289f568415 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -393,6 +393,9 @@ static void nand_clock_setup(void)
 #if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I || \
     defined CONFIG_MACH_SUN9I || defined CONFIG_MACH_SUN50I
 	setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0));
+#endif
+#if defined(CONFIG_MACH_SUN5I) && defined(CONFIG_NAND_SUNXI)
+	setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA));
 #endif
 	setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1);
 }
diff --git a/drivers/mtd/nand/raw/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c
index a29a76c58d..1b2c995803 100644
--- a/drivers/mtd/nand/raw/sunxi_nand_spl.c
+++ b/drivers/mtd/nand/raw/sunxi_nand_spl.c
@@ -12,6 +12,7 @@
 #include <linux/bitops.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
+#include <cpu_func.h>
 #include <linux/mtd/rawnand.h>
 
 /* registers */
@@ -85,6 +86,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;
@@ -254,6 +271,93 @@ static int nand_change_column(u16 column)
 
 static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116};
 
+#if defined(CONFIG_MACH_SUN5I)
+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;
+	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];
+
+	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;
+	}
+
+	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;
+}
+#else
 static int nand_read_page(const struct nfc_config *conf, u32 offs,
 			  void *dest, int len)
 {
@@ -326,6 +430,7 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs,
 
 	return 0;
 }
+#endif
 
 static int nand_max_ecc_strength(struct nfc_config *conf)
 {
-- 
2.30.2



More information about the U-Boot mailing list