Commit 04c001b04e6fac072523490e263f2ec148092a31
Committed by
Hebbar, Gururaja
1 parent
5b31cb2cd1
Exists in
master
arm:omap:nand - Enable BCH8 support
1. BCH8 ECC support is enabled. 2. Support for BCH8 error correction using ELM module is added. 3. ECC positions updated for BCH8 in synchronized with U-boot. 4. Corrected GPMC settings for BCH8 ECC scheme. Signed-off-by: Philip, Avinash <avinashphilip@ti.com> Signed-off-by: Hebbar, Gururaja <gururaja.hebbar@ti.com>
Showing 3 changed files with 132 additions and 10 deletions Side-by-side Diff
arch/arm/mach-omap2/board-flash.c
... | ... | @@ -148,7 +148,7 @@ |
148 | 148 | board_nand_data.gpmc_irq = OMAP_GPMC_IRQ_BASE + cs; |
149 | 149 | |
150 | 150 | if (cpu_is_am335x()) { |
151 | - board_nand_data.ecc_opt = OMAP_ECC_HAMMING_CODE_HW; | |
151 | + board_nand_data.ecc_opt = OMAP_ECC_BCH8_CODE_HW; | |
152 | 152 | board_nand_data.xfer_type = NAND_OMAP_PREFETCH_POLLED; |
153 | 153 | } |
154 | 154 |
arch/arm/mach-omap2/gpmc.c
... | ... | @@ -863,9 +863,9 @@ |
863 | 863 | bch_mod = 0; |
864 | 864 | bch_wrapmode = 0x09; |
865 | 865 | } else if (ecc_type == OMAP_ECC_BCH8_CODE_HW) { |
866 | - eccsize1 = 0x1A; eccsize0 = 0x18; | |
866 | + eccsize1 = 0x2; eccsize0 = 0x1A; | |
867 | 867 | bch_mod = 1; |
868 | - bch_wrapmode = 0x04; | |
868 | + bch_wrapmode = 0x01; | |
869 | 869 | } else |
870 | 870 | eccsize1 = ((ecc_size >> 1) - 1); |
871 | 871 | break; |
872 | 872 | |
873 | 873 | |
... | ... | @@ -875,13 +875,13 @@ |
875 | 875 | |
876 | 876 | case GPMC_ECC_WRITE: |
877 | 877 | if (ecc_type == OMAP_ECC_BCH4_CODE_HW) { |
878 | - eccsize1 = 0x20; eccsize0 = 0x00; | |
878 | + eccsize1 = 0x1c; eccsize0 = 0x0; | |
879 | 879 | bch_mod = 0; |
880 | 880 | bch_wrapmode = 0x06; |
881 | 881 | } else if (ecc_type == OMAP_ECC_BCH8_CODE_HW) { |
882 | - eccsize1 = 0x20; eccsize0 = 0x00; | |
882 | + eccsize1 = 0x1c; eccsize0 = 0x00; | |
883 | 883 | bch_mod = 1; |
884 | - bch_wrapmode = 0x06; | |
884 | + bch_wrapmode = 0x01; | |
885 | 885 | } else |
886 | 886 | eccsize1 = ((ecc_size >> 1) - 1); |
887 | 887 | break; |
... | ... | @@ -898,7 +898,7 @@ |
898 | 898 | ecc_size_conf_val = (eccsize1 << 22) | (eccsize0 << 12); |
899 | 899 | ecc_conf_val = ((0x01 << 16) | (bch_mod << 12) |
900 | 900 | | (bch_wrapmode << 8) | (dev_width << 7) |
901 | - | (0x03 << 4) | (cs << 1) | (0x1)); | |
901 | + | (0x00 << 4) | (cs << 1) | (0x1)); | |
902 | 902 | } else { |
903 | 903 | gpmc_write_reg(GPMC_ECC_CONTROL, 0x00000101); |
904 | 904 | ecc_size_conf_val = (eccsize1 << 22) | 0x0000000F; |
... | ... | @@ -936,7 +936,7 @@ |
936 | 936 | |
937 | 937 | if ((ecc_type == OMAP_ECC_BCH4_CODE_HW) || |
938 | 938 | (ecc_type == OMAP_ECC_BCH8_CODE_HW)) { |
939 | - for (i = 0; i < 4; i++) { | |
939 | + for (i = 0; i < 1; i++) { | |
940 | 940 | /* |
941 | 941 | * Reading HW ECC_BCH_Results |
942 | 942 | * 0x240-0x24C, 0x250-0x25C, 0x260-0x26C, 0x270-0x27C |
drivers/mtd/nand/omap2.c
... | ... | @@ -23,10 +23,15 @@ |
23 | 23 | #include <plat/dma.h> |
24 | 24 | #include <plat/gpmc.h> |
25 | 25 | #include <plat/nand.h> |
26 | +#include <plat/elm.h> | |
26 | 27 | |
27 | 28 | #define DRIVER_NAME "omap2-nand" |
28 | 29 | #define OMAP_NAND_TIMEOUT_MS 5000 |
29 | 30 | |
31 | +#define BCH8_ECC_BYTES (512) | |
32 | +#define BCH8_ECC_OOB_BYTES (13) | |
33 | +#define BCH8_ECC_MAX ((BCH8_ECC_BYTES + BCH8_ECC_OOB_BYTES) * 8) | |
34 | + | |
30 | 35 | #define NAND_Ecc_P1e (1 << 0) |
31 | 36 | #define NAND_Ecc_P2e (1 << 1) |
32 | 37 | #define NAND_Ecc_P4e (1 << 2) |
... | ... | @@ -96,6 +101,8 @@ |
96 | 101 | |
97 | 102 | #define MAX_HWECC_BYTES_OOB_64 24 |
98 | 103 | #define JFFS2_CLEAN_MARKER_OFFSET 0x2 |
104 | +#define BCH_ECC_POS 0x2 | |
105 | +#define BCH_JFFS2_CLEAN_MARKER_OFFSET 0x36 | |
99 | 106 | |
100 | 107 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
101 | 108 | |
... | ... | @@ -790,6 +797,73 @@ |
790 | 797 | } |
791 | 798 | |
792 | 799 | /** |
800 | + * omap_read_page_bch - BCH ecc based page read function | |
801 | + * @mtd: mtd info structure | |
802 | + * @chip: nand chip info structure | |
803 | + * @buf: buffer to store read data | |
804 | + * @page: page number to read | |
805 | + * | |
806 | + * For BCH syndrome calculation and error correction using ELM module. | |
807 | + * Syndrome calculation is surpressed for reading of non page aligned length | |
808 | + */ | |
809 | +static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, | |
810 | + uint8_t *buf, int page) | |
811 | +{ | |
812 | + int i, eccsize = chip->ecc.size; | |
813 | + int eccbytes = chip->ecc.bytes; | |
814 | + int eccsteps = chip->ecc.steps; | |
815 | + uint8_t *p = buf; | |
816 | + uint8_t *ecc_calc = chip->buffers->ecccalc; | |
817 | + uint8_t *ecc_code = chip->buffers->ecccode; | |
818 | + uint32_t *eccpos = chip->ecc.layout->eccpos; | |
819 | + uint8_t *oob = chip->oob_poi; | |
820 | + uint32_t data_pos; | |
821 | + uint32_t oob_pos; | |
822 | + | |
823 | + data_pos = 0; | |
824 | + /* oob area start */ | |
825 | + oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0]; | |
826 | + | |
827 | + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, | |
828 | + oob += eccbytes) { | |
829 | + chip->ecc.hwctl(mtd, NAND_ECC_READ); | |
830 | + /* read data */ | |
831 | + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page); | |
832 | + chip->read_buf(mtd, p, eccsize); | |
833 | + | |
834 | + /* read respective ecc from oob area */ | |
835 | + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page); | |
836 | + chip->read_buf(mtd, oob, eccbytes); | |
837 | + /* read syndrome */ | |
838 | + chip->ecc.calculate(mtd, p, &ecc_calc[i]); | |
839 | + | |
840 | + data_pos += eccsize; | |
841 | + oob_pos += eccbytes; | |
842 | + } | |
843 | + | |
844 | + for (i = 0; i < chip->ecc.total; i++) | |
845 | + ecc_code[i] = chip->oob_poi[eccpos[i]]; | |
846 | + | |
847 | + eccsteps = chip->ecc.steps; | |
848 | + p = buf; | |
849 | + | |
850 | + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | |
851 | + int stat; | |
852 | + | |
853 | + if (!(chip->ops.len & 0x7ff)) { | |
854 | + stat = chip->ecc.correct(mtd, p, &ecc_code[i], | |
855 | + &ecc_calc[i]); | |
856 | + | |
857 | + if (stat < 0) | |
858 | + mtd->ecc_stats.failed++; | |
859 | + else | |
860 | + mtd->ecc_stats.corrected += stat; | |
861 | + } | |
862 | + } | |
863 | + return 0; | |
864 | +} | |
865 | + | |
866 | +/** | |
793 | 867 | * omap_correct_data - Compares the ECC read with HW generated ECC |
794 | 868 | * @mtd: MTD device structure |
795 | 869 | * @dat: page data |
... | ... | @@ -873,6 +947,47 @@ |
873 | 947 | dat += 512; |
874 | 948 | } |
875 | 949 | break; |
950 | + case OMAP_ECC_BCH8_CODE_HW: | |
951 | + eccsize = BCH8_ECC_OOB_BYTES; | |
952 | + | |
953 | + for (i = 0; i < blockCnt; i++) { | |
954 | + eccflag = 0; | |
955 | + /* check if area is flashed */ | |
956 | + for (j = 0; (j < eccsize) && (eccflag == 0); j++) | |
957 | + if (read_ecc[j] != 0xFF) | |
958 | + eccflag = 1; | |
959 | + | |
960 | + if (eccflag == 1) { | |
961 | + eccflag = 0; | |
962 | + /* check if any ecc error */ | |
963 | + for (j = 0; (j < eccsize) && (eccflag == 0); | |
964 | + j++) | |
965 | + if (calc_ecc[j] != 0) | |
966 | + eccflag = 1; | |
967 | + } | |
968 | + | |
969 | + count = 0; | |
970 | + if (eccflag == 1) | |
971 | + count = elm_decode_bch_error(0, calc_ecc, | |
972 | + err_loc); | |
973 | + | |
974 | + for (j = 0; j < count; j++) { | |
975 | + u32 bit_pos, byte_pos; | |
976 | + | |
977 | + bit_pos = err_loc[j] % 8; | |
978 | + byte_pos = (BCH8_ECC_MAX - err_loc[j] - 1) / 8; | |
979 | + if (err_loc[j] < BCH8_ECC_MAX) | |
980 | + dat[byte_pos] ^= | |
981 | + 1 << bit_pos; | |
982 | + /* else, not interested to correct ecc */ | |
983 | + } | |
984 | + | |
985 | + stat += count; | |
986 | + calc_ecc = calc_ecc + eccsize; | |
987 | + read_ecc = read_ecc + eccsize; | |
988 | + dat += BCH8_ECC_BYTES; | |
989 | + } | |
990 | + break; | |
876 | 991 | } |
877 | 992 | return stat; |
878 | 993 | } |
... | ... | @@ -1111,8 +1226,9 @@ |
1111 | 1226 | info->nand.ecc.bytes = 4*7; |
1112 | 1227 | info->nand.ecc.size = 4*512; |
1113 | 1228 | } else if (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW) { |
1114 | - info->nand.ecc.bytes = 13; | |
1115 | - info->nand.ecc.size = 4*512; | |
1229 | + info->nand.ecc.bytes = 13; | |
1230 | + info->nand.ecc.size = 512; | |
1231 | + info->nand.ecc.read_page = omap_read_page_bch; | |
1116 | 1232 | } else { |
1117 | 1233 | info->nand.ecc.bytes = 3; |
1118 | 1234 | info->nand.ecc.size = 512; |
... | ... | @@ -1155,6 +1271,12 @@ |
1155 | 1271 | offset + omap_oobinfo.eccbytes; |
1156 | 1272 | omap_oobinfo.oobfree->length = info->mtd.oobsize - |
1157 | 1273 | (offset + omap_oobinfo.eccbytes); |
1274 | + } else if (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW) { | |
1275 | + offset = BCH_ECC_POS; /* Synchronize with U-boot */ | |
1276 | + omap_oobinfo.oobfree->offset = | |
1277 | + BCH_JFFS2_CLEAN_MARKER_OFFSET; | |
1278 | + omap_oobinfo.oobfree->length = info->mtd.oobsize - | |
1279 | + offset - omap_oobinfo.eccbytes; | |
1158 | 1280 | } else { |
1159 | 1281 | omap_oobinfo.oobfree->offset = offset; |
1160 | 1282 | omap_oobinfo.oobfree->length = info->mtd.oobsize - |