ecc.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /* error correcting code for nand flash */
  2. #include "u.h"
  3. #include "../port/lib.h"
  4. #include "mem.h"
  5. #include "dat.h"
  6. #include "fns.h"
  7. #include "io.h"
  8. #include "../port/error.h"
  9. #include "nandecc.h"
  10. #define CORRECTABLEMASK 0x545555
  11. static uchar ecctab[] = {
  12. 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
  13. 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
  14. 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
  15. 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
  16. 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
  17. 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
  18. 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
  19. 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
  20. 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
  21. 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
  22. 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
  23. 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
  24. 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
  25. 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
  26. 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
  27. 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
  28. 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
  29. 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
  30. 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
  31. 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
  32. 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
  33. 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
  34. 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
  35. 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
  36. 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
  37. 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
  38. 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
  39. 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
  40. 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
  41. 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
  42. 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
  43. 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
  44. };
  45. ulong
  46. nandecc(uchar *buf)
  47. {
  48. int cp, zeros, ones, im, lp, om, i;
  49. cp = 0xff;
  50. zeros = 0xff;
  51. ones = 0xff;
  52. for (i = 0; i < 256; i++) {
  53. int tabent = ecctab[buf[i]];
  54. cp ^= tabent;
  55. if (tabent & 1) {
  56. zeros ^= ~i;
  57. ones ^= i;
  58. }
  59. }
  60. lp = 0;
  61. for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
  62. if (ones & im)
  63. lp |= om;
  64. om >>= 1;
  65. if (zeros & im)
  66. lp |= om;
  67. }
  68. return (((cp & 0xff) | 3) << 16) | lp;
  69. }
  70. NandEccError
  71. nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
  72. {
  73. ulong xorecc, mask;
  74. int k;
  75. if (calcecc == *storedecc)
  76. return NandEccErrorGood;
  77. if (reportbad)
  78. print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n",
  79. calcecc, *storedecc);
  80. xorecc = calcecc ^ *storedecc;
  81. if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
  82. ulong imask;
  83. ushort out, omask;
  84. int line, col;
  85. for (imask = 0x800000, omask = 0x800, out = 0; imask;
  86. imask >>= 2, omask >>= 1)
  87. if (xorecc & imask)
  88. out |= omask;
  89. line = out & 0xff;
  90. col = out >> 9;
  91. if (reportbad)
  92. print("nandecccorrect: single bit error line %d col %d\n",
  93. line, col);
  94. buf[line] ^= (1 << col);
  95. *storedecc = calcecc;
  96. return NandEccErrorOneBit;
  97. }
  98. for (mask = 0x800000, k = 0; mask; mask >>= 1)
  99. if (mask & xorecc)
  100. k++;
  101. if (k == 1) {
  102. if (reportbad)
  103. print("nandecccorrect: single bit error in ecc\n");
  104. /* assume the stored ecc was wrong */
  105. *storedecc = calcecc;
  106. return NandEccErrorOneBitInEcc;
  107. }
  108. if (reportbad)
  109. print("nandecccorrect: 2 bit error\n");
  110. return NandEccErrorBad;
  111. }