diff options
author | Roger Quadros | 2023-11-24 16:22:18 -0600 |
---|---|---|
committer | Praneeth Bajjuri | 2023-11-24 16:54:00 -0600 |
commit | c0176ab8dd53f86e193c578ec4781400e9fb18e3 (patch) | |
tree | 3d485cd0562fa58dcb58d08cbda47a834b535460 | |
parent | 2d30da97edd3fab245e01986f91ceb34655903e0 (diff) | |
download | ti-u-boot-c0176ab8dd53f86e193c578ec4781400e9fb18e3.tar.gz ti-u-boot-c0176ab8dd53f86e193c578ec4781400e9fb18e3.tar.xz ti-u-boot-c0176ab8dd53f86e193c578ec4781400e9fb18e3.zip |
mtd: nand: omap_gpmc: Fix NAND in SPL for AM335x
AM335x uses a special driver "am335x_spl_bch.c" as SPL
NAND loader. This driver expects 1 sector at a time ECC
and doesn't work well with multi-sector ECC that was implemented
in commit 04fcd2587321.
Switch back to 1 sector at a time read/ECC.
Fixes: 04fcd2587321 ("mtd: rawnand: omap_gpmc: Fix BCH6/16 HW based correction")
Signed-off-by: Roger Quadros <rogerq@kernel.org>
-rw-r--r-- | drivers/mtd/nand/raw/omap_gpmc.c | 96 |
1 files changed, 30 insertions, 66 deletions
diff --git a/drivers/mtd/nand/raw/omap_gpmc.c b/drivers/mtd/nand/raw/omap_gpmc.c index 43f7363b9dd..fc8383d84b4 100644 --- a/drivers/mtd/nand/raw/omap_gpmc.c +++ b/drivers/mtd/nand/raw/omap_gpmc.c | |||
@@ -293,7 +293,7 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, | |||
293 | break; | 293 | break; |
294 | case OMAP_ECC_BCH8_CODE_HW: | 294 | case OMAP_ECC_BCH8_CODE_HW: |
295 | bch_type = 1; | 295 | bch_type = 1; |
296 | nsectors = chip->ecc.steps; | 296 | nsectors = 1; |
297 | if (mode == NAND_ECC_READ) { | 297 | if (mode == NAND_ECC_READ) { |
298 | wr_mode = BCH_WRAPMODE_1; | 298 | wr_mode = BCH_WRAPMODE_1; |
299 | ecc_size0 = BCH8R_ECC_SIZE0; | 299 | ecc_size0 = BCH8R_ECC_SIZE0; |
@@ -306,7 +306,7 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, | |||
306 | break; | 306 | break; |
307 | case OMAP_ECC_BCH16_CODE_HW: | 307 | case OMAP_ECC_BCH16_CODE_HW: |
308 | bch_type = 0x2; | 308 | bch_type = 0x2; |
309 | nsectors = chip->ecc.steps; | 309 | nsectors = 1; |
310 | if (mode == NAND_ECC_READ) { | 310 | if (mode == NAND_ECC_READ) { |
311 | wr_mode = 0x01; | 311 | wr_mode = 0x01; |
312 | ecc_size0 = 52; /* ECC bits in nibbles per sector */ | 312 | ecc_size0 = 52; /* ECC bits in nibbles per sector */ |
@@ -345,17 +345,16 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, | |||
345 | } | 345 | } |
346 | 346 | ||
347 | /** | 347 | /** |
348 | * _omap_calculate_ecc_bch - Generate BCH ECC bytes for one sector | 348 | * omap_calculate_ecc_bch - Generate BCH ECC bytes for one sector |
349 | * @mtd: MTD device structure | 349 | * @mtd: MTD device structure |
350 | * @dat: The pointer to data on which ecc is computed | 350 | * @dat: The pointer to data on which ecc is computed |
351 | * @ecc_code: The ecc_code buffer | 351 | * @ecc_code: The ecc_code buffer |
352 | * @sector: The sector number (for a multi sector page) | ||
353 | * | 352 | * |
354 | * Support calculating of BCH4/8/16 ECC vectors for one sector | 353 | * Support calculating of BCH4/8/16 ECC vectors for one sector |
355 | * within a page. Sector number is in @sector. | 354 | * within a page. Sector number is in @sector. |
356 | */ | 355 | */ |
357 | static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat, | 356 | static int omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat, |
358 | u8 *ecc_code, int sector) | 357 | u8 *ecc_code) |
359 | { | 358 | { |
360 | struct nand_chip *chip = mtd_to_nand(mtd); | 359 | struct nand_chip *chip = mtd_to_nand(mtd); |
361 | struct omap_nand_info *info = nand_get_controller_data(chip); | 360 | struct omap_nand_info *info = nand_get_controller_data(chip); |
@@ -368,7 +367,7 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat, | |||
368 | case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: | 367 | case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: |
369 | #endif | 368 | #endif |
370 | case OMAP_ECC_BCH8_CODE_HW: | 369 | case OMAP_ECC_BCH8_CODE_HW: |
371 | ptr = &gpmc_cfg->bch_result_0_3[sector].bch_result_x[3]; | 370 | ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3]; |
372 | val = readl(ptr); | 371 | val = readl(ptr); |
373 | ecc_code[i++] = (val >> 0) & 0xFF; | 372 | ecc_code[i++] = (val >> 0) & 0xFF; |
374 | ptr--; | 373 | ptr--; |
@@ -383,21 +382,21 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat, | |||
383 | 382 | ||
384 | break; | 383 | break; |
385 | case OMAP_ECC_BCH16_CODE_HW: | 384 | case OMAP_ECC_BCH16_CODE_HW: |
386 | val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[2]); | 385 | val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]); |
387 | ecc_code[i++] = (val >> 8) & 0xFF; | 386 | ecc_code[i++] = (val >> 8) & 0xFF; |
388 | ecc_code[i++] = (val >> 0) & 0xFF; | 387 | ecc_code[i++] = (val >> 0) & 0xFF; |
389 | val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[1]); | 388 | val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]); |
390 | ecc_code[i++] = (val >> 24) & 0xFF; | 389 | ecc_code[i++] = (val >> 24) & 0xFF; |
391 | ecc_code[i++] = (val >> 16) & 0xFF; | 390 | ecc_code[i++] = (val >> 16) & 0xFF; |
392 | ecc_code[i++] = (val >> 8) & 0xFF; | 391 | ecc_code[i++] = (val >> 8) & 0xFF; |
393 | ecc_code[i++] = (val >> 0) & 0xFF; | 392 | ecc_code[i++] = (val >> 0) & 0xFF; |
394 | val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[0]); | 393 | val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]); |
395 | ecc_code[i++] = (val >> 24) & 0xFF; | 394 | ecc_code[i++] = (val >> 24) & 0xFF; |
396 | ecc_code[i++] = (val >> 16) & 0xFF; | 395 | ecc_code[i++] = (val >> 16) & 0xFF; |
397 | ecc_code[i++] = (val >> 8) & 0xFF; | 396 | ecc_code[i++] = (val >> 8) & 0xFF; |
398 | ecc_code[i++] = (val >> 0) & 0xFF; | 397 | ecc_code[i++] = (val >> 0) & 0xFF; |
399 | for (j = 3; j >= 0; j--) { | 398 | for (j = 3; j >= 0; j--) { |
400 | val = readl(&gpmc_cfg->bch_result_0_3[sector].bch_result_x[j] | 399 | val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j] |
401 | ); | 400 | ); |
402 | ecc_code[i++] = (val >> 24) & 0xFF; | 401 | ecc_code[i++] = (val >> 24) & 0xFF; |
403 | ecc_code[i++] = (val >> 16) & 0xFF; | 402 | ecc_code[i++] = (val >> 16) & 0xFF; |
@@ -431,22 +430,6 @@ static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat, | |||
431 | return 0; | 430 | return 0; |
432 | } | 431 | } |
433 | 432 | ||
434 | /** | ||
435 | * omap_calculate_ecc_bch - ECC generator for 1 sector | ||
436 | * @mtd: MTD device structure | ||
437 | * @dat: The pointer to data on which ecc is computed | ||
438 | * @ecc_code: The ecc_code buffer | ||
439 | * | ||
440 | * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used | ||
441 | * when SW based correction is required as ECC is required for one sector | ||
442 | * at a time. | ||
443 | */ | ||
444 | static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, | ||
445 | const u_char *dat, u_char *ecc_calc) | ||
446 | { | ||
447 | return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0); | ||
448 | } | ||
449 | |||
450 | static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | 433 | static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
451 | { | 434 | { |
452 | struct nand_chip *chip = mtd_to_nand(mtd); | 435 | struct nand_chip *chip = mtd_to_nand(mtd); |
@@ -572,34 +555,6 @@ static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len) | |||
572 | 555 | ||
573 | #ifdef CONFIG_NAND_OMAP_ELM | 556 | #ifdef CONFIG_NAND_OMAP_ELM |
574 | 557 | ||
575 | /** | ||
576 | * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors | ||
577 | * @mtd: MTD device structure | ||
578 | * @dat: The pointer to data on which ecc is computed | ||
579 | * @ecc_code: The ecc_code buffer | ||
580 | * | ||
581 | * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go. | ||
582 | */ | ||
583 | static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd, | ||
584 | const u_char *dat, u_char *ecc_calc) | ||
585 | { | ||
586 | struct nand_chip *chip = mtd_to_nand(mtd); | ||
587 | int eccbytes = chip->ecc.bytes; | ||
588 | unsigned long nsectors; | ||
589 | int i, ret; | ||
590 | |||
591 | nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1; | ||
592 | for (i = 0; i < nsectors; i++) { | ||
593 | ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i); | ||
594 | if (ret) | ||
595 | return ret; | ||
596 | |||
597 | ecc_calc += eccbytes; | ||
598 | } | ||
599 | |||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | /* | 558 | /* |
604 | * omap_reverse_list - re-orders list elements in reverse order [internal] | 559 | * omap_reverse_list - re-orders list elements in reverse order [internal] |
605 | * @list: pointer to start of list | 560 | * @list: pointer to start of list |
@@ -752,32 +707,38 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, | |||
752 | { | 707 | { |
753 | int i, eccsize = chip->ecc.size; | 708 | int i, eccsize = chip->ecc.size; |
754 | int eccbytes = chip->ecc.bytes; | 709 | int eccbytes = chip->ecc.bytes; |
755 | int ecctotal = chip->ecc.total; | ||
756 | int eccsteps = chip->ecc.steps; | 710 | int eccsteps = chip->ecc.steps; |
757 | uint8_t *p = buf; | 711 | uint8_t *p = buf; |
758 | uint8_t *ecc_calc = chip->buffers->ecccalc; | 712 | uint8_t *ecc_calc = chip->buffers->ecccalc; |
759 | uint8_t *ecc_code = chip->buffers->ecccode; | 713 | uint8_t *ecc_code = chip->buffers->ecccode; |
760 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 714 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
761 | uint8_t *oob = chip->oob_poi; | 715 | uint8_t *oob = chip->oob_poi; |
716 | uint32_t data_pos; | ||
762 | uint32_t oob_pos; | 717 | uint32_t oob_pos; |
763 | 718 | ||
719 | data_pos = 0; | ||
764 | /* oob area start */ | 720 | /* oob area start */ |
765 | oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0]; | 721 | oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0]; |
766 | oob += chip->ecc.layout->eccpos[0]; | 722 | oob += chip->ecc.layout->eccpos[0]; |
767 | 723 | ||
768 | /* Enable ECC engine */ | 724 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, |
769 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | 725 | oob += eccbytes) { |
726 | /* Enable ECC engine */ | ||
727 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | ||
770 | 728 | ||
771 | /* read entire page */ | 729 | /* read data */ |
772 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); | 730 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1); |
773 | chip->read_buf(mtd, buf, mtd->writesize); | 731 | chip->read_buf(mtd, p, eccsize); |
774 | 732 | ||
775 | /* read all ecc bytes from oob area */ | 733 | /* read respective ecc from oob area */ |
776 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1); | 734 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1); |
777 | chip->read_buf(mtd, oob, ecctotal); | 735 | chip->read_buf(mtd, oob, eccbytes); |
736 | /* read syndrome */ | ||
737 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | ||
778 | 738 | ||
779 | /* Calculate ecc bytes */ | 739 | data_pos += eccsize; |
780 | omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc); | 740 | oob_pos += eccbytes; |
741 | } | ||
781 | 742 | ||
782 | for (i = 0; i < chip->ecc.total; i++) | 743 | for (i = 0; i < chip->ecc.total; i++) |
783 | ecc_code[i] = chip->oob_poi[eccpos[i]]; | 744 | ecc_code[i] = chip->oob_poi[eccpos[i]]; |
@@ -945,6 +906,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, | |||
945 | nand->ecc.hwctl = omap_enable_hwecc_bch; | 906 | nand->ecc.hwctl = omap_enable_hwecc_bch; |
946 | nand->ecc.correct = omap_correct_data_bch_sw; | 907 | nand->ecc.correct = omap_correct_data_bch_sw; |
947 | nand->ecc.calculate = omap_calculate_ecc_bch; | 908 | nand->ecc.calculate = omap_calculate_ecc_bch; |
909 | nand->ecc.steps = eccsteps; | ||
948 | /* define ecc-layout */ | 910 | /* define ecc-layout */ |
949 | ecclayout->eccbytes = nand->ecc.bytes * eccsteps; | 911 | ecclayout->eccbytes = nand->ecc.bytes * eccsteps; |
950 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | 912 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; |
@@ -987,6 +949,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, | |||
987 | nand->ecc.correct = omap_correct_data_bch; | 949 | nand->ecc.correct = omap_correct_data_bch; |
988 | nand->ecc.calculate = omap_calculate_ecc_bch; | 950 | nand->ecc.calculate = omap_calculate_ecc_bch; |
989 | nand->ecc.read_page = omap_read_page_bch; | 951 | nand->ecc.read_page = omap_read_page_bch; |
952 | nand->ecc.steps = eccsteps; | ||
990 | /* define ecc-layout */ | 953 | /* define ecc-layout */ |
991 | ecclayout->eccbytes = nand->ecc.bytes * eccsteps; | 954 | ecclayout->eccbytes = nand->ecc.bytes * eccsteps; |
992 | for (i = 0; i < ecclayout->eccbytes; i++) | 955 | for (i = 0; i < ecclayout->eccbytes; i++) |
@@ -1020,6 +983,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, | |||
1020 | nand->ecc.correct = omap_correct_data_bch; | 983 | nand->ecc.correct = omap_correct_data_bch; |
1021 | nand->ecc.calculate = omap_calculate_ecc_bch; | 984 | nand->ecc.calculate = omap_calculate_ecc_bch; |
1022 | nand->ecc.read_page = omap_read_page_bch; | 985 | nand->ecc.read_page = omap_read_page_bch; |
986 | nand->ecc.steps = eccsteps; | ||
1023 | /* define ecc-layout */ | 987 | /* define ecc-layout */ |
1024 | ecclayout->eccbytes = nand->ecc.bytes * eccsteps; | 988 | ecclayout->eccbytes = nand->ecc.bytes * eccsteps; |
1025 | for (i = 0; i < ecclayout->eccbytes; i++) | 989 | for (i = 0; i < ecclayout->eccbytes; i++) |