chip->ecc.hwctl() is used for preparing the H/W controller before read/write
NAND accesses (like assigning data-buf, enabling ECC scheme configs, etc.)

Though all ECC schemes in OMAP NAND driver use GPMC controller for generating
ECC syndrome (for both Read/Write accesses). But but in current code
HAM1_ECC and BCHx_ECC schemes implement individual function to achieve this.
This patch
(1) removes omap_hwecc_init() and omap_hwecc_init_bch()
as chip->ecc.hwctl will re-initializeGPMC before every read/write call.
omap_hwecc_init_bch() -> omap_enable_ecc_bch()

(2) merges the GPMC configuration code for all ECC schemes into
single omap_enable_hwecc(), thus adding scalability for future ECC schemes.
omap_enable_hwecc() + omap_enable_ecc_bch() -> omap_enable_hwecc()

Signed-off-by: Pekon Gupta <pe...@ti.com>
---
 drivers/mtd/nand/omap_gpmc.c | 207 ++++++++++++-------------------------------
 1 file changed, 58 insertions(+), 149 deletions(-)

diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index d9a4a5e..b8f0e86 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -17,6 +17,9 @@
 #include <nand.h>
 #include <asm/arch/elm.h>
 
+
+#define SECTOR_BYTES           512
+
 static uint8_t cs;
 static __maybe_unused struct nand_ecclayout hw_nand_oob =
        GPMC_NAND_HW_ECC_LAYOUT;
@@ -60,21 +63,6 @@ int omap_spl_dev_ready(struct mtd_info *mtd)
 }
 #endif
 
-/*
- * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in
- *                   GPMC controller
- * @mtd:        MTD device structure
- *
- */
-static void __maybe_unused omap_hwecc_init(struct nand_chip *chip)
-{
-       /*
-        * Init ECC Control Register
-        * Clear all ECC | Enable Reg1
-        */
-       writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
-       writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_cfg->ecc_size_config);
-}
 
 /*
  * gen_true_ecc - This function will generate true ECC value, which
@@ -192,38 +180,6 @@ static int __maybe_unused omap_calculate_ecc(struct 
mtd_info *mtd,
 }
 
 /*
- * omap_enable_ecc - This function enables the hardware ecc functionality
- * @mtd:        MTD device structure
- * @mode:       Read/Write mode
- */
-static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t 
mode)
-{
-       struct nand_chip *chip = mtd->priv;
-       uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
-
-       switch (mode) {
-       case NAND_ECC_READ:
-       case NAND_ECC_WRITE:
-               /* Clear the ecc result registers, select ecc reg as 1 */
-               writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
-
-               /*
-                * Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
-                * tell all regs to generate size0 sized regs
-                * we just have a single ECC engine for all CS
-                */
-               writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL,
-                       &gpmc_cfg->ecc_size_config);
-               val = (dev_width << 7) | (cs << 1) | (0x1);
-               writel(val, &gpmc_cfg->ecc_config);
-               break;
-       default:
-               printf("Error: Unrecognized Mode[%d]!\n", mode);
-               break;
-       }
-}
-
-/*
  * Generic BCH interface
  */
 struct nand_bch_priv {
@@ -262,105 +218,63 @@ static __maybe_unused struct nand_bch_priv bch_priv = {
 };
 
 /*
- * omap_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in
- *                             GPMC controller
+ * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
  * @mtd:       MTD device structure
  * @mode:      Read/Write mode
  */
 __maybe_unused
-static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
+static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
 {
-       uint32_t val;
-       uint32_t dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
-#if defined(CONFIG_NAND_OMAP_ECC_BCH8_CODE_HW)
-       uint32_t unused_length = 0;
-#endif
-       uint32_t wr_mode = BCH_WRAPMODE_6;
-       struct nand_bch_priv *bch = chip->priv;
-
-       /* Clear the ecc result registers, select ecc reg as 1 */
-       writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
-
-#if defined(CONFIG_NAND_OMAP_ECC_BCH8_CODE_HW)
-       wr_mode = BCH_WRAPMODE_1;
-
-       switch (bch->nibbles) {
-       case ECC_BCH4_NIBBLES:
-               unused_length = 3;
-               break;
-       case ECC_BCH8_NIBBLES:
-               unused_length = 2;
-               break;
-       case ECC_BCH16_NIBBLES:
-               unused_length = 0;
-               break;
-       }
-
-       /*
-        * This is ecc_size_config for ELM mode.
-        * Here we are using different settings for read and write access and
-        * also depending on BCH strength.
-        */
-       switch (mode) {
-       case NAND_ECC_WRITE:
-               /* write access only setup eccsize1 config */
-               val = ((unused_length + bch->nibbles) << 22);
-               break;
-
-       case NAND_ECC_READ:
-       default:
-               /*
-                * by default eccsize0 selected for ecc1resultsize
-                * eccsize0 config.
-                */
-               val  = (bch->nibbles << 12);
-               /* eccsize1 config */
-               val |= (unused_length << 22);
-               break;
-       }
+       struct nand_chip *chip = mtd->priv;
+       unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+       unsigned int ecc_algo = 0;
+       unsigned int bch_type = 0;
+       unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00;
+       u32 ecc_size_config_val = 0;
+       u32 ecc_config_val = 0;
+
+       if (chip->ecc.strength == 1) {
+               ecc_algo = 0x0;
+               bch_type = 0x0;
+               bch_wrapmode = 0x00;
+               eccsize0 = 0xFF;
+               eccsize1 = 0xFF;
+#if defined(CONFIG_NAND_OMAP_ECC_BCH8_CODE_HW) || \
+       defined(CONFIG_NAND_OMAP_ECC_BCH8_CODE_HW_DETECTION_SW)
+       } else if (chip->ecc.strength == 8) {
+               ecc_algo = 0x1;
+               bch_type = 0x1;
+               if (mode == NAND_ECC_WRITE) {
+                       bch_wrapmode = 0x01;
+                       eccsize0 = 0;  /* extra bits in nibbles per sector */
+                       eccsize1 = 28; /* OOB bits in nibbles per sector */
+               } else {
+                       bch_wrapmode = 0x01;
+                       eccsize0 = 26; /* ECC bits in nibbles per sector */
+                       eccsize1 = 2;  /* non-ECC bits in nibbles per sector */
+               }
 #else
-       /*
-        * This ecc_size_config setting is for BCH sw library.
-        *
-        * Note: we only support BCH8 currently with BCH sw library!
-        * Should be really easy to adobt to BCH4, however some omap3 have
-        * flaws with BCH4.
-        *
-        * Here we are using wrapping mode 6 both for reading and writing, with:
-        *  size0 = 0  (no additional protected byte in spare area)
-        *  size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
-        */
-       val = (32 << 22) | (0 << 12);
+       } else {
+               printf("*Error: invalid driver configuration\n");
 #endif
-       /* ecc size configuration */
-       writel(val, &gpmc_cfg->ecc_size_config);
-
-       /*
-        * Configure the ecc engine in gpmc
-        * We assume 512 Byte sector pages for access to NAND.
-        */
-       val  = (1 << 16);               /* enable BCH mode */
-       val |= (bch->type << 12);       /* setup BCH type */
-       val |= (wr_mode << 8);          /* setup wrapping mode */
-       val |= (dev_width << 7);        /* setup device width (16 or 8 bit) */
-       val |= (cs << 1);               /* setup chip select to work on */
-       debug("set ECC_CONFIG=0x%08x\n", val);
-       writel(val, &gpmc_cfg->ecc_config);
-}
-
-/*
- * omap_enable_ecc_bch - This function enables the bch h/w ecc functionality
- * @mtd:       MTD device structure
- * @mode:      Read/Write mode
- */
-__maybe_unused
-static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode)
-{
-       struct nand_chip *chip = mtd->priv;
-
-       omap_hwecc_init_bch(chip, mode);
-       /* enable ecc */
-       writel((readl(&gpmc_cfg->ecc_config) | 0x1), &gpmc_cfg->ecc_config);
+       }
+       /* Clear ecc and enable bits */
+       writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
+       /* Configure ecc size for BCH */
+       ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12);
+       writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config);
+
+       /* Configure device details for BCH engine */
+       ecc_config_val = ((ecc_algo << 16)      | /* HAM1 | BCHx */
+                       (bch_type << 12)        | /* BCH4/BCH8/BCH16 */
+                       (bch_wrapmode << 8)     | /* wrap mode */
+                       (dev_width << 7)        | /* bus width */
+                       (0x0 << 4)              | /* number of sectors */
+                       (cs <<  1)              | /* ECC CS */
+                       (0x0));                 /* disable ECC */
+       writel(ecc_config_val, &gpmc_cfg->ecc_config);
+       /* enable ECC engine */
+       writel(ecc_config_val | 0x1, &gpmc_cfg->ecc_config);
 }
 
 /*
@@ -801,7 +715,7 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t 
eccstrength)
                        nand->ecc.hwctl = omap_enable_hwecc;
                        nand->ecc.correct = omap_correct_data;
                        nand->ecc.calculate = omap_calculate_ecc;
-                       omap_hwecc_init(nand);
+                       omap_enable_hwecc(mtd, NAND_ECC_READ);
                        printf("1-bit hamming HW ECC selected\n");
                } else if (eccstrength == 8) {
 #if defined(CONFIG_NAND_OMAP_ECC_BCH8_CODE_HW)
@@ -810,13 +724,12 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t 
eccstrength)
                        nand->ecc.size          = 512;
                        nand->ecc.bytes         = 14;
                        nand->ecc.read_page     = omap_read_page_bch;
-                       nand->ecc.hwctl         = omap_enable_ecc_bch;
+                       nand->ecc.hwctl         = omap_enable_hwecc;
                        nand->ecc.correct       = omap_correct_data_bch;
                        nand->ecc.calculate     = omap_calculate_ecc_bch;
                        /* ELM is used for ECC error detection */
                        elm_init();
                        nand->priv = &bch_priv;
-                       omap_hwecc_init_bch(nand, NAND_ECC_READ);
                        printf("using OMAP_ECC_BCH8_CODE_HW\n");
 #elif defined(CONFIG_NAND_OMAP_ECC_BCH8_CODE_HW_DETECTION_SW) && \
        defined(CONFIG_BCH)
@@ -824,7 +737,7 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t 
eccstrength)
                        nand->ecc.layout        = &hw_bch8_nand_oob;
                        nand->ecc.size          = 512;
                        nand->ecc.bytes         = 13;
-                       nand->ecc.hwctl         = omap_enable_ecc_bch;
+                       nand->ecc.hwctl         = omap_enable_hwecc;
                        nand->ecc.correct       = omap_correct_data_bch;
                        nand->ecc.calculate     = omap_calculate_ecc_bch;
                        /* BCH SW library is used for error detection */
@@ -834,7 +747,6 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t 
eccstrength)
                                return -ENODEV;
                        }
                        nand->priv = &bch_priv;
-                       omap_hwecc_init_bch(nand, NAND_ECC_READ);
                        printf("using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
 #else
                        printf("selected ECC not supported or not enabled\n");
@@ -919,14 +831,13 @@ int board_nand_init(struct nand_chip *nand)
        nand->ecc.size          = CONFIG_SYS_NAND_ECCSIZE;
        nand->ecc.bytes         = CONFIG_SYS_NAND_ECCBYTES;
        nand->ecc.strength      = 8;
-       nand->ecc.hwctl         = omap_enable_ecc_bch;
+       nand->ecc.hwctl         = omap_enable_hwecc;
        nand->ecc.correct       = omap_correct_data_bch;
        nand->ecc.calculate     = omap_calculate_ecc_bch;
        nand->ecc.read_page     = omap_read_page_bch;
        /* ELM is used for ECC error detection */
        elm_init();
        nand->priv = &bch_priv;
-       omap_hwecc_init_bch(nand, NAND_ECC_READ);
 #elif defined(CONFIG_NAND_OMAP_ECC_BCH8_CODE_HW_DETECTION_SW) && \
        defined(CONFIG_BCH)
        printf("NAND: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
@@ -935,7 +846,7 @@ int board_nand_init(struct nand_chip *nand)
        nand->ecc.size          = CONFIG_SYS_NAND_ECCSIZE;
        nand->ecc.bytes         = CONFIG_SYS_NAND_ECCBYTES;
        nand->ecc.strength      = 8;
-       nand->ecc.hwctl         = omap_enable_ecc_bch;
+       nand->ecc.hwctl         = omap_enable_hwecc;
        nand->ecc.correct       = omap_correct_data_bch;
        nand->ecc.calculate     = omap_calculate_ecc_bch;
        /* BCH SW library is used for error detection */
@@ -945,7 +856,6 @@ int board_nand_init(struct nand_chip *nand)
                return -ENODEV;
        }
        nand->priv = &bch_priv;
-       omap_hwecc_init_bch(nand, NAND_ECC_READ);
 #elif !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC)
        printf("NAND: using OMAP_ECC_HAM1_CODE_SW\n");
        nand->ecc.mode = NAND_ECC_SOFT;
@@ -959,7 +869,6 @@ int board_nand_init(struct nand_chip *nand)
        nand->ecc.correct = omap_correct_data;
        nand->ecc.calculate = omap_calculate_ecc;
        nand->ecc.strength = 1;
-       omap_hwecc_init(nand);
 #endif
 
 #ifdef CONFIG_SPL_BUILD
-- 
1.8.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to