]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/mtd/nand/sunxi_nand_spl.c
sunxi_nand_spl: Properly config page-size in the nand ctl register
[karo-tx-uboot.git] / drivers / mtd / nand / sunxi_nand_spl.c
index 147d47638f68daeadd85ee0740bb32fe36aa88d3..872cedfd5e8237200167e91259b663a641a448b7 100644 (file)
@@ -42,6 +42,8 @@
 #define NFC_CTL_EN                 (1 << 0)
 #define NFC_CTL_RESET              (1 << 1)
 #define NFC_CTL_RAM_METHOD         (1 << 14)
+#define NFC_CTL_PAGE_SIZE_MASK     (0xf << 8)
+#define NFC_CTL_PAGE_SIZE(a)       ((fls(a) - 11) << 8)
 
 
 #define NFC_ECC_EN                 (1 << 0)
@@ -181,60 +183,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;
@@ -266,6 +234,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 */
@@ -311,6 +283,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)++;
 }
@@ -320,6 +296,9 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
        void *current_dest;
        uint32_t ecc_errors = 0;
 
+       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) {