nand_ecc.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  drivers/mtd/nand_ecc.c
  3.  *
  4.  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
  5.  *                     Toshiba America Electronics Components, Inc.
  6.  *
  7.  * $Id: nand_ecc.c,v 1.7 2002/03/21 14:13:50 dwmw2 Exp $
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License version 2 as
  11.  * published by the Free Software Foundation.
  12.  *
  13.  * This file contains an ECC algorithm from Toshiba that detects and
  14.  * corrects 1 bit errors in a 256 byte block of data.
  15.  */
  16. #include <linux/types.h>
  17. #include <linux/kernel.h>
  18. #include <linux/module.h>
  19. /*
  20.  * Pre-calculated 256-way 1 byte column parity
  21.  */
  22. static const u_char nand_ecc_precalc_table[] = {
  23. 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
  24. 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  25. 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  26. 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  27. 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  28. 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  29. 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  30. 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  31. 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  32. 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  33. 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  34. 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  35. 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  36. 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  37. 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  38. 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
  39. };
  40. /*
  41.  * Creates non-inverted ECC code from line parity
  42.  */
  43. static void nand_trans_result(u_char reg2, u_char reg3,
  44. u_char *ecc_code)
  45. {
  46. u_char a, b, i, tmp1, tmp2;
  47. /* Initialize variables */
  48. a = b = 0x80;
  49. tmp1 = tmp2 = 0;
  50. /* Calculate first ECC byte */
  51. for (i = 0; i < 4; i++) {
  52. if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
  53. tmp1 |= b;
  54. b >>= 1;
  55. if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
  56. tmp1 |= b;
  57. b >>= 1;
  58. a >>= 1;
  59. }
  60. /* Calculate second ECC byte */
  61. b = 0x80;
  62. for (i = 0; i < 4; i++) {
  63. if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
  64. tmp2 |= b;
  65. b >>= 1;
  66. if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
  67. tmp2 |= b;
  68. b >>= 1;
  69. a >>= 1;
  70. }
  71. /* Store two of the ECC bytes */
  72. ecc_code[0] = tmp1;
  73. ecc_code[1] = tmp2;
  74. }
  75. /*
  76.  * Calculate 3 byte ECC code for 256 byte block
  77.  */
  78. void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
  79. {
  80. u_char idx, reg1, reg2, reg3;
  81. int j;
  82. /* Initialize variables */
  83. reg1 = reg2 = reg3 = 0;
  84. ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
  85. /* Build up column parity */ 
  86. for(j = 0; j < 256; j++) {
  87. /* Get CP0 - CP5 from table */
  88. idx = nand_ecc_precalc_table[dat[j]];
  89. reg1 ^= (idx & 0x3f);
  90. /* All bit XOR = 1 ? */
  91. if (idx & 0x40) {
  92. reg3 ^= (u_char) j;
  93. reg2 ^= ~((u_char) j);
  94. }
  95. }
  96. /* Create non-inverted ECC code from line parity */
  97. nand_trans_result(reg2, reg3, ecc_code);
  98. /* Calculate final ECC code */
  99. ecc_code[0] = ~ecc_code[0];
  100. ecc_code[1] = ~ecc_code[1];
  101. ecc_code[2] = ((~reg1) << 2) | 0x03;
  102. }
  103. /*
  104.  * Detect and correct a 1 bit error for 256 byte block
  105.  */
  106. int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
  107. {
  108. u_char a, b, c, d1, d2, d3, add, bit, i;
  109. /* Do error detection */ 
  110. d1 = calc_ecc[0] ^ read_ecc[0];
  111. d2 = calc_ecc[1] ^ read_ecc[1];
  112. d3 = calc_ecc[2] ^ read_ecc[2];
  113. if ((d1 | d2 | d3) == 0) {
  114. /* No errors */
  115. return 0;
  116. }
  117. else {
  118. a = (d1 ^ (d1 >> 1)) & 0x55;
  119. b = (d2 ^ (d2 >> 1)) & 0x55;
  120. c = (d3 ^ (d3 >> 1)) & 0x54;
  121. /* Found and will correct single bit error in the data */
  122. if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
  123. c = 0x80;
  124. add = 0;
  125. a = 0x80;
  126. for (i=0; i<4; i++) {
  127. if (d1 & c)
  128. add |= a;
  129. c >>= 2;
  130. a >>= 1;
  131. }
  132. c = 0x80;
  133. for (i=0; i<4; i++) {
  134. if (d2 & c)
  135. add |= a;
  136. c >>= 2;
  137. a >>= 1;
  138. }
  139. bit = 0;
  140. b = 0x04;
  141. c = 0x80;
  142. for (i=0; i<3; i++) {
  143. if (d3 & c)
  144. bit |= b;
  145. c >>= 2;
  146. b >>= 1;
  147. }
  148. b = 0x01;
  149. a = dat[add];
  150. a ^= (b << bit);
  151. dat[add] = a;
  152. return 1;
  153. }
  154. else {
  155. i = 0;
  156. while (d1) {
  157. if (d1 & 0x01)
  158. ++i;
  159. d1 >>= 1;
  160. }
  161. while (d2) {
  162. if (d2 & 0x01)
  163. ++i;
  164. d2 >>= 1;
  165. }
  166. while (d3) {
  167. if (d3 & 0x01)
  168. ++i;
  169. d3 >>= 1;
  170. }
  171. if (i == 1) {
  172. /* ECC Code Error Correction */
  173. read_ecc[0] = calc_ecc[0];
  174. read_ecc[1] = calc_ecc[1];
  175. read_ecc[2] = calc_ecc[2];
  176. return 2;
  177. }
  178. else {
  179. /* Uncorrectable Error */
  180. return -1;
  181. }
  182. }
  183. }
  184. /* Should never happen */
  185. return -1;
  186. }
  187. EXPORT_SYMBOL(nand_calculate_ecc);
  188. EXPORT_SYMBOL(nand_correct_data);
  189. MODULE_LICENSE("GPL");
  190. MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>");
  191. MODULE_DESCRIPTION("Generic NAND ECC support");