
This reverts commit 6ddbb1e936c78cdef1e7395039fa7020c5c75326. --- drivers/mtd/nand/raw/sunxi_nand_spl.c | 141 ++++++++++++++++---------- 1 file changed, 85 insertions(+), 56 deletions(-)
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)