]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
mtd: nand: omap_gpmc: Fix NAND in SPL for AM335x
authorRoger Quadros <rogerq@kernel.org>
Mon, 11 Dec 2023 11:45:59 +0000 (13:45 +0200)
committerDario Binacchi <dario.binacchi@amarulasolutions.com>
Mon, 15 Jan 2024 07:58:24 +0000 (08:58 +0100)
AM335x uses a special driver "am335x_spl_bch.c" as SPL
NAND loader. This driver expects 1 sector at a time ECC
and doesn't work well with multi-sector ECC that was implemented in
commit 04fcd2587321 ("mtd: rawnand: omap_gpmc: Fix BCH6/16 HW based correction")

Additionally, the omap_elm driver does not support multi sector ECC and will
need more work and tests to get multi sector working correctly on all
platforms.

Switch back to 1 sector at a time read/ECC.

Fixes: 04fcd2587321 ("mtd: rawnand: omap_gpmc: Fix BCH6/16 HW based correction")
Signed-off-by: Roger Quadros <rogerq@kernel.org>
Tested-by: Enrico Leto <enrico.leto@siemens.com>
Tested-by: Heiko Schocher <hs@denx.de>
Link: https://lore.kernel.org/all/20231211114600.4414-2-rogerq@kernel.org/
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
drivers/mtd/nand/raw/omap_gpmc.c

index 0e25bd5dc28f71b93398a05d440c31d7e1af4eaf..414133105f0be080924683d0552b8740646a4369 100644 (file)
@@ -294,7 +294,7 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd,
                break;
        case OMAP_ECC_BCH8_CODE_HW:
                bch_type = 1;
-               nsectors = chip->ecc.steps;
+               nsectors = 1;
                if (mode == NAND_ECC_READ) {
                        wr_mode   = BCH_WRAPMODE_1;
                        ecc_size0 = BCH8R_ECC_SIZE0;
@@ -307,7 +307,7 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd,
                break;
        case OMAP_ECC_BCH16_CODE_HW:
                bch_type = 0x2;
-               nsectors = chip->ecc.steps;
+               nsectors = 1;
                if (mode == NAND_ECC_READ) {
                        wr_mode   = 0x01;
                        ecc_size0 = 52; /* ECC bits in nibbles per sector */
@@ -346,17 +346,16 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd,
 }
 
 /**
- * _omap_calculate_ecc_bch - Generate BCH ECC bytes for one sector
+ * omap_calculate_ecc_bch - Generate BCH ECC bytes for one sector
  * @mtd:        MTD device structure
  * @dat:        The pointer to data on which ecc is computed
  * @ecc_code:   The ecc_code buffer
- * @sector:     The sector number (for a multi sector page)
  *
  * Support calculating of BCH4/8/16 ECC vectors for one sector
  * within a page. Sector number is in @sector.
  */
-static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
-                                  u8 *ecc_code, int sector)
+static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
+                                                u8 *ecc_code)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct omap_nand_info *info = nand_get_controller_data(chip);
@@ -369,7 +368,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
        case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
 #endif
        case OMAP_ECC_BCH8_CODE_HW:
-               ptr = &gpmc_cfg->bch_result_0_3[sector].bch_result_x[3];
+               ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
                val = readl(ptr);
                ecc_code[i++] = (val >>  0) & 0xFF;
                ptr--;
@@ -384,21 +383,21 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
 
                break;
        case OMAP_ECC_BCH16_CODE_HW:
-               val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[2]);
+               val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]);
                ecc_code[i++] = (val >>  8) & 0xFF;
                ecc_code[i++] = (val >>  0) & 0xFF;
-               val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[1]);
+               val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]);
                ecc_code[i++] = (val >> 24) & 0xFF;
                ecc_code[i++] = (val >> 16) & 0xFF;
                ecc_code[i++] = (val >>  8) & 0xFF;
                ecc_code[i++] = (val >>  0) & 0xFF;
-               val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[0]);
+               val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]);
                ecc_code[i++] = (val >> 24) & 0xFF;
                ecc_code[i++] = (val >> 16) & 0xFF;
                ecc_code[i++] = (val >>  8) & 0xFF;
                ecc_code[i++] = (val >>  0) & 0xFF;
                for (j = 3; j >= 0; j--) {
-                       val = readl(&gpmc_cfg->bch_result_0_3[sector].bch_result_x[j]
+                       val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j]
                                                                        );
                        ecc_code[i++] = (val >> 24) & 0xFF;
                        ecc_code[i++] = (val >> 16) & 0xFF;
@@ -432,22 +431,6 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
        return 0;
 }
 
-/**
- * omap_calculate_ecc_bch - ECC generator for 1 sector
- * @mtd:        MTD device structure
- * @dat:       The pointer to data on which ecc is computed
- * @ecc_code:  The ecc_code buffer
- *
- * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
- * when SW based correction is required as ECC is required for one sector
- * at a time.
- */
-static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
-                                 const u_char *dat, u_char *ecc_calc)
-{
-       return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
-}
-
 static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
@@ -573,34 +556,6 @@ static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
 
 #ifdef CONFIG_NAND_OMAP_ELM
 
-/**
- * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
- * @mtd:       MTD device structure
- * @dat:       The pointer to data on which ecc is computed
- * @ecc_code:  The ecc_code buffer
- *
- * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
- */
-static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd,
-                                       const u_char *dat, u_char *ecc_calc)
-{
-       struct nand_chip *chip = mtd_to_nand(mtd);
-       int eccbytes = chip->ecc.bytes;
-       unsigned long nsectors;
-       int i, ret;
-
-       nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1;
-       for (i = 0; i < nsectors; i++) {
-               ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i);
-               if (ret)
-                       return ret;
-
-               ecc_calc += eccbytes;
-       }
-
-       return 0;
-}
-
 /*
  * omap_reverse_list - re-orders list elements in reverse order [internal]
  * @list:      pointer to start of list
@@ -753,7 +708,6 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 {
        int i, eccsize = chip->ecc.size;
        int eccbytes = chip->ecc.bytes;
-       int ecctotal = chip->ecc.total;
        int eccsteps = chip->ecc.steps;
        uint8_t *p = buf;
        uint8_t *ecc_calc = chip->buffers->ecccalc;
@@ -761,24 +715,30 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
        uint32_t *eccpos = chip->ecc.layout->eccpos;
        uint8_t *oob = chip->oob_poi;
        uint32_t oob_pos;
+       u32 data_pos = 0;
 
        /* oob area start */
        oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
        oob += chip->ecc.layout->eccpos[0];
 
-       /* Enable ECC engine */
-       chip->ecc.hwctl(mtd, NAND_ECC_READ);
+       for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
+            oob += eccbytes) {
+               /* Enable ECC engine */
+               chip->ecc.hwctl(mtd, NAND_ECC_READ);
 
-       /* read entire page */
-       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
-       chip->read_buf(mtd, buf, mtd->writesize);
+               /* read data */
+               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1);
+               chip->read_buf(mtd, p, eccsize);
 
-       /* read all ecc bytes from oob area */
-       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
-       chip->read_buf(mtd, oob, ecctotal);
+               /* read respective ecc from oob area */
+               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
+               chip->read_buf(mtd, oob, eccbytes);
+               /* read syndrome */
+               chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
-       /* Calculate ecc bytes */
-       omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
+               data_pos += eccsize;
+               oob_pos += eccbytes;
+       }
 
        for (i = 0; i < chip->ecc.total; i++)
                ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -946,6 +906,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand,
                nand->ecc.hwctl         = omap_enable_hwecc_bch;
                nand->ecc.correct       = omap_correct_data_bch_sw;
                nand->ecc.calculate     = omap_calculate_ecc_bch;
+               nand->ecc.steps         = eccsteps;
                /* define ecc-layout */
                ecclayout->eccbytes     = nand->ecc.bytes * eccsteps;
                ecclayout->eccpos[0]    = BADBLOCK_MARKER_LENGTH;
@@ -988,6 +949,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand,
                nand->ecc.correct       = omap_correct_data_bch;
                nand->ecc.calculate     = omap_calculate_ecc_bch;
                nand->ecc.read_page     = omap_read_page_bch;
+               nand->ecc.steps         = eccsteps;
                /* define ecc-layout */
                ecclayout->eccbytes     = nand->ecc.bytes * eccsteps;
                for (i = 0; i < ecclayout->eccbytes; i++)
@@ -1021,6 +983,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand,
                nand->ecc.correct       = omap_correct_data_bch;
                nand->ecc.calculate     = omap_calculate_ecc_bch;
                nand->ecc.read_page     = omap_read_page_bch;
+               nand->ecc.steps         = eccsteps;
                /* define ecc-layout */
                ecclayout->eccbytes     = nand->ecc.bytes * eccsteps;
                for (i = 0; i < ecclayout->eccbytes; i++)