Message ID | 20240916-brcmnand-fixes-v2-7-08632f64c8ec@linaro.org |
---|---|
State | New |
Headers | show |
Series | mtd: nand: brcmnand: Backported fixes from Linux | expand |
> -----Original Message----- > From: Linus Walleij <linus.walleij@linaro.org> > Sent: Monday, September 16, 2024 2:59 AM > To: u-boot@lists.denx.de; Dario Binacchi > <dario.binacchi@amarulasolutions.com>; Michael Trimarchi > <michael@amarulasolutions.com>; Anand Gore > <anand.gore@broadcom.com>; William Zhang > <william.zhang@broadcom.com>; Kursad Oney > <kursad.oney@broadcom.com>; Philippe Reynes > <philippe.reynes@softathome.com> > Cc: Linus Walleij <linus.walleij@linaro.org>; David Regan > <dregan@broadcom.com>; Miquel Raynal <miquel.raynal@bootlin.com> > Subject: [PATCH v2 7/7] mtd: rawnand: brcmnand: Add support for getting > ecc setting from strap > > From: William Zhang <william.zhang@broadcom.com> > > Backport from the upstream Linux kernel > commit c2cf7e25eb2a3c915a420fb8ceed8912add7f36c > "mtd: rawnand: brcmnand: Add support for getting ecc setting from strap" > > Note: the upstream kernel introduces a new > bool brcmnand_get_sector_size_1k() function because the int > version in U-Boot has been removed in Linux. I kept the old > int-returning version that is already in U-Boot as we depend > on that in other code. > > BCMBCA broadband SoC based board design does not specify ecc setting in > dts but rather use the SoC NAND strap info to obtain the ecc strength > and spare area size setting. Add brcm,nand-ecc-use-strap dts propety for > this purpose and update driver to support this option. However these two > options can not be used at the same time. > > Signed-off-by: William Zhang <william.zhang@broadcom.com> > Reviewed-by: David Regan <dregan@broadcom.com> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> > Link: https://lore.kernel.org/linux-mtd/20240301173308.226004-1- > william.zhang@broadcom.com > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > drivers/mtd/nand/raw/brcmnand/brcmnand.c | 70 > ++++++++++++++++++++++++++++++-- > 1 file changed, 66 insertions(+), 4 deletions(-) > > diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c > b/drivers/mtd/nand/raw/brcmnand/brcmnand.c > index 071b33951648..749553c9df90 100644 > --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c > +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c > @@ -980,6 +980,43 @@ static void brcmnand_set_sector_size_1k(struct > brcmnand_host *host, int val) > nand_writereg(ctrl, acc_control_offs, tmp); > } > > +static int brcmnand_get_spare_size(struct brcmnand_host *host) > +{ > + struct brcmnand_controller *ctrl = host->ctrl; > + u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs, > + > BRCMNAND_CS_ACC_CONTROL); > + u32 acc = nand_readreg(ctrl, acc_control_offs); > + > + return (acc & brcmnand_spare_area_mask(ctrl)); > +} > + > +static void brcmnand_get_ecc_settings(struct brcmnand_host *host, > struct nand_chip *chip) > +{ > + struct brcmnand_controller *ctrl = host->ctrl; > + u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs, > + > BRCMNAND_CS_ACC_CONTROL); > + bool sector_size_1k = brcmnand_get_sector_size_1k(host); > + int spare_area_size, ecc_level; > + u32 acc; > + > + spare_area_size = brcmnand_get_spare_size(host); > + acc = nand_readreg(ctrl, acc_control_offs); > + ecc_level = (acc & brcmnand_ecc_level_mask(ctrl)) >> ctrl- > >ecc_level_shift; > + if (sector_size_1k) > + chip->ecc.strength = ecc_level * 2; > + else if (spare_area_size == 16 && ecc_level == 15) > + chip->ecc.strength = 1; /* hamming */ > + else > + chip->ecc.strength = ecc_level; > + > + if (chip->ecc.size == 0) { > + if (sector_size_1k) > + chip->ecc.size = 1024; > + else > + chip->ecc.size = 512; > + } > +} > + > > /********************************************************** > ************* > * CS_NAND_SELECT > > ********************************************************** > *************/ > @@ -2323,12 +2360,33 @@ static int brcmnand_setup_dev(struct > brcmnand_host *host) > struct nand_memory_organization *memorg = > nanddev_get_memorg(nanddev); > struct brcmnand_controller *ctrl = host->ctrl; > struct brcmnand_cfg *cfg = &host->hwcfg; > - char msg[128]; > u32 offs, tmp, oob_sector; > + bool use_strap = false; > + char msg[128]; > int ret; > > memset(cfg, 0, sizeof(*cfg)); > > +#ifndef __UBOOT__ > + use_strap = of_property_read_bool(nand_get_flash_node(chip), > + "brcm,nand-ecc-use-strap"): > +#else > + use_strap = ofnode_read_bool(nand_get_flash_node(chip), > + "brcm,nand-ecc-use-strap"); > +#endif /* __UBOOT__ */ > + /* > + * Either nand-ecc-xxx or brcm,nand-ecc-use-strap can be set. Error > out > + * if both exist. > + */ > + if (chip->ecc.strength && use_strap) { > + dev_err(ctrl->dev, > + "ECC strap and DT ECC configuration properties are > mutually exclusive\n"); > + return -EINVAL; > + } > + > + if (use_strap) > + brcmnand_get_ecc_settings(host, chip); > + > #ifndef __UBOOT__ > ret = of_property_read_u32(nand_get_flash_node(chip), > "brcm,nand-oob-sector-size", > @@ -2338,10 +2396,14 @@ static int brcmnand_setup_dev(struct > brcmnand_host *host) > "brcm,nand-oob-sector-size", > &oob_sector); > #endif /* __UBOOT__ */ > + > if (ret) { > - /* Use detected size */ > - cfg->spare_area_size = mtd->oobsize / > - (mtd->writesize >> FC_SHIFT); > + if (use_strap) > + cfg->spare_area_size = > brcmnand_get_spare_size(host); > + else > + /* Use detected size */ > + cfg->spare_area_size = mtd->oobsize / > + (mtd->writesize >> FC_SHIFT); > } else { > cfg->spare_area_size = oob_sector; > } > > -- > 2.46.0 Reviewed-by: William Zhang <william.zhang@broadcom.com> Tested-by: William Zhang <william.zhang@broadcom.com>
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 071b33951648..749553c9df90 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -980,6 +980,43 @@ static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val) nand_writereg(ctrl, acc_control_offs, tmp); } +static int brcmnand_get_spare_size(struct brcmnand_host *host) +{ + struct brcmnand_controller *ctrl = host->ctrl; + u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs, + BRCMNAND_CS_ACC_CONTROL); + u32 acc = nand_readreg(ctrl, acc_control_offs); + + return (acc & brcmnand_spare_area_mask(ctrl)); +} + +static void brcmnand_get_ecc_settings(struct brcmnand_host *host, struct nand_chip *chip) +{ + struct brcmnand_controller *ctrl = host->ctrl; + u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs, + BRCMNAND_CS_ACC_CONTROL); + bool sector_size_1k = brcmnand_get_sector_size_1k(host); + int spare_area_size, ecc_level; + u32 acc; + + spare_area_size = brcmnand_get_spare_size(host); + acc = nand_readreg(ctrl, acc_control_offs); + ecc_level = (acc & brcmnand_ecc_level_mask(ctrl)) >> ctrl->ecc_level_shift; + if (sector_size_1k) + chip->ecc.strength = ecc_level * 2; + else if (spare_area_size == 16 && ecc_level == 15) + chip->ecc.strength = 1; /* hamming */ + else + chip->ecc.strength = ecc_level; + + if (chip->ecc.size == 0) { + if (sector_size_1k) + chip->ecc.size = 1024; + else + chip->ecc.size = 512; + } +} + /*********************************************************************** * CS_NAND_SELECT ***********************************************************************/ @@ -2323,12 +2360,33 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) struct nand_memory_organization *memorg = nanddev_get_memorg(nanddev); struct brcmnand_controller *ctrl = host->ctrl; struct brcmnand_cfg *cfg = &host->hwcfg; - char msg[128]; u32 offs, tmp, oob_sector; + bool use_strap = false; + char msg[128]; int ret; memset(cfg, 0, sizeof(*cfg)); +#ifndef __UBOOT__ + use_strap = of_property_read_bool(nand_get_flash_node(chip), + "brcm,nand-ecc-use-strap"): +#else + use_strap = ofnode_read_bool(nand_get_flash_node(chip), + "brcm,nand-ecc-use-strap"); +#endif /* __UBOOT__ */ + /* + * Either nand-ecc-xxx or brcm,nand-ecc-use-strap can be set. Error out + * if both exist. + */ + if (chip->ecc.strength && use_strap) { + dev_err(ctrl->dev, + "ECC strap and DT ECC configuration properties are mutually exclusive\n"); + return -EINVAL; + } + + if (use_strap) + brcmnand_get_ecc_settings(host, chip); + #ifndef __UBOOT__ ret = of_property_read_u32(nand_get_flash_node(chip), "brcm,nand-oob-sector-size", @@ -2338,10 +2396,14 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) "brcm,nand-oob-sector-size", &oob_sector); #endif /* __UBOOT__ */ + if (ret) { - /* Use detected size */ - cfg->spare_area_size = mtd->oobsize / - (mtd->writesize >> FC_SHIFT); + if (use_strap) + cfg->spare_area_size = brcmnand_get_spare_size(host); + else + /* Use detected size */ + cfg->spare_area_size = mtd->oobsize / + (mtd->writesize >> FC_SHIFT); } else { cfg->spare_area_size = oob_sector; }