]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller
authorWilliam Zhang <william.zhang@broadcom.com>
Mon, 16 Sep 2024 09:58:43 +0000 (11:58 +0200)
committerTom Rini <trini@konsulko.com>
Sat, 5 Oct 2024 17:19:24 +0000 (11:19 -0600)
Backport from the Linux kernel
commit 2ec2839a9062db8a592525a3fdabd42dcd9a3a9b
"mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller"

v7.2 controller has different ECC level field size and shift in the acc
control register than its predecessor and successor controller. It needs
to be set specifically.

Signed-off-by: William Zhang <william.zhang@broadcom.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20230706182909.79151-2-william.zhang@broadcom.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: William Zhang <william.zhang@broadcom.com>
drivers/mtd/nand/raw/brcmnand/brcmnand.c

index b1af3f717d43b0414a5f2b0dbc26dfb2c9d2a4a4..700d1122639f0cf9c7f08996866bb6b8cde7ed98 100644 (file)
@@ -218,6 +218,7 @@ struct brcmnand_controller {
        const unsigned int      *page_sizes;
        unsigned int            page_size_shift;
        unsigned int            max_oob;
+       u32                     ecc_level_shift;
        u32                     features;
 
        /* for low-power standby/resume only */
@@ -544,6 +545,34 @@ enum {
        INTFC_CTLR_READY                = BIT(31),
 };
 
+/***********************************************************************
+ * NAND ACC CONTROL bitfield
+ *
+ * Some bits have remained constant throughout hardware revision, while
+ * others have shifted around.
+ ***********************************************************************/
+
+/* Constant for all versions (where supported) */
+enum {
+       /* See BRCMNAND_HAS_CACHE_MODE */
+       ACC_CONTROL_CACHE_MODE                          = BIT(22),
+
+       /* See BRCMNAND_HAS_PREFETCH */
+       ACC_CONTROL_PREFETCH                            = BIT(23),
+
+       ACC_CONTROL_PAGE_HIT                            = BIT(24),
+       ACC_CONTROL_WR_PREEMPT                          = BIT(25),
+       ACC_CONTROL_PARTIAL_PAGE                        = BIT(26),
+       ACC_CONTROL_RD_ERASED                           = BIT(27),
+       ACC_CONTROL_FAST_PGM_RDIN                       = BIT(28),
+       ACC_CONTROL_WR_ECC                              = BIT(30),
+       ACC_CONTROL_RD_ECC                              = BIT(31),
+};
+
+#define        ACC_CONTROL_ECC_SHIFT                   16
+/* Only for v7.2 */
+#define        ACC_CONTROL_ECC_EXT_SHIFT               13
+
 static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
 {
        return brcmnand_readl(ctrl->nand_base + offs);
@@ -675,6 +704,12 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
 #endif /* __UBOOT__ */
                ctrl->features |= BRCMNAND_HAS_WP;
 
+       /* v7.2 has different ecc level shift in the acc register */
+       if (ctrl->nand_version == 0x0702)
+               ctrl->ecc_level_shift = ACC_CONTROL_ECC_EXT_SHIFT;
+       else
+               ctrl->ecc_level_shift = ACC_CONTROL_ECC_SHIFT;
+
        return 0;
 }
 
@@ -844,30 +879,6 @@ static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
        return 0;
 }
 
-/***********************************************************************
- * NAND ACC CONTROL bitfield
- *
- * Some bits have remained constant throughout hardware revision, while
- * others have shifted around.
- ***********************************************************************/
-
-/* Constant for all versions (where supported) */
-enum {
-       /* See BRCMNAND_HAS_CACHE_MODE */
-       ACC_CONTROL_CACHE_MODE                          = BIT(22),
-
-       /* See BRCMNAND_HAS_PREFETCH */
-       ACC_CONTROL_PREFETCH                            = BIT(23),
-
-       ACC_CONTROL_PAGE_HIT                            = BIT(24),
-       ACC_CONTROL_WR_PREEMPT                          = BIT(25),
-       ACC_CONTROL_PARTIAL_PAGE                        = BIT(26),
-       ACC_CONTROL_RD_ERASED                           = BIT(27),
-       ACC_CONTROL_FAST_PGM_RDIN                       = BIT(28),
-       ACC_CONTROL_WR_ECC                              = BIT(30),
-       ACC_CONTROL_RD_ECC                              = BIT(31),
-};
-
 static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
 {
        if (ctrl->nand_version == 0x0702)
@@ -880,18 +891,15 @@ static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
                return GENMASK(4, 0);
 }
 
-#define NAND_ACC_CONTROL_ECC_SHIFT     16
-#define NAND_ACC_CONTROL_ECC_EXT_SHIFT 13
-
 static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
 {
        u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
 
-       mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
+       mask <<= ACC_CONTROL_ECC_SHIFT;
 
        /* v7.2 includes additional ECC levels */
-       if (ctrl->nand_version >= 0x0702)
-               mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
+       if (ctrl->nand_version == 0x0702)
+               mask |= 0x7 << ACC_CONTROL_ECC_EXT_SHIFT;
 
        return mask;
 }
@@ -905,8 +913,8 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
 
        if (en) {
                acc_control |= ecc_flags; /* enable RD/WR ECC */
-               acc_control |= host->hwcfg.ecc_level
-                              << NAND_ACC_CONTROL_ECC_SHIFT;
+               acc_control &= ~brcmnand_ecc_level_mask(ctrl);
+               acc_control |= host->hwcfg.ecc_level << ctrl->ecc_level_shift;
        } else {
                acc_control &= ~ecc_flags; /* disable RD/WR ECC */
                acc_control &= ~brcmnand_ecc_level_mask(ctrl);
@@ -2225,7 +2233,7 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
        tmp &= ~brcmnand_ecc_level_mask(ctrl);
        tmp &= ~brcmnand_spare_area_mask(ctrl);
        if (ctrl->nand_version >= 0x0302) {
-               tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
+               tmp |= cfg->ecc_level << ctrl->ecc_level_shift;
                tmp |= cfg->spare_area_size;
        }
        nand_writereg(ctrl, acc_control_offs, tmp);