diff mbox series

[v2,1/2] mtd: rawnand: gpmi: Refactor bch geometry settings function

Message ID 20220325211411.30714-1-han.xu@nxp.com
State Changes Requested
Headers show
Series [v2,1/2] mtd: rawnand: gpmi: Refactor bch geometry settings function | expand

Commit Message

Han Xu March 25, 2022, 9:14 p.m. UTC
The code change refactor the bch geometry setting function, which still
use the legacy bch setting as default option, while user may choose to
use chips required minimum ecc strength by DT flag "fsl,use-minimum-ecc".
It also improve the gpmi_check_ecc function to check if the selected ecc
strength is strong enough.

The driver uses legacy bch geometry settings by default, if the NAND
chips oob size is less than 1KB. The legacy_set_geometry() sets the data
chunk size(step_size) larger than oob size to make sure BBM locates in
data chunk, then set the maximum ecc stength oob can hold. It always use
unbalanced ECC layout, which ecc0 will cover both meta and data0 chunk.

For all other cases,set the bch geometry by chip required strength and
step size, which uses the minimum ecc strength chip required. It can be
explicitly enabled by DT flag "fsl,use-minimum-ecc", but need to be
en/disabled in both u-boot and kernel at the same time.

Signed-off-by: Han Xu <han.xu@nxp.com>
Tested-by: Sean Nyekjaer <sean@geanix.com>

---
Changes in v2
 - split the patch to two parts
 - change the commit log
 - add test tag
---
 drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 56 ++++++++++++++++------
 1 file changed, 42 insertions(+), 14 deletions(-)

Comments

Miquel Raynal March 28, 2022, 9:17 a.m. UTC | #1
Hi Han,

han.xu@nxp.com wrote on Fri, 25 Mar 2022 16:14:10 -0500:

> The code change refactor the bch geometry setting function, which still
> use the legacy bch setting as default option, while user may choose to
> use chips required minimum ecc strength by DT flag "fsl,use-minimum-ecc".
> It also improve the gpmi_check_ecc function to check if the selected ecc
> strength is strong enough.

That should be a dedicated patch?

Otherwise looks fine.

> 
> The driver uses legacy bch geometry settings by default, if the NAND
> chips oob size is less than 1KB. The legacy_set_geometry() sets the data
> chunk size(step_size) larger than oob size to make sure BBM locates in
> data chunk, then set the maximum ecc stength oob can hold. It always use
> unbalanced ECC layout, which ecc0 will cover both meta and data0 chunk.
> 
> For all other cases,set the bch geometry by chip required strength and
> step size, which uses the minimum ecc strength chip required. It can be
> explicitly enabled by DT flag "fsl,use-minimum-ecc", but need to be
> en/disabled in both u-boot and kernel at the same time.
> 
> Signed-off-by: Han Xu <han.xu@nxp.com>
> Tested-by: Sean Nyekjaer <sean@geanix.com>
> 

Thanks,
Miquèl
diff mbox series

Patch

diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
index d96899fa90b7..9a37f8cc663e 100644
--- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
@@ -238,9 +238,14 @@  static void gpmi_dump_info(struct gpmi_nand_data *this)
 		geo->block_mark_bit_offset);
 }
 
-static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
+static bool gpmi_check_ecc(struct gpmi_nand_data *this)
 {
+	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(&this->nand);
 	struct bch_geometry *geo = &this->bch_geometry;
+	const struct nand_ecc_props *requirements =
+		nanddev_get_ecc_requirements(&chip->base);
+	int corr, ds_corr;
 
 	/* Do the sanity check. */
 	if (GPMI_IS_MXS(this)) {
@@ -248,7 +253,22 @@  static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
 		if (geo->gf_len == 14)
 			return false;
 	}
-	return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
+
+	if (geo->ecc_strength > this->devdata->bch_max_ecc_strength)
+		return false;
+
+	/* check ecc strength, same as nand_ecc_is_strong_enough() did */
+	if (requirements->step_size) {
+		corr = mtd->writesize * geo->ecc_strength /
+		       geo->ecc_chunk_size;
+		ds_corr = mtd->writesize * requirements->strength /
+			  requirements->step_size;
+		if (corr < ds_corr ||
+		    geo->ecc_strength < requirements->strength)
+			return false;
+	}
+
+	return true;
 }
 
 /*
@@ -514,24 +534,32 @@  static int legacy_set_geometry(struct gpmi_nand_data *this)
 static int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
 	struct nand_chip *chip = &this->nand;
+	struct mtd_info *mtd = nand_to_mtd(&this->nand);
 	const struct nand_ecc_props *requirements =
 		nanddev_get_ecc_requirements(&chip->base);
+	bool use_minimun_ecc;
+	int err;
 
-	if (chip->ecc.strength > 0 && chip->ecc.size > 0)
-		return set_geometry_by_ecc_info(this, chip->ecc.strength,
-						chip->ecc.size);
-
-	if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
-				|| legacy_set_geometry(this)) {
-		if (!(requirements->strength > 0 && requirements->step_size > 0))
-			return -EINVAL;
+	use_minimun_ecc = of_property_read_bool(this->dev->of_node,
+						"fsl,use-minimum-ecc");
 
-		return set_geometry_by_ecc_info(this,
-						requirements->strength,
-						requirements->step_size);
+	/* use legacy bch geometry settings by default*/
+	if ((!use_minimun_ecc && mtd->oobsize < 1024) ||
+	    !(requirements->strength > 0 && requirements->step_size > 0)) {
+		dev_dbg(this->dev, "use legacy bch geometry\n");
+		err = legacy_set_geometry(this);
+		if (!err)
+			return 0;
 	}
 
-	return 0;
+	/* otherwise use the minimum ecc nand chip required */
+	dev_dbg(this->dev, "use minimum ecc bch geometry\n");
+	err = set_geometry_by_ecc_info(this, requirements->strength,
+					requirements->step_size);
+	if (err)
+		dev_err(this->dev, "none of the bch geometry setting works\n");
+
+	return err;
 }
 
 /* Configures the geometry for BCH.  */