mtd: nand: pxa3xx: simplify ECC hardware parameters
authorChris Packham <judge.packham@gmail.com>
Thu, 25 Aug 2022 04:59:49 +0000 (16:59 +1200)
committerStefan Roese <sr@denx.de>
Thu, 6 Oct 2022 08:15:34 +0000 (10:15 +0200)
Replace the if/else chain in pxa_ecc_init() with a lookup table. This
makes the code more concise and hopefully easier to follow. Remove the
unused ecc_layout tables and replace it with a single dummy one (the
pxa3xx driver has never used this but the mtd subsystem expects it to be
provided).

Tested on an Allied Telesis x530 switch with Micron MT29F2G08ABAEAWP
NAND Flash.

Signed-off-by: Chris Packham <judge.packham@gmail.com>
drivers/mtd/nand/raw/pxa3xx_nand.c

index 9c29e8a..fcd1b9c 100644 (file)
@@ -330,89 +330,44 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 };
 #endif
 
-static struct nand_ecclayout ecc_layout_2KB_bch4bit = {
-       .eccbytes = 32,
-       .eccpos = {
-               32, 33, 34, 35, 36, 37, 38, 39,
-               40, 41, 42, 43, 44, 45, 46, 47,
-               48, 49, 50, 51, 52, 53, 54, 55,
-               56, 57, 58, 59, 60, 61, 62, 63},
-       .oobfree = { {2, 30} }
-};
-
-static struct nand_ecclayout ecc_layout_2KB_bch8bit = {
-       .eccbytes = 64,
-       .eccpos = {
-               32, 33, 34, 35, 36, 37, 38, 39,
-               40, 41, 42, 43, 44, 45, 46, 47,
-               48, 49, 50, 51, 52, 53, 54, 55,
-               56, 57, 58, 59, 60, 61, 62, 63,
-               64, 65, 66, 67, 68, 69, 70, 71,
-               72, 73, 74, 75, 76, 77, 78, 79,
-               80, 81, 82, 83, 84, 85, 86, 87,
-               88, 89, 90, 91, 92, 93, 94, 95},
-       .oobfree = { {1, 4}, {6, 26} }
-};
-
-static struct nand_ecclayout ecc_layout_4KB_bch4bit = {
-       .eccbytes = 64,
-       .eccpos = {
-               32,  33,  34,  35,  36,  37,  38,  39,
-               40,  41,  42,  43,  44,  45,  46,  47,
-               48,  49,  50,  51,  52,  53,  54,  55,
-               56,  57,  58,  59,  60,  61,  62,  63,
-               96,  97,  98,  99,  100, 101, 102, 103,
-               104, 105, 106, 107, 108, 109, 110, 111,
-               112, 113, 114, 115, 116, 117, 118, 119,
-               120, 121, 122, 123, 124, 125, 126, 127},
-       /* Bootrom looks in bytes 0 & 5 for bad blocks */
-       .oobfree = { {6, 26}, { 64, 32} }
+struct marvell_hw_ecc_layout {
+       int                     page_size;
+       int                     strength;
+       unsigned int            ecc_size;
+       unsigned int            nfullchunks;
+       unsigned int            chunk_size;
+       unsigned int            spare_size;
+       unsigned int            last_chunk_size;
+       unsigned int            last_spare_size;
 };
 
-static struct nand_ecclayout ecc_layout_8KB_bch4bit = {
-       .eccbytes = 128,
-       .eccpos = {
-               32,  33,  34,  35,  36,  37,  38,  39,
-               40,  41,  42,  43,  44,  45,  46,  47,
-               48,  49,  50,  51,  52,  53,  54,  55,
-               56,  57,  58,  59,  60,  61,  62,  63,
-
-               96,  97,  98,  99,  100, 101, 102, 103,
-               104, 105, 106, 107, 108, 109, 110, 111,
-               112, 113, 114, 115, 116, 117, 118, 119,
-               120, 121, 122, 123, 124, 125, 126, 127,
-
-               160, 161, 162, 163, 164, 165, 166, 167,
-               168, 169, 170, 171, 172, 173, 174, 175,
-               176, 177, 178, 179, 180, 181, 182, 183,
-               184, 185, 186, 187, 188, 189, 190, 191,
-
-               224, 225, 226, 227, 228, 229, 230, 231,
-               232, 233, 234, 235, 236, 237, 238, 239,
-               240, 241, 242, 243, 244, 245, 246, 247,
-               248, 249, 250, 251, 252, 253, 254, 255},
-
-       /* Bootrom looks in bytes 0 & 5 for bad blocks */
-       .oobfree = { {1, 4}, {6, 26}, { 64, 32}, {128, 32}, {192, 32} }
+static const struct marvell_hw_ecc_layout nfc_layouts[] = {
+       /* page_size strength ecc_size nfullchunks chunk_size spare_size last_chunk last_spare */
+       {     512,      1,       8,         1,         512,        8,         0,         0      },
+       {    2048,      1,      24,         1,        2048,       40,         0,         0      },
+
+       {    2048,      4,      32,         1,        2048,       32,         0,         0      },
+       {    2048,      8,      32,         1,        1024,        0,      1024,        32      },
+       {    2048,     12,      32,         2,         704,        0,       640,         0      },
+       {    2048,     16,      32,         4,         512,        0,         0,        32      },
+       {    4096,      4,      32,         2,        2048,       32,         0,         0      },
+       {    4096,      8,      32,         4,        1024,        0,         0,        64      },
+       {    4096,     12,      32,         5,         704,        0,       576,        32      },
+       {    4096,     16,      32,         8,         512,        0,         0,        32      },
+
+       {    8192,      4,      32,         4,        2048,       32,         0,         0      },
+       {    8192,      8,      32,         8,        1024,        0,         0,       160      },
+       {    8192,     12,      32,        11,         704,        0,       448,        64      },
+       {    8192,     16,      32,        16,         512,        0,         0,        32      },
+       { },
 };
 
-static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
-       .eccbytes = 128,
-       .eccpos = {
-               32,  33,  34,  35,  36,  37,  38,  39,
-               40,  41,  42,  43,  44,  45,  46,  47,
-               48,  49,  50,  51,  52,  53,  54,  55,
-               56,  57,  58,  59,  60,  61,  62,  63},
+static struct nand_ecclayout ecc_layout_empty = {
+       .eccbytes = 0,
+       .eccpos = { },
        .oobfree = { }
 };
 
-static struct nand_ecclayout ecc_layout_8KB_bch8bit = {
-       .eccbytes = 256,
-       .eccpos = {},
-       /* HW ECC handles all ECC data and all spare area is free for OOB */
-       .oobfree = {{0, 160} }
-};
-
 #define NDTR0_tCH(c)   (min((c), 7) << 19)
 #define NDTR0_tCS(c)   (min((c), 7) << 16)
 #define NDTR0_tWH(c)   (min((c), 7) << 11)
@@ -1549,113 +1504,47 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
                        struct nand_ecc_ctrl *ecc,
                        int strength, int ecc_stepsize, int page_size)
 {
-       if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
-               info->nfullchunks = 1;
-               info->ntotalchunks = 1;
-               info->chunk_size = 2048;
-               info->spare_size = 40;
-               info->ecc_size = 24;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = 512;
-               ecc->strength = 1;
-
-       } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
-               info->nfullchunks = 1;
-               info->ntotalchunks = 1;
-               info->chunk_size = 512;
-               info->spare_size = 8;
-               info->ecc_size = 8;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = 512;
-               ecc->strength = 1;
+       int i = 0;
+
+       /*  if ecc strength is 1 ecc algo is Hamming else bch */
+       info->ecc_bch = (strength == 1) ? 0 : 1;
+
+       ecc->mode = NAND_ECC_HW;
+
+       /* ecc->layout is not in use for pxa driver (but shouldn't be NULL)*/
+       if (info->ecc_bch == 1)
+               ecc->layout = &ecc_layout_empty;
+
+       /* for bch actual ecc strength is 16 per chunk */
+       ecc->strength = (info->ecc_bch == 1) ? 16 : 1;
+
+       while (nfc_layouts[i].strength) {
+               if (strength == nfc_layouts[i].strength && page_size == nfc_layouts[i].page_size) {
+                       info->nfullchunks = nfc_layouts[i].nfullchunks;
+                       info->chunk_size = nfc_layouts[i].chunk_size;
+                       info->spare_size = nfc_layouts[i].spare_size;
+                       info->last_chunk_size = nfc_layouts[i].last_chunk_size;
+                       info->last_spare_size = nfc_layouts[i].last_spare_size;
+                       info->ntotalchunks = (info->last_spare_size || info->last_chunk_size) ?
+                                       info->nfullchunks + 1 : info->nfullchunks;
+                       info->ecc_size = nfc_layouts[i].ecc_size;
+                       break;
+               }
+               ++i;
+       }
 
-       /*
-        * Required ECC: 4-bit correction per 512 bytes
-        * Select: 16-bit correction per 2048 bytes
-        */
-       } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
-               info->ecc_bch = 1;
-               info->nfullchunks = 1;
-               info->ntotalchunks = 1;
-               info->chunk_size = 2048;
-               info->spare_size = 32;
-               info->ecc_size = 32;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = info->chunk_size;
-               ecc->layout = &ecc_layout_2KB_bch4bit;
-               ecc->strength = 16;
-
-       } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
-               info->ecc_bch = 1;
-               info->nfullchunks = 2;
-               info->ntotalchunks = 2;
-               info->chunk_size = 2048;
-               info->spare_size = 32;
-               info->ecc_size = 32;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = info->chunk_size;
-               ecc->layout = &ecc_layout_4KB_bch4bit;
-               ecc->strength = 16;
-
-       } else if (strength == 4 && ecc_stepsize == 512 && page_size == 8192) {
-               info->ecc_bch = 1;
-               info->nfullchunks = 4;
-               info->ntotalchunks = 4;
-               info->chunk_size = 2048;
-               info->spare_size = 32;
-               info->ecc_size = 32;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = info->chunk_size;
-               ecc->layout = &ecc_layout_8KB_bch4bit;
-               ecc->strength = 16;
+       /* for bch the ecc is calculated per chunk size and for Hamming it is 512 */
+       ecc->size = (info->ecc_bch) ? info->chunk_size : 512;
 
-       /*
-        * Required ECC: 8-bit correction per 512 bytes
-        * Select: 16-bit correction per 1024 bytes
+       /* nand_scan_tail func perform  validity tests for ECC strength, and it
+        * assumes that all chunks are with same size. in our case when ecc is 12
+        * the chunk size is 704 but the last chunk is with different size so
+        * we cheat it nand_scan_tail validity tests by set info->ecc_size value to 512
         */
-       } else if (strength == 8 && ecc_stepsize == 512 && page_size == 2048) {
-               info->ecc_bch = 1;
-               info->nfullchunks = 1;
-               info->ntotalchunks = 2;
-               info->chunk_size = 1024;
-               info->spare_size = 0;
-               info->last_chunk_size = 1024;
-               info->last_spare_size = 32;
-               info->ecc_size = 32;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = info->chunk_size;
-               ecc->layout = &ecc_layout_2KB_bch8bit;
-               ecc->strength = 16;
-
-       } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
-               info->ecc_bch = 1;
-               info->nfullchunks = 4;
-               info->ntotalchunks = 5;
-               info->chunk_size = 1024;
-               info->spare_size = 0;
-               info->last_chunk_size = 0;
-               info->last_spare_size = 64;
-               info->ecc_size = 32;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = info->chunk_size;
-               ecc->layout = &ecc_layout_4KB_bch8bit;
-               ecc->strength = 16;
-
-       } else if (strength == 8 && ecc_stepsize == 512 && page_size == 8192) {
-               info->ecc_bch = 1;
-               info->nfullchunks = 8;
-               info->ntotalchunks = 9;
-               info->chunk_size = 1024;
-               info->spare_size = 0;
-               info->last_chunk_size = 0;
-               info->last_spare_size = 160;
-               info->ecc_size = 32;
-               ecc->mode = NAND_ECC_HW;
-               ecc->size = info->chunk_size;
-               ecc->layout = &ecc_layout_8KB_bch8bit;
-               ecc->strength = 16;
+       if (strength == 12)
+               ecc->size = 512;
 
-       } else {
+       if (ecc_stepsize != 512 || !(nfc_layouts[i].strength)) {
                dev_err(info->controller.active->mtd.dev,
                        "ECC strength %d at page size %d is not supported\n",
                        strength, page_size);