Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06f384c9 authored by Rafał Miłecki's avatar Rafał Miłecki Committed by Boris Brezillon
Browse files

mtd: nand: read ECC algorithm from the new field



Now we have all drivers properly setting this new field we can start
using it. For a very short period of time we should support both values:
NAND_ECC_SOFT and NAND_ECC_SOFT_BCH treating them the same. It's because
of_get_nand_ecc_mode may still be setting NAND_ECC_SOFT_BCH.

Signed-off-by: default avatarRafał Miłecki <zajec5@gmail.com>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
parent ef296dc9
Loading
Loading
Loading
Loading
+85 −61
Original line number Diff line number Diff line
@@ -4171,6 +4171,83 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
}
EXPORT_SYMBOL(nand_scan_ident);

static int nand_set_ecc_soft_ops(struct mtd_info *mtd)
{
	struct nand_chip *chip = mtd_to_nand(mtd);
	struct nand_ecc_ctrl *ecc = &chip->ecc;

	if (WARN_ON(ecc->mode != NAND_ECC_SOFT &&
		    ecc->mode != NAND_ECC_SOFT_BCH))
		return -EINVAL;

	switch (ecc->algo) {
	case NAND_ECC_HAMMING:
		ecc->calculate = nand_calculate_ecc;
		ecc->correct = nand_correct_data;
		ecc->read_page = nand_read_page_swecc;
		ecc->read_subpage = nand_read_subpage;
		ecc->write_page = nand_write_page_swecc;
		ecc->read_page_raw = nand_read_page_raw;
		ecc->write_page_raw = nand_write_page_raw;
		ecc->read_oob = nand_read_oob_std;
		ecc->write_oob = nand_write_oob_std;
		if (!ecc->size)
			ecc->size = 256;
		ecc->bytes = 3;
		ecc->strength = 1;
		return 0;
	case NAND_ECC_BCH:
		if (!mtd_nand_has_bch()) {
			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
			return -EINVAL;
		}
		ecc->calculate = nand_bch_calculate_ecc;
		ecc->correct = nand_bch_correct_data;
		ecc->read_page = nand_read_page_swecc;
		ecc->read_subpage = nand_read_subpage;
		ecc->write_page = nand_write_page_swecc;
		ecc->read_page_raw = nand_read_page_raw;
		ecc->write_page_raw = nand_write_page_raw;
		ecc->read_oob = nand_read_oob_std;
		ecc->write_oob = nand_write_oob_std;
		/*
		* Board driver should supply ecc.size and ecc.strength
		* values to select how many bits are correctable.
		* Otherwise, default to 4 bits for large page devices.
		*/
		if (!ecc->size && (mtd->oobsize >= 64)) {
			ecc->size = 512;
			ecc->strength = 4;
		}

		/*
		 * if no ecc placement scheme was provided pickup the default
		 * large page one.
		 */
		if (!mtd->ooblayout) {
			/* handle large page devices only */
			if (mtd->oobsize < 64) {
				WARN(1, "OOB layout is required when using software BCH on small pages\n");
				return -EINVAL;
			}

			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
		}

		/* See nand_bch_init() for details. */
		ecc->bytes = 0;
		ecc->priv = nand_bch_init(mtd);
		if (!ecc->priv) {
			WARN(1, "BCH ECC initialization failed!\n");
			return -EINVAL;
		}
		return 0;
	default:
		WARN(1, "Unsupported ECC algorithm!\n");
		return -EINVAL;
	}
}

/*
 * Check if the chip configuration meet the datasheet requirements.

@@ -4246,7 +4323,9 @@ int nand_scan_tail(struct mtd_info *mtd)
	/*
	 * If no default placement scheme is given, select an appropriate one.
	 */
	if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
	if (!mtd->ooblayout &&
	    !((ecc->mode == NAND_ECC_SOFT || ecc->mode == NAND_ECC_SOFT_BCH) &&
	       ecc->algo == NAND_ECC_BCH)) {
		switch (mtd->oobsize) {
		case 8:
		case 16:
@@ -4340,66 +4419,9 @@ int nand_scan_tail(struct mtd_info *mtd)
		ecc->algo = NAND_ECC_HAMMING;

	case NAND_ECC_SOFT:
		ecc->calculate = nand_calculate_ecc;
		ecc->correct = nand_correct_data;
		ecc->read_page = nand_read_page_swecc;
		ecc->read_subpage = nand_read_subpage;
		ecc->write_page = nand_write_page_swecc;
		ecc->read_page_raw = nand_read_page_raw;
		ecc->write_page_raw = nand_write_page_raw;
		ecc->read_oob = nand_read_oob_std;
		ecc->write_oob = nand_write_oob_std;
		if (!ecc->size)
			ecc->size = 256;
		ecc->bytes = 3;
		ecc->strength = 1;
		break;

	case NAND_ECC_SOFT_BCH:
		if (!mtd_nand_has_bch()) {
			WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
			ret = -EINVAL;
			goto err_free;
		}
		ecc->calculate = nand_bch_calculate_ecc;
		ecc->correct = nand_bch_correct_data;
		ecc->read_page = nand_read_page_swecc;
		ecc->read_subpage = nand_read_subpage;
		ecc->write_page = nand_write_page_swecc;
		ecc->read_page_raw = nand_read_page_raw;
		ecc->write_page_raw = nand_write_page_raw;
		ecc->read_oob = nand_read_oob_std;
		ecc->write_oob = nand_write_oob_std;
		/*
		 * Board driver should supply ecc.size and ecc.strength values
		 * to select how many bits are correctable. Otherwise, default
		 * to 4 bits for large page devices.
		 */
		if (!ecc->size && (mtd->oobsize >= 64)) {
			ecc->size = 512;
			ecc->strength = 4;
		}

		/*
		 * if no ecc placement scheme was provided pickup the default
		 * large page one.
		 */
		if (!mtd->ooblayout) {
			/* handle large page devices only */
			if (mtd->oobsize < 64) {
				WARN(1, "OOB layout is required when using software BCH on small pages\n");
				ret = -EINVAL;
				goto err_free;
			}

			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
		}

		/* See nand_bch_init() for details. */
		ecc->bytes = 0;
		ecc->priv = nand_bch_init(mtd);
		if (!ecc->priv) {
			WARN(1, "BCH ECC initialization failed!\n");
		ret = nand_set_ecc_soft_ops(mtd);
		if (ret) {
			ret = -EINVAL;
			goto err_free;
		}
@@ -4585,7 +4607,9 @@ void nand_release(struct mtd_info *mtd)
{
	struct nand_chip *chip = mtd_to_nand(mtd);

	if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
	if ((chip->ecc.mode == NAND_ECC_SOFT ||
	     chip->ecc.mode == NAND_ECC_SOFT_BCH) &&
	    chip->ecc.algo == NAND_ECC_BCH)
		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);

	mtd_device_unregister(mtd);