Skip to content

Commit

Permalink
mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller
Browse files Browse the repository at this point in the history
commit 2ec2839 upstream.

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.

Fixes: decba6d ("mtd: brcmnand: Add v7.2 controller support")
Signed-off-by: William Zhang <william.zhang@broadcom.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Cc: stable@vger.kernel.org
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
William Zhang authored and Greg Kroah-Hartman committed Sep 23, 2023
1 parent 17a4032 commit 55e55d7
Showing 1 changed file with 42 additions and 33 deletions.
75 changes: 42 additions & 33 deletions drivers/mtd/nand/raw/brcmnand/brcmnand.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct brcmnand_controller {
unsigned int max_page_size;
const unsigned int *page_sizes;
unsigned int max_oob;
u32 ecc_level_shift;
u32 features;

/* for low-power standby/resume only */
Expand Down Expand Up @@ -441,6 +442,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);
Expand Down Expand Up @@ -544,6 +573,12 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
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;
}

Expand Down Expand Up @@ -697,30 +732,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)
Expand All @@ -731,18 +742,15 @@ static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
return GENMASK(5, 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;
}
Expand All @@ -756,8 +764,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);
Expand Down Expand Up @@ -2103,9 +2111,10 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,

tmp = nand_readreg(ctrl, acc_control_offs);
tmp &= ~brcmnand_ecc_level_mask(ctrl);
tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
tmp |= cfg->ecc_level << ctrl->ecc_level_shift;
tmp &= ~brcmnand_spare_area_mask(ctrl);
tmp |= cfg->spare_area_size;

nand_writereg(ctrl, acc_control_offs, tmp);

brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
Expand Down

0 comments on commit 55e55d7

Please sign in to comment.