Commit 04c001b04e6fac072523490e263f2ec148092a31

Authored by Philip, Avinash
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 -