Skip to content

Commit c2cf7e2

Browse files
William Zhangmiquelraynal
authored andcommitted
mtd: rawnand: brcmnand: Add support for getting ecc setting from strap
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
1 parent 29d53c5 commit c2cf7e2

File tree

1 file changed

+77
-6
lines changed

1 file changed

+77
-6
lines changed

drivers/mtd/nand/raw/brcmnand/brcmnand.c

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,22 @@ static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
10381038
return -1;
10391039
}
10401040

1041+
static bool brcmnand_get_sector_size_1k(struct brcmnand_host *host)
1042+
{
1043+
struct brcmnand_controller *ctrl = host->ctrl;
1044+
int sector_size_bit = brcmnand_sector_1k_shift(ctrl);
1045+
u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
1046+
BRCMNAND_CS_ACC_CONTROL);
1047+
u32 acc_control;
1048+
1049+
if (sector_size_bit < 0)
1050+
return false;
1051+
1052+
acc_control = nand_readreg(ctrl, acc_control_offs);
1053+
1054+
return ((acc_control & BIT(sector_size_bit)) != 0);
1055+
}
1056+
10411057
static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
10421058
{
10431059
struct brcmnand_controller *ctrl = host->ctrl;
@@ -1055,6 +1071,43 @@ static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
10551071
nand_writereg(ctrl, acc_control_offs, tmp);
10561072
}
10571073

1074+
static int brcmnand_get_spare_size(struct brcmnand_host *host)
1075+
{
1076+
struct brcmnand_controller *ctrl = host->ctrl;
1077+
u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
1078+
BRCMNAND_CS_ACC_CONTROL);
1079+
u32 acc = nand_readreg(ctrl, acc_control_offs);
1080+
1081+
return (acc & brcmnand_spare_area_mask(ctrl));
1082+
}
1083+
1084+
static void brcmnand_get_ecc_settings(struct brcmnand_host *host, struct nand_chip *chip)
1085+
{
1086+
struct brcmnand_controller *ctrl = host->ctrl;
1087+
u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
1088+
BRCMNAND_CS_ACC_CONTROL);
1089+
bool sector_size_1k = brcmnand_get_sector_size_1k(host);
1090+
int spare_area_size, ecc_level;
1091+
u32 acc;
1092+
1093+
spare_area_size = brcmnand_get_spare_size(host);
1094+
acc = nand_readreg(ctrl, acc_control_offs);
1095+
ecc_level = (acc & brcmnand_ecc_level_mask(ctrl)) >> ctrl->ecc_level_shift;
1096+
if (sector_size_1k)
1097+
chip->ecc.strength = ecc_level * 2;
1098+
else if (spare_area_size == 16 && ecc_level == 15)
1099+
chip->ecc.strength = 1; /* hamming */
1100+
else
1101+
chip->ecc.strength = ecc_level;
1102+
1103+
if (chip->ecc.size == 0) {
1104+
if (sector_size_1k)
1105+
chip->ecc.size = 1024;
1106+
else
1107+
chip->ecc.size = 512;
1108+
}
1109+
}
1110+
10581111
/***********************************************************************
10591112
* CS_NAND_SELECT
10601113
***********************************************************************/
@@ -2625,19 +2678,37 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
26252678
nanddev_get_memorg(&chip->base);
26262679
struct brcmnand_controller *ctrl = host->ctrl;
26272680
struct brcmnand_cfg *cfg = &host->hwcfg;
2628-
char msg[128];
2681+
struct device_node *np = nand_get_flash_node(chip);
26292682
u32 offs, tmp, oob_sector;
2683+
bool use_strap = false;
2684+
char msg[128];
26302685
int ret;
26312686

26322687
memset(cfg, 0, sizeof(*cfg));
2688+
use_strap = of_property_read_bool(np, "brcm,nand-ecc-use-strap");
26332689

2634-
ret = of_property_read_u32(nand_get_flash_node(chip),
2635-
"brcm,nand-oob-sector-size",
2690+
/*
2691+
* Either nand-ecc-xxx or brcm,nand-ecc-use-strap can be set. Error out
2692+
* if both exist.
2693+
*/
2694+
if (chip->ecc.strength && use_strap) {
2695+
dev_err(ctrl->dev,
2696+
"ECC strap and DT ECC configuration properties are mutually exclusive\n");
2697+
return -EINVAL;
2698+
}
2699+
2700+
if (use_strap)
2701+
brcmnand_get_ecc_settings(host, chip);
2702+
2703+
ret = of_property_read_u32(np, "brcm,nand-oob-sector-size",
26362704
&oob_sector);
26372705
if (ret) {
2638-
/* Use detected size */
2639-
cfg->spare_area_size = mtd->oobsize /
2640-
(mtd->writesize >> FC_SHIFT);
2706+
if (use_strap)
2707+
cfg->spare_area_size = brcmnand_get_spare_size(host);
2708+
else
2709+
/* Use detected size */
2710+
cfg->spare_area_size = mtd->oobsize /
2711+
(mtd->writesize >> FC_SHIFT);
26412712
} else {
26422713
cfg->spare_area_size = oob_sector;
26432714
}

0 commit comments

Comments
 (0)