Because using DMA implementation is not generic and was not developped to work on SoCs like A33, migrate the SPL to use PIO.
Signed-off-by: Miquel Raynal <miquel.ray...@free-electrons.com> --- board/sunxi/board.c | 4 +- drivers/mtd/nand/sunxi_nand_spl.c | 167 +++++++++++++++++--------------------- 2 files changed, 79 insertions(+), 92 deletions(-) diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 70e01437c4..512e2c17a6 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -266,11 +266,13 @@ static void nand_clock_setup(void) struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); + setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_NAND0)); + setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_NAND0)); #ifdef CONFIG_MACH_SUN9I setbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA)); #else setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA)); + setbits_le32(&ccm->ahb_reset0_cfg, (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/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 2488d5cb51..5de6825994 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -10,6 +10,7 @@ #include <common.h> #include <config.h> #include <nand.h> +#include <linux/ctype.h> /* registers */ #define NFC_CTL 0x00000000 @@ -45,32 +46,22 @@ #define NFC_CTL_PAGE_SIZE_MASK (0xf << 8) #define NFC_CTL_PAGE_SIZE(a) ((fls(a) - 11) << 8) - #define NFC_ECC_EN (1 << 0) -#define NFC_ECC_PIPELINE (1 << 3) #define NFC_ECC_EXCEPTION (1 << 4) #define NFC_ECC_BLOCK_SIZE (1 << 5) #define NFC_ECC_RANDOM_EN (1 << 9) -#define NFC_ECC_RANDOM_DIRECTION (1 << 10) - #define NFC_ADDR_NUM_OFFSET 16 -#define NFC_ACCESS_DIR (1 << 20) #define NFC_SEND_ADDR (1 << 19) #define NFC_DATA_TRANS (1 << 21) #define NFC_SEND_CMD1 (1 << 22) #define NFC_WAIT_FLAG (1 << 23) #define NFC_SEND_CMD2 (1 << 24) -#define NFC_SEQ (1 << 25) -#define NFC_DATA_SWAP_METHOD (1 << 26) -#define NFC_ROW_AUTO_INC (1 << 27) -#define NFC_SEND_CMD3 (1 << 28) -#define NFC_SEND_CMD4 (1 << 29) #define NFC_RAW_CMD (0 << 30) -#define NFC_PAGE_CMD (2 << 30) +#define NFC_ECC_CMD (1 << 30) #define NFC_ST_CMD_INT_FLAG (1 << 1) -#define NFC_ST_DMA_INT_FLAG (1 << 2) +#define NFC_ST_CMD_FIFO_STAT (1 << 3) #define NFC_READ_CMD_OFFSET 0 #define NFC_RANDOM_READ_CMD0_OFFSET 8 @@ -80,22 +71,6 @@ #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,7 +229,23 @@ static int nand_reset_column(void) SUNXI_NFC_BASE + NFC_CMD); return nand_wait_int(); +} +static int nand_change_column(u16 column) +{ + nand_wait_cmd_fifo_empty(); + + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) | + (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) | + (NFC_CMD_RNDOUTSTART << NFC_READ_CMD_OFFSET), + SUNXI_NFC_BASE + NFC_RCMD_SET); + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + writel(column, SUNXI_NFC_BASE + NFC_ADDR_LOW); + writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_RAW_CMD | + (1 << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADDR | NFC_CMD_RNDOUT, + SUNXI_NFC_BASE + NFC_CMD); + + return nand_wait_int(); } static const int ecc_bytes[] = {32, 46, 54, 60, 74, 88, 102, 110, 116}; @@ -262,86 +253,80 @@ 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; - u32 val; - int page; - - page = offs / conf->page_size; + int oob_chunk_sz = ecc_bytes[conf->ecc_strength]; + int page = offs / conf->page_size; + u32 ecc_st; + int i; 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); + /* 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); + nand_wait_cmd_fifo_empty(); + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT); + writel(NFC_DATA_TRANS, SUNXI_NFC_BASE + NFC_CMD); + nand_wait_int(); - 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); + /* + * Let the ECC engine consume the ECC bytes and possibly correct + * the data. + */ + nand_change_column(oob_off); + nand_wait_cmd_fifo_empty(); + writel(NFC_ST_CMD_INT_FLAG, SUNXI_NFC_BASE + NFC_ST); + writel(NFC_DATA_TRANS | NFC_ECC_CMD, SUNXI_NFC_BASE + NFC_CMD); + nand_wait_int(); - 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; - } + /* Get the ECC status */ + ecc_st = readl(SUNXI_NFC_BASE + NFC_ECC_ST); - invalidate_dcache_range(dst, - ALIGN(dst + conf->ecc_size, ARCH_DMA_MINALIGN)); + /* Retrieve the data from SRAM */ + memcpy_fromio(data, SUNXI_NFC_BASE + NFC_RAM0_BASE, + conf->ecc_size); - val = readl(SUNXI_NFC_BASE + NFC_ECC_ST); + /* Stop ECC engine */ + writel(readl(SUNXI_NFC_BASE + NFC_ECC_CTL) & ~NFC_ECC_EN, + SUNXI_NFC_BASE + NFC_ECC_CTL); - /* ECC error detected. */ - if (val & 0xffff) - return -EIO; + /* ECC error detected. */ + if (ecc_st & 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; + /* + * Return 1 if the page is empty. We consider the page as empty + * if the first ECC block is marked empty. + */ + if (ecc_st & 0x10000) + return 1; + + if (data_off + conf->ecc_size >= len) + break; + } + + return 0; } static int nand_max_ecc_strength(struct nfc_config *conf) -- 2.11.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot