]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/mtd/nand/sunxi_nand_spl.c
sunxi_nand_spl: Use kernel driver algorithm for determining ecc_mode / _off
[karo-tx-uboot.git] / drivers / mtd / nand / sunxi_nand_spl.c
index 9efe904cc7fdc3631fb7ebe57f7252cc01a6e036..61eb393446fb205e4ae031b37dadb937bfd85924 100644 (file)
@@ -5,9 +5,10 @@
  * SPDX-License-Identifier:     GPL-2.0+
  */
 
+#include <asm/arch/clock.h>
+#include <asm/io.h>
 #include <common.h>
 #include <config.h>
-#include <asm/io.h>
 #include <nand.h>
 
 /* registers */
@@ -180,60 +181,26 @@ static void nand_read_page(unsigned int real_addr, dma_addr_t dst,
                           int syndrome, uint32_t *ecc_errors)
 {
        uint32_t val;
-       int ecc_off = 0;
+       int i, ecc_off = 0;
        uint16_t ecc_mode = 0;
        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 };
 
-       switch (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH) {
-       case 16:
-               ecc_mode = 0;
-               ecc_off = 0x20;
-               break;
-       case 24:
-               ecc_mode = 1;
-               ecc_off = 0x2e;
-               break;
-       case 28:
-               ecc_mode = 2;
-               ecc_off = 0x32;
-               break;
-       case 32:
-               ecc_mode = 3;
-               ecc_off = 0x3c;
-               break;
-       case 40:
-               ecc_mode = 4;
-               ecc_off = 0x4a;
-               break;
-       case 48:
-               ecc_mode = 4;
-               ecc_off = 0x52;
-               break;
-       case 56:
-               ecc_mode = 4;
-               ecc_off = 0x60;
-               break;
-       case 60:
-               ecc_mode = 4;
-               ecc_off = 0x0;
-               break;
-       case 64:
-               ecc_mode = 4;
-               ecc_off = 0x0;
-               break;
-       default:
-               ecc_mode = 0;
-               ecc_off = 0;
+       for (i = 0; i < ARRAY_SIZE(strengths); i++) {
+               if (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH == strengths[i]) {
+                       ecc_mode = i;
+                       break;
+               }
        }
 
-       if (ecc_off == 0) {
-               printf("Unsupported ECC strength (%d)!\n",
-                      CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH);
-               return;
-       }
+       /* 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);
+       /* 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;
@@ -265,6 +232,10 @@ static void nand_read_page(unsigned int real_addr, dma_addr_t dst,
                writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA);
        }
 
+       flush_dcache_range(dst,
+                          ALIGN(dst + CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
+                                ARCH_DMA_MINALIGN));
+
        /* SUNXI_DMA */
        writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */
        /* read from REG_IO_DATA */
@@ -310,6 +281,10 @@ static void nand_read_page(unsigned int real_addr, dma_addr_t dst,
                return;
        }
 
+       invalidate_dcache_range(dst,
+                       ALIGN(dst + CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE,
+                             ARCH_DMA_MINALIGN));
+
        if (readl(SUNXI_NFC_BASE + NFC_ECC_ST))
                (*ecc_errors)++;
 }
@@ -330,4 +305,16 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
        return ecc_errors ? -1 : 0;
 }
 
-void nand_deselect(void) {}
+void nand_deselect(void)
+{
+       struct sunxi_ccm_reg *const ccm =
+               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+       clrbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0));
+#ifdef CONFIG_MACH_SUN9I
+       clrbits_le32(&ccm->ahb_gate1, (1 << AHB_GATE_OFFSET_DMA));
+#else
+       clrbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_DMA));
+#endif
+       clrbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1);
+}