mirror of https://gitee.com/openkylin/linux.git
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: Rafał Miłecki <zajec5@gmail.com> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
This commit is contained in:
parent
ef296dc947
commit
06f384c901
|
@ -4171,6 +4171,83 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(nand_scan_ident);
|
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.
|
* 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 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) {
|
switch (mtd->oobsize) {
|
||||||
case 8:
|
case 8:
|
||||||
case 16:
|
case 16:
|
||||||
|
@ -4340,66 +4419,9 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
ecc->algo = NAND_ECC_HAMMING;
|
ecc->algo = NAND_ECC_HAMMING;
|
||||||
|
|
||||||
case NAND_ECC_SOFT:
|
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:
|
case NAND_ECC_SOFT_BCH:
|
||||||
if (!mtd_nand_has_bch()) {
|
ret = nand_set_ecc_soft_ops(mtd);
|
||||||
WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n");
|
if (ret) {
|
||||||
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 = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
@ -4585,7 +4607,9 @@ void nand_release(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd_to_nand(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);
|
nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
|
||||||
|
|
||||||
mtd_device_unregister(mtd);
|
mtd_device_unregister(mtd);
|
||||||
|
|
Loading…
Reference in New Issue