| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * This file contains an ECC algorithm that detects and corrects 1 bit |
|---|
| 3 | 4 | * errors in a 256 byte block of data. |
|---|
| .. | .. |
|---|
| 10 | 11 | * Thomas Gleixner (tglx@linutronix.de) |
|---|
| 11 | 12 | * |
|---|
| 12 | 13 | * Information on how this algorithm works and how it was developed |
|---|
| 13 | | - * can be found in Documentation/mtd/nand_ecc.txt |
|---|
| 14 | | - * |
|---|
| 15 | | - * This file is free software; you can redistribute it and/or modify it |
|---|
| 16 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 17 | | - * Free Software Foundation; either version 2 or (at your option) any |
|---|
| 18 | | - * later version. |
|---|
| 19 | | - * |
|---|
| 20 | | - * This file is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 21 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 22 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|---|
| 23 | | - * for more details. |
|---|
| 24 | | - * |
|---|
| 25 | | - * You should have received a copy of the GNU General Public License along |
|---|
| 26 | | - * with this file; if not, write to the Free Software Foundation, Inc., |
|---|
| 27 | | - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|---|
| 28 | | - * |
|---|
| 14 | + * can be found in Documentation/driver-api/mtd/nand_ecc.rst |
|---|
| 29 | 15 | */ |
|---|
| 30 | 16 | |
|---|
| 31 | 17 | #include <linux/types.h> |
|---|
| .. | .. |
|---|
| 132 | 118 | * @buf: input buffer with raw data |
|---|
| 133 | 119 | * @eccsize: data bytes per ECC step (256 or 512) |
|---|
| 134 | 120 | * @code: output buffer with ECC |
|---|
| 121 | + * @sm_order: Smart Media byte ordering |
|---|
| 135 | 122 | */ |
|---|
| 136 | 123 | void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, |
|---|
| 137 | | - unsigned char *code) |
|---|
| 124 | + unsigned char *code, bool sm_order) |
|---|
| 138 | 125 | { |
|---|
| 139 | 126 | int i; |
|---|
| 140 | 127 | const uint32_t *bp = (uint32_t *)buf; |
|---|
| .. | .. |
|---|
| 144 | 131 | /* rp0..rp15..rp17 are the various accumulated parities (per byte) */ |
|---|
| 145 | 132 | uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; |
|---|
| 146 | 133 | uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16; |
|---|
| 147 | | - uint32_t uninitialized_var(rp17); /* to make compiler happy */ |
|---|
| 134 | + uint32_t rp17; |
|---|
| 148 | 135 | uint32_t par; /* the cumulative parity for all data */ |
|---|
| 149 | 136 | uint32_t tmppar; /* the cumulative parity for this iteration; |
|---|
| 150 | 137 | for rp12, rp14 and rp16 at the end of the |
|---|
| .. | .. |
|---|
| 330 | 317 | * possible, but benchmarks showed that on the system this is developed |
|---|
| 331 | 318 | * the code below is the fastest |
|---|
| 332 | 319 | */ |
|---|
| 333 | | -#ifdef CONFIG_MTD_NAND_ECC_SMC |
|---|
| 334 | | - code[0] = |
|---|
| 335 | | - (invparity[rp7] << 7) | |
|---|
| 336 | | - (invparity[rp6] << 6) | |
|---|
| 337 | | - (invparity[rp5] << 5) | |
|---|
| 338 | | - (invparity[rp4] << 4) | |
|---|
| 339 | | - (invparity[rp3] << 3) | |
|---|
| 340 | | - (invparity[rp2] << 2) | |
|---|
| 341 | | - (invparity[rp1] << 1) | |
|---|
| 342 | | - (invparity[rp0]); |
|---|
| 343 | | - code[1] = |
|---|
| 344 | | - (invparity[rp15] << 7) | |
|---|
| 345 | | - (invparity[rp14] << 6) | |
|---|
| 346 | | - (invparity[rp13] << 5) | |
|---|
| 347 | | - (invparity[rp12] << 4) | |
|---|
| 348 | | - (invparity[rp11] << 3) | |
|---|
| 349 | | - (invparity[rp10] << 2) | |
|---|
| 350 | | - (invparity[rp9] << 1) | |
|---|
| 351 | | - (invparity[rp8]); |
|---|
| 352 | | -#else |
|---|
| 353 | | - code[1] = |
|---|
| 354 | | - (invparity[rp7] << 7) | |
|---|
| 355 | | - (invparity[rp6] << 6) | |
|---|
| 356 | | - (invparity[rp5] << 5) | |
|---|
| 357 | | - (invparity[rp4] << 4) | |
|---|
| 358 | | - (invparity[rp3] << 3) | |
|---|
| 359 | | - (invparity[rp2] << 2) | |
|---|
| 360 | | - (invparity[rp1] << 1) | |
|---|
| 361 | | - (invparity[rp0]); |
|---|
| 362 | | - code[0] = |
|---|
| 363 | | - (invparity[rp15] << 7) | |
|---|
| 364 | | - (invparity[rp14] << 6) | |
|---|
| 365 | | - (invparity[rp13] << 5) | |
|---|
| 366 | | - (invparity[rp12] << 4) | |
|---|
| 367 | | - (invparity[rp11] << 3) | |
|---|
| 368 | | - (invparity[rp10] << 2) | |
|---|
| 369 | | - (invparity[rp9] << 1) | |
|---|
| 370 | | - (invparity[rp8]); |
|---|
| 371 | | -#endif |
|---|
| 320 | + if (sm_order) { |
|---|
| 321 | + code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) | |
|---|
| 322 | + (invparity[rp5] << 5) | (invparity[rp4] << 4) | |
|---|
| 323 | + (invparity[rp3] << 3) | (invparity[rp2] << 2) | |
|---|
| 324 | + (invparity[rp1] << 1) | (invparity[rp0]); |
|---|
| 325 | + code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) | |
|---|
| 326 | + (invparity[rp13] << 5) | (invparity[rp12] << 4) | |
|---|
| 327 | + (invparity[rp11] << 3) | (invparity[rp10] << 2) | |
|---|
| 328 | + (invparity[rp9] << 1) | (invparity[rp8]); |
|---|
| 329 | + } else { |
|---|
| 330 | + code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) | |
|---|
| 331 | + (invparity[rp5] << 5) | (invparity[rp4] << 4) | |
|---|
| 332 | + (invparity[rp3] << 3) | (invparity[rp2] << 2) | |
|---|
| 333 | + (invparity[rp1] << 1) | (invparity[rp0]); |
|---|
| 334 | + code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) | |
|---|
| 335 | + (invparity[rp13] << 5) | (invparity[rp12] << 4) | |
|---|
| 336 | + (invparity[rp11] << 3) | (invparity[rp10] << 2) | |
|---|
| 337 | + (invparity[rp9] << 1) | (invparity[rp8]); |
|---|
| 338 | + } |
|---|
| 339 | + |
|---|
| 372 | 340 | if (eccsize_mult == 1) |
|---|
| 373 | 341 | code[2] = |
|---|
| 374 | 342 | (invparity[par & 0xf0] << 7) | |
|---|
| .. | .. |
|---|
| 394 | 362 | /** |
|---|
| 395 | 363 | * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte |
|---|
| 396 | 364 | * block |
|---|
| 397 | | - * @mtd: MTD block structure |
|---|
| 365 | + * @chip: NAND chip object |
|---|
| 398 | 366 | * @buf: input buffer with raw data |
|---|
| 399 | 367 | * @code: output buffer with ECC |
|---|
| 400 | 368 | */ |
|---|
| 401 | | -int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, |
|---|
| 369 | +int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf, |
|---|
| 402 | 370 | unsigned char *code) |
|---|
| 403 | 371 | { |
|---|
| 404 | | - __nand_calculate_ecc(buf, |
|---|
| 405 | | - mtd_to_nand(mtd)->ecc.size, code); |
|---|
| 372 | + bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER; |
|---|
| 373 | + |
|---|
| 374 | + __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order); |
|---|
| 406 | 375 | |
|---|
| 407 | 376 | return 0; |
|---|
| 408 | 377 | } |
|---|
| .. | .. |
|---|
| 414 | 383 | * @read_ecc: ECC from the chip |
|---|
| 415 | 384 | * @calc_ecc: the ECC calculated from raw data |
|---|
| 416 | 385 | * @eccsize: data bytes per ECC step (256 or 512) |
|---|
| 386 | + * @sm_order: Smart Media byte order |
|---|
| 417 | 387 | * |
|---|
| 418 | 388 | * Detect and correct a 1 bit error for eccsize byte block |
|---|
| 419 | 389 | */ |
|---|
| 420 | 390 | int __nand_correct_data(unsigned char *buf, |
|---|
| 421 | 391 | unsigned char *read_ecc, unsigned char *calc_ecc, |
|---|
| 422 | | - unsigned int eccsize) |
|---|
| 392 | + unsigned int eccsize, bool sm_order) |
|---|
| 423 | 393 | { |
|---|
| 424 | 394 | unsigned char b0, b1, b2, bit_addr; |
|---|
| 425 | 395 | unsigned int byte_addr; |
|---|
| .. | .. |
|---|
| 431 | 401 | * we might need the xor result more than once, |
|---|
| 432 | 402 | * so keep them in a local var |
|---|
| 433 | 403 | */ |
|---|
| 434 | | -#ifdef CONFIG_MTD_NAND_ECC_SMC |
|---|
| 435 | | - b0 = read_ecc[0] ^ calc_ecc[0]; |
|---|
| 436 | | - b1 = read_ecc[1] ^ calc_ecc[1]; |
|---|
| 437 | | -#else |
|---|
| 438 | | - b0 = read_ecc[1] ^ calc_ecc[1]; |
|---|
| 439 | | - b1 = read_ecc[0] ^ calc_ecc[0]; |
|---|
| 440 | | -#endif |
|---|
| 404 | + if (sm_order) { |
|---|
| 405 | + b0 = read_ecc[0] ^ calc_ecc[0]; |
|---|
| 406 | + b1 = read_ecc[1] ^ calc_ecc[1]; |
|---|
| 407 | + } else { |
|---|
| 408 | + b0 = read_ecc[1] ^ calc_ecc[1]; |
|---|
| 409 | + b1 = read_ecc[0] ^ calc_ecc[0]; |
|---|
| 410 | + } |
|---|
| 411 | + |
|---|
| 441 | 412 | b2 = read_ecc[2] ^ calc_ecc[2]; |
|---|
| 442 | 413 | |
|---|
| 443 | 414 | /* check if there are any bitfaults */ |
|---|
| .. | .. |
|---|
| 491 | 462 | |
|---|
| 492 | 463 | /** |
|---|
| 493 | 464 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) |
|---|
| 494 | | - * @mtd: MTD block structure |
|---|
| 465 | + * @chip: NAND chip object |
|---|
| 495 | 466 | * @buf: raw data read from the chip |
|---|
| 496 | 467 | * @read_ecc: ECC from the chip |
|---|
| 497 | 468 | * @calc_ecc: the ECC calculated from raw data |
|---|
| 498 | 469 | * |
|---|
| 499 | 470 | * Detect and correct a 1 bit error for 256/512 byte block |
|---|
| 500 | 471 | */ |
|---|
| 501 | | -int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, |
|---|
| 472 | +int nand_correct_data(struct nand_chip *chip, unsigned char *buf, |
|---|
| 502 | 473 | unsigned char *read_ecc, unsigned char *calc_ecc) |
|---|
| 503 | 474 | { |
|---|
| 504 | | - return __nand_correct_data(buf, read_ecc, calc_ecc, |
|---|
| 505 | | - mtd_to_nand(mtd)->ecc.size); |
|---|
| 475 | + bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER; |
|---|
| 476 | + |
|---|
| 477 | + return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size, |
|---|
| 478 | + sm_order); |
|---|
| 506 | 479 | } |
|---|
| 507 | 480 | EXPORT_SYMBOL(nand_correct_data); |
|---|
| 508 | 481 | |
|---|