/* error correcting code for nand flash */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "nandecc.h" #define CORRECTABLEMASK 0x545555 static uchar ecctab[] = { 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, }; ulong nandecc(uchar *buf) { int cp, zeros, ones, im, lp, om, i; cp = 0xff; zeros = 0xff; ones = 0xff; for (i = 0; i < 256; i++) { int tabent = ecctab[buf[i]]; cp ^= tabent; if (tabent & 1) { zeros ^= ~i; ones ^= i; } } lp = 0; for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) { if (ones & im) lp |= om; om >>= 1; if (zeros & im) lp |= om; } return (((cp & 0xff) | 3) << 16) | lp; } NandEccError nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad) { ulong xorecc, mask; int k; if (calcecc == *storedecc) return NandEccErrorGood; if (reportbad) print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n", calcecc, *storedecc); xorecc = calcecc ^ *storedecc; if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) { ulong imask; ushort out, omask; int line, col; for (imask = 0x800000, omask = 0x800, out = 0; imask; imask >>= 2, omask >>= 1) if (xorecc & imask) out |= omask; line = out & 0xff; col = out >> 9; if (reportbad) print("nandecccorrect: single bit error line %d col %d\n", line, col); buf[line] ^= (1 << col); *storedecc = calcecc; return NandEccErrorOneBit; } for (mask = 0x800000, k = 0; mask; mask >>= 1) if (mask & xorecc) k++; if (k == 1) { if (reportbad) print("nandecccorrect: single bit error in ecc\n"); /* assume the stored ecc was wrong */ *storedecc = calcecc; return NandEccErrorOneBitInEcc; } if (reportbad) print("nandecccorrect: 2 bit error\n"); return NandEccErrorBad; }