diff options
| author | Rafał Miłecki <zajec5@gmail.com> | 2016-04-17 16:53:05 -0400 |
|---|---|---|
| committer | Boris Brezillon <boris.brezillon@free-electrons.com> | 2016-05-05 17:55:10 -0400 |
| commit | 06f384c9010ea7fa1146b9dfdd419d99c9b8a962 (patch) | |
| tree | 0c93f6f3bfca05225e784fb5f73556ab8782f8f3 | |
| parent | ef296dc947f6a9300a7fb5b696d1e1f543479e18 (diff) | |
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>
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 146 |
1 files changed, 85 insertions, 61 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 2a049576ab31..9f967531bc68 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -4171,6 +4171,83 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, | |||
| 4171 | } | 4171 | } |
| 4172 | EXPORT_SYMBOL(nand_scan_ident); | 4172 | EXPORT_SYMBOL(nand_scan_ident); |
| 4173 | 4173 | ||
| 4174 | static int nand_set_ecc_soft_ops(struct mtd_info *mtd) | ||
| 4175 | { | ||
| 4176 | struct nand_chip *chip = mtd_to_nand(mtd); | ||
| 4177 | struct nand_ecc_ctrl *ecc = &chip->ecc; | ||
| 4178 | |||
| 4179 | if (WARN_ON(ecc->mode != NAND_ECC_SOFT && | ||
| 4180 | ecc->mode != NAND_ECC_SOFT_BCH)) | ||
| 4181 | return -EINVAL; | ||
| 4182 | |||
| 4183 | switch (ecc->algo) { | ||
| 4184 | case NAND_ECC_HAMMING: | ||
| 4185 | ecc->calculate = nand_calculate_ecc; | ||
| 4186 | ecc->correct = nand_correct_data; | ||
| 4187 | ecc->read_page = nand_read_page_swecc; | ||
| 4188 | ecc->read_subpage = nand_read_subpage; | ||
| 4189 | ecc->write_page = nand_write_page_swecc; | ||
| 4190 | ecc->read_page_raw = nand_read_page_raw; | ||
| 4191 | ecc->write_page_raw = nand_write_page_raw; | ||
| 4192 | ecc->read_oob = nand_read_oob_std; | ||
| 4193 | ecc->write_oob = nand_write_oob_std; | ||
| 4194 | if (!ecc->size) | ||
| 4195 | ecc->size = 256; | ||
| 4196 | ecc->bytes = 3; | ||
| 4197 | ecc->strength = 1; | ||
| 4198 | return 0; | ||
| 4199 | case NAND_ECC_BCH: | ||
| 4200 | if (!mtd_nand_has_bch()) { | ||
| 4201 | WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); | ||
| 4202 | return -EINVAL; | ||
| 4203 | } | ||
| 4204 | ecc->calculate = nand_bch_calculate_ecc; | ||
| 4205 | ecc->correct = nand_bch_correct_data; | ||
| 4206 | ecc->read_page = nand_read_page_swecc; | ||
| 4207 | ecc->read_subpage = nand_read_subpage; | ||
| 4208 | ecc->write_page = nand_write_page_swecc; | ||
| 4209 | ecc->read_page_raw = nand_read_page_raw; | ||
| 4210 | ecc->write_page_raw = nand_write_page_raw; | ||
| 4211 | ecc->read_oob = nand_read_oob_std; | ||
| 4212 | ecc->write_oob = nand_write_oob_std; | ||
| 4213 | /* | ||
| 4214 | * Board driver should supply ecc.size and ecc.strength | ||
| 4215 | * values to select how many bits are correctable. | ||
| 4216 | * Otherwise, default to 4 bits for large page devices. | ||
| 4217 | */ | ||
| 4218 | if (!ecc->size && (mtd->oobsize >= 64)) { | ||
| 4219 | ecc->size = 512; | ||
| 4220 | ecc->strength = 4; | ||
| 4221 | } | ||
| 4222 | |||
| 4223 | /* | ||
| 4224 | * if no ecc placement scheme was provided pickup the default | ||
| 4225 | * large page one. | ||
| 4226 | */ | ||
| 4227 | if (!mtd->ooblayout) { | ||
| 4228 | /* handle large page devices only */ | ||
| 4229 | if (mtd->oobsize < 64) { | ||
| 4230 | WARN(1, "OOB layout is required when using software BCH on small pages\n"); | ||
| 4231 | return -EINVAL; | ||
| 4232 | } | ||
| 4233 | |||
| 4234 | mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); | ||
| 4235 | } | ||
| 4236 | |||
| 4237 | /* See nand_bch_init() for details. */ | ||
| 4238 | ecc->bytes = 0; | ||
| 4239 | ecc->priv = nand_bch_init(mtd); | ||
| 4240 | if (!ecc->priv) { | ||
| 4241 | WARN(1, "BCH ECC initialization failed!\n"); | ||
| 4242 | return -EINVAL; | ||
| 4243 | } | ||
| 4244 | return 0; | ||
| 4245 | default: | ||
| 4246 | WARN(1, "Unsupported ECC algorithm!\n"); | ||
| 4247 | return -EINVAL; | ||
| 4248 | } | ||
| 4249 | } | ||
| 4250 | |||
| 4174 | /* | 4251 | /* |
| 4175 | * Check if the chip configuration meet the datasheet requirements. | 4252 | * Check if the chip configuration meet the datasheet requirements. |
| 4176 | 4253 | ||
| @@ -4246,7 +4323,9 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 4246 | /* | 4323 | /* |
| 4247 | * If no default placement scheme is given, select an appropriate one. | 4324 | * If no default placement scheme is given, select an appropriate one. |
| 4248 | */ | 4325 | */ |
| 4249 | if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) { | 4326 | if (!mtd->ooblayout && |
| 4327 | !((ecc->mode == NAND_ECC_SOFT || ecc->mode == NAND_ECC_SOFT_BCH) && | ||
| 4328 | ecc->algo == NAND_ECC_BCH)) { | ||
| 4250 | switch (mtd->oobsize) { | 4329 | switch (mtd->oobsize) { |
| 4251 | case 8: | 4330 | case 8: |
| 4252 | case 16: | 4331 | case 16: |
| @@ -4340,66 +4419,9 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 4340 | ecc->algo = NAND_ECC_HAMMING; | 4419 | ecc->algo = NAND_ECC_HAMMING; |
| 4341 | 4420 | ||
| 4342 | case NAND_ECC_SOFT: | 4421 | case NAND_ECC_SOFT: |
| 4343 | ecc->calculate = nand_calculate_ecc; | ||
| 4344 | ecc->correct = nand_correct_data; | ||
| 4345 | ecc->read_page = nand_read_page_swecc; | ||
| 4346 | ecc->read_subpage = nand_read_subpage; | ||
| 4347 | ecc->write_page = nand_write_page_swecc; | ||
| 4348 | ecc->read_page_raw = nand_read_page_raw; | ||
| 4349 | ecc->write_page_raw = nand_write_page_raw; | ||
| 4350 | ecc->read_oob = nand_read_oob_std; | ||
| 4351 | ecc->write_oob = nand_write_oob_std; | ||
| 4352 | if (!ecc->size) | ||
| 4353 | ecc->size = 256; | ||
| 4354 | ecc->bytes = 3; | ||
| 4355 | ecc->strength = 1; | ||
| 4356 | break; | ||
| 4357 | |||
| 4358 | case NAND_ECC_SOFT_BCH: | 4422 | case NAND_ECC_SOFT_BCH: |
| 4359 | if (!mtd_nand_has_bch()) { | 4423 | ret = nand_set_ecc_soft_ops(mtd); |
| 4360 | WARN(1, "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); | 4424 | if (ret) { |
| 4361 | ret = -EINVAL; | ||
| 4362 | goto err_free; | ||
| 4363 | } | ||
| 4364 | ecc->calculate = nand_bch_calculate_ecc; | ||
| 4365 | ecc->correct = nand_bch_correct_data; | ||
| 4366 | ecc->read_page = nand_read_page_swecc; | ||
| 4367 | ecc->read_subpage = nand_read_subpage; | ||
| 4368 | ecc->write_page = nand_write_page_swecc; | ||
| 4369 | ecc->read_page_raw = nand_read_page_raw; | ||
| 4370 | ecc->write_page_raw = nand_write_page_raw; | ||
| 4371 | ecc->read_oob = nand_read_oob_std; | ||
| 4372 | ecc->write_oob = nand_write_oob_std; | ||
| 4373 | /* | ||
| 4374 | * Board driver should supply ecc.size and ecc.strength values | ||
| 4375 | * to select how many bits are correctable. Otherwise, default | ||
| 4376 | * to 4 bits for large page devices. | ||
| 4377 | */ | ||
| 4378 | if (!ecc->size && (mtd->oobsize >= 64)) { | ||
| 4379 | ecc->size = 512; | ||
| 4380 | ecc->strength = 4; | ||
| 4381 | } | ||
| 4382 | |||
| 4383 | /* | ||
| 4384 | * if no ecc placement scheme was provided pickup the default | ||
| 4385 | * large page one. | ||
| 4386 | */ | ||
| 4387 | if (!mtd->ooblayout) { | ||
| 4388 | /* handle large page devices only */ | ||
| 4389 | if (mtd->oobsize < 64) { | ||
| 4390 | WARN(1, "OOB layout is required when using software BCH on small pages\n"); | ||
| 4391 | ret = -EINVAL; | ||
| 4392 | goto err_free; | ||
| 4393 | } | ||
| 4394 | |||
| 4395 | mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); | ||
| 4396 | } | ||
| 4397 | |||
| 4398 | /* See nand_bch_init() for details. */ | ||
| 4399 | ecc->bytes = 0; | ||
| 4400 | ecc->priv = nand_bch_init(mtd); | ||
| 4401 | if (!ecc->priv) { | ||
| 4402 | WARN(1, "BCH ECC initialization failed!\n"); | ||
| 4403 | ret = -EINVAL; | 4425 | ret = -EINVAL; |
| 4404 | goto err_free; | 4426 | goto err_free; |
| 4405 | } | 4427 | } |
| @@ -4585,7 +4607,9 @@ void nand_release(struct mtd_info *mtd) | |||
| 4585 | { | 4607 | { |
| 4586 | struct nand_chip *chip = mtd_to_nand(mtd); | 4608 | struct nand_chip *chip = mtd_to_nand(mtd); |
| 4587 | 4609 | ||
| 4588 | if (chip->ecc.mode == NAND_ECC_SOFT_BCH) | 4610 | if ((chip->ecc.mode == NAND_ECC_SOFT || |
| 4611 | chip->ecc.mode == NAND_ECC_SOFT_BCH) && | ||
| 4612 | chip->ecc.algo == NAND_ECC_BCH) | ||
| 4589 | nand_bch_free((struct nand_bch_control *)chip->ecc.priv); | 4613 | nand_bch_free((struct nand_bch_control *)chip->ecc.priv); |
| 4590 | 4614 | ||
| 4591 | mtd_device_unregister(mtd); | 4615 | mtd_device_unregister(mtd); |
