aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafał Miłecki <zajec5@gmail.com>2016-04-17 16:53:05 -0400
committerBoris Brezillon <boris.brezillon@free-electrons.com>2016-05-05 17:55:10 -0400
commit06f384c9010ea7fa1146b9dfdd419d99c9b8a962 (patch)
tree0c93f6f3bfca05225e784fb5f73556ab8782f8f3
parentef296dc947f6a9300a7fb5b696d1e1f543479e18 (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.c146
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}
4172EXPORT_SYMBOL(nand_scan_ident); 4172EXPORT_SYMBOL(nand_scan_ident);
4173 4173
4174static 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);