diff options
author | Hans de Goede | 2015-08-15 20:51:53 +0200 |
---|---|---|
committer | Hans de Goede | 2015-08-31 08:43:42 +0200 |
commit | f5916d1856cb043f79304a99103a2f910298eecc (patch) | |
tree | 48274075f44e9d525d77c72ba2c6405d1db8e168 /drivers/mtd | |
parent | 0a247554c2dec96e693c1b02761cf0b5d5189fc0 (diff) |
sunxi_nand_spl: Parametrize lowlevel read functions
Parametrize the lowlevel nand_read_page function, instead of directly
using the CONFIG_foo settings for page-size, etc. there and add a few
wrappers / helper functions for calling it.
This is a preparation patch for adding auto-detecting of the nand
parameters like the BROM does.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ian Campbell <ijc@hellion.org.uk>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/sunxi_nand_spl.c | 86 |
1 files changed, 48 insertions, 38 deletions
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index 872cedfd5e8..3206a502027 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -179,8 +179,8 @@ void nand_init(void) } } -static void nand_read_page(unsigned int real_addr, dma_addr_t dst, - int syndrome, uint32_t *ecc_errors) +static int nand_read_page(int page_size, int ecc_strength, int ecc_page_size, + int addr_cycles, uint32_t real_addr, dma_addr_t dst, int syndrome) { uint32_t val; int i, ecc_off = 0; @@ -188,28 +188,26 @@ static void nand_read_page(unsigned int real_addr, dma_addr_t dst, uint16_t rand_seed; uint32_t page; uint16_t column; - uint32_t oob_offset; static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; for (i = 0; i < ARRAY_SIZE(strengths); i++) { - if (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH == strengths[i]) { + if (ecc_strength == strengths[i]) { ecc_mode = i; break; } } /* HW ECC always request ECC bytes for 1024 bytes blocks */ - ecc_off = DIV_ROUND_UP(CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH * fls(8 * 1024), 8); + ecc_off = DIV_ROUND_UP(ecc_strength * fls(8 * 1024), 8); /* HW ECC always work with even numbers of ECC bytes */ ecc_off += (ecc_off & 1); ecc_off += 4; /* prepad */ - page = real_addr / CONFIG_NAND_SUNXI_SPL_PAGE_SIZE; - column = real_addr % CONFIG_NAND_SUNXI_SPL_PAGE_SIZE; + page = real_addr / page_size; + column = real_addr % page_size; if (syndrome) - column += (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) - * ecc_off; + column += (column / ecc_page_size) * ecc_off; /* clear ecc status */ writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); @@ -227,16 +225,11 @@ static void nand_read_page(unsigned int real_addr, dma_addr_t dst, val = readl(SUNXI_NFC_BASE + NFC_CTL); writel(val | NFC_CTL_RAM_METHOD, SUNXI_NFC_BASE + NFC_CTL); - if (!syndrome) { - oob_offset = CONFIG_NAND_SUNXI_SPL_PAGE_SIZE - + (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) - * ecc_off; - writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA); - } + if (!syndrome) + writel(page_size + (column / ecc_page_size) * ecc_off, + SUNXI_NFC_BASE + NFC_SPARE_AREA); - flush_dcache_range(dst, - ALIGN(dst + CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, - ARCH_DMA_MINALIGN)); + flush_dcache_range(dst, ALIGN(dst + ecc_page_size, ARCH_DMA_MINALIGN)); /* SUNXI_DMA */ writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */ @@ -248,7 +241,7 @@ static void nand_read_page(unsigned int real_addr, dma_addr_t dst, 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(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, + writel(ecc_page_size, SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */ writel(SUNXI_DMA_DDMA_CFG_REG_LOADING | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 @@ -267,47 +260,64 @@ static void nand_read_page(unsigned int real_addr, dma_addr_t dst, SUNXI_NFC_BASE + NFC_ADDR_LOW); writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS | - NFC_PAGE_CMD | NFC_WAIT_FLAG | (4 << NFC_ADDR_NUM_OFFSET) | + NFC_PAGE_CMD | NFC_WAIT_FLAG | + ((addr_cycles - 1) << NFC_ADDR_NUM_OFFSET) | NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0), SUNXI_NFC_BASE + NFC_CMD); if (!check_value(SUNXI_NFC_BASE + NFC_ST, (1 << 2), MAX_RETRIES)) { printf("Error while initializing dma interrupt\n"); - return; + return -1; } if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0, SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) { printf("Error while waiting for dma transfer to finish\n"); - return; + return -1; } invalidate_dcache_range(dst, - ALIGN(dst + CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, - ARCH_DMA_MINALIGN)); + ALIGN(dst + ecc_page_size, ARCH_DMA_MINALIGN)); if (readl(SUNXI_NFC_BASE + NFC_ECC_ST)) - (*ecc_errors)++; + return -1; + + return 0; } -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +static int nand_read_ecc(int page_size, int ecc_strength, int ecc_page_size, + int addr_cycles, uint32_t offs, uint32_t size, void *dest, int syndrome) { - void *current_dest; - uint32_t ecc_errors = 0; + void *end = dest + size; clrsetbits_le32(SUNXI_NFC_BASE + NFC_CTL, NFC_CTL_PAGE_SIZE_MASK, - NFC_CTL_PAGE_SIZE(CONFIG_NAND_SUNXI_SPL_PAGE_SIZE)); - - for (current_dest = dest; - current_dest < (dest + size); - current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) { - nand_read_page(offs, (dma_addr_t)current_dest, - offs < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END, - &ecc_errors); - offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE; + NFC_CTL_PAGE_SIZE(page_size)); + + for ( ;dest < end; dest += ecc_page_size, offs += ecc_page_size) { + if (nand_read_page(page_size, ecc_strength, ecc_page_size, + addr_cycles, offs, (dma_addr_t)dest, + syndrome)) + return -1; } - return ecc_errors ? -1 : 0; + + return 0; +} + +static int nand_read_buffer(uint32_t offs, unsigned int size, void *dest, + int syndrome) +{ + return nand_read_ecc(CONFIG_NAND_SUNXI_SPL_PAGE_SIZE, + CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH, + CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, + 5, offs, size, dest, syndrome); +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + int syndrome = offs < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END; + + return nand_read_buffer(offs, size, dest, syndrome); } void nand_deselect(void) |