aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoger Quadros2023-11-24 16:22:18 -0600
committerPraneeth Bajjuri2023-11-24 16:54:00 -0600
commitc0176ab8dd53f86e193c578ec4781400e9fb18e3 (patch)
tree3d485cd0562fa58dcb58d08cbda47a834b535460
parent2d30da97edd3fab245e01986f91ceb34655903e0 (diff)
downloadti-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.c96
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 */
357static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat, 356static 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 */
444static 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
450static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) 433static 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 */
583static 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++)