mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller
[ Upstream commit 2ec2839a9062db8a592525a3fdabd42dcd9a3a9b ]
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: decba6d478
("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: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
b87d03ed6a
commit
4954c5a054
@ -268,6 +268,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 */
|
||||
@ -592,6 +593,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 bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl)
|
||||
{
|
||||
return static_branch_unlikely(&brcmnand_soc_has_ops_key);
|
||||
@ -729,6 +758,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;
|
||||
}
|
||||
|
||||
@ -917,30 +952,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)
|
||||
@ -953,18 +964,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;
|
||||
}
|
||||
@ -978,8 +986,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);
|
||||
@ -2533,7 +2541,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);
|
||||
|
Loading…
Reference in New Issue
Block a user