aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap2/gpmc.c184
-rw-r--r--arch/arm/plat-omap/include/plat/gpmc.h11
2 files changed, 195 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 00d510858e28..1ca8d7fd625a 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -49,6 +49,7 @@
49#define GPMC_ECC_CONTROL 0x1f8 49#define GPMC_ECC_CONTROL 0x1f8
50#define GPMC_ECC_SIZE_CONFIG 0x1fc 50#define GPMC_ECC_SIZE_CONFIG 0x1fc
51#define GPMC_ECC1_RESULT 0x200 51#define GPMC_ECC1_RESULT 0x200
52#define GPMC_ECC_BCH_RESULT_0 0x240 /* not available on OMAP2 */
52 53
53#define GPMC_CS0_OFFSET 0x60 54#define GPMC_CS0_OFFSET 0x60
54#define GPMC_CS_SIZE 0x30 55#define GPMC_CS_SIZE 0x30
@@ -920,3 +921,186 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
920 return 0; 921 return 0;
921} 922}
922EXPORT_SYMBOL_GPL(gpmc_calculate_ecc); 923EXPORT_SYMBOL_GPL(gpmc_calculate_ecc);
924
925#ifdef CONFIG_ARCH_OMAP3
926
927/**
928 * gpmc_init_hwecc_bch - initialize hardware BCH ecc functionality
929 * @cs: chip select number
930 * @nsectors: how many 512-byte sectors to process
931 * @nerrors: how many errors to correct per sector (4 or 8)
932 *
933 * This function must be executed before any call to gpmc_enable_hwecc_bch.
934 */
935int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors)
936{
937 /* check if ecc module is in use */
938 if (gpmc_ecc_used != -EINVAL)
939 return -EINVAL;
940
941 /* support only OMAP3 class */
942 if (!cpu_is_omap34xx()) {
943 printk(KERN_ERR "BCH ecc is not supported on this CPU\n");
944 return -EINVAL;
945 }
946
947 /*
948 * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1.
949 * Other chips may be added if confirmed to work.
950 */
951 if ((nerrors == 4) &&
952 (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) {
953 printk(KERN_ERR "BCH 4-bit mode is not supported on this CPU\n");
954 return -EINVAL;
955 }
956
957 /* sanity check */
958 if (nsectors > 8) {
959 printk(KERN_ERR "BCH cannot process %d sectors (max is 8)\n",
960 nsectors);
961 return -EINVAL;
962 }
963
964 return 0;
965}
966EXPORT_SYMBOL_GPL(gpmc_init_hwecc_bch);
967
968/**
969 * gpmc_enable_hwecc_bch - enable hardware BCH ecc functionality
970 * @cs: chip select number
971 * @mode: read/write mode
972 * @dev_width: device bus width(1 for x16, 0 for x8)
973 * @nsectors: how many 512-byte sectors to process
974 * @nerrors: how many errors to correct per sector (4 or 8)
975 */
976int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors,
977 int nerrors)
978{
979 unsigned int val;
980
981 /* check if ecc module is in use */
982 if (gpmc_ecc_used != -EINVAL)
983 return -EINVAL;
984
985 gpmc_ecc_used = cs;
986
987 /* clear ecc and enable bits */
988 gpmc_write_reg(GPMC_ECC_CONTROL, 0x1);
989
990 /*
991 * When using BCH, sector size is hardcoded to 512 bytes.
992 * Here we are using wrapping mode 6 both for reading and writing, with:
993 * size0 = 0 (no additional protected byte in spare area)
994 * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
995 */
996 gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, (32 << 22) | (0 << 12));
997
998 /* BCH configuration */
999 val = ((1 << 16) | /* enable BCH */
1000 (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */
1001 (0x06 << 8) | /* wrap mode = 6 */
1002 (dev_width << 7) | /* bus width */
1003 (((nsectors-1) & 0x7) << 4) | /* number of sectors */
1004 (cs << 1) | /* ECC CS */
1005 (0x1)); /* enable ECC */
1006
1007 gpmc_write_reg(GPMC_ECC_CONFIG, val);
1008 gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
1009 return 0;
1010}
1011EXPORT_SYMBOL_GPL(gpmc_enable_hwecc_bch);
1012
1013/**
1014 * gpmc_calculate_ecc_bch4 - Generate 7 ecc bytes per sector of 512 data bytes
1015 * @cs: chip select number
1016 * @dat: The pointer to data on which ecc is computed
1017 * @ecc: The ecc output buffer
1018 */
1019int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc)
1020{
1021 int i;
1022 unsigned long nsectors, reg, val1, val2;
1023
1024 if (gpmc_ecc_used != cs)
1025 return -EINVAL;
1026
1027 nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1;
1028
1029 for (i = 0; i < nsectors; i++) {
1030
1031 reg = GPMC_ECC_BCH_RESULT_0 + 16*i;
1032
1033 /* Read hw-computed remainder */
1034 val1 = gpmc_read_reg(reg + 0);
1035 val2 = gpmc_read_reg(reg + 4);
1036
1037 /*
1038 * Add constant polynomial to remainder, in order to get an ecc
1039 * sequence of 0xFFs for a buffer filled with 0xFFs; and
1040 * left-justify the resulting polynomial.
1041 */
1042 *ecc++ = 0x28 ^ ((val2 >> 12) & 0xFF);
1043 *ecc++ = 0x13 ^ ((val2 >> 4) & 0xFF);
1044 *ecc++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF));
1045 *ecc++ = 0x39 ^ ((val1 >> 20) & 0xFF);
1046 *ecc++ = 0x96 ^ ((val1 >> 12) & 0xFF);
1047 *ecc++ = 0xac ^ ((val1 >> 4) & 0xFF);
1048 *ecc++ = 0x7f ^ ((val1 & 0xF) << 4);
1049 }
1050
1051 gpmc_ecc_used = -EINVAL;
1052 return 0;
1053}
1054EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch4);
1055
1056/**
1057 * gpmc_calculate_ecc_bch8 - Generate 13 ecc bytes per block of 512 data bytes
1058 * @cs: chip select number
1059 * @dat: The pointer to data on which ecc is computed
1060 * @ecc: The ecc output buffer
1061 */
1062int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc)
1063{
1064 int i;
1065 unsigned long nsectors, reg, val1, val2, val3, val4;
1066
1067 if (gpmc_ecc_used != cs)
1068 return -EINVAL;
1069
1070 nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1;
1071
1072 for (i = 0; i < nsectors; i++) {
1073
1074 reg = GPMC_ECC_BCH_RESULT_0 + 16*i;
1075
1076 /* Read hw-computed remainder */
1077 val1 = gpmc_read_reg(reg + 0);
1078 val2 = gpmc_read_reg(reg + 4);
1079 val3 = gpmc_read_reg(reg + 8);
1080 val4 = gpmc_read_reg(reg + 12);
1081
1082 /*
1083 * Add constant polynomial to remainder, in order to get an ecc
1084 * sequence of 0xFFs for a buffer filled with 0xFFs.
1085 */
1086 *ecc++ = 0xef ^ (val4 & 0xFF);
1087 *ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF);
1088 *ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF);
1089 *ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF);
1090 *ecc++ = 0xed ^ (val3 & 0xFF);
1091 *ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF);
1092 *ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF);
1093 *ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
1094 *ecc++ = 0x97 ^ (val2 & 0xFF);
1095 *ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF);
1096 *ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
1097 *ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF);
1098 *ecc++ = 0xb5 ^ (val1 & 0xFF);
1099 }
1100
1101 gpmc_ecc_used = -EINVAL;
1102 return 0;
1103}
1104EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch8);
1105
1106#endif /* CONFIG_ARCH_OMAP3 */
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 1527929b445a..f37764a36072 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -92,6 +92,8 @@ enum omap_ecc {
92 OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */ 92 OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
93 /* 1-bit ecc: stored at beginning of spare area as romcode */ 93 /* 1-bit ecc: stored at beginning of spare area as romcode */
94 OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */ 94 OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
95 OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */
96 OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
95}; 97};
96 98
97/* 99/*
@@ -157,4 +159,13 @@ extern int gpmc_nand_write(int cs, int cmd, int wval);
157 159
158int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size); 160int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size);
159int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code); 161int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
162
163#ifdef CONFIG_ARCH_OMAP3
164int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors);
165int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors,
166 int nerrors);
167int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc);
168int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc);
169#endif /* CONFIG_ARCH_OMAP3 */
170
160#endif 171#endif