/* 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" enum { Corrmask = 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, tabent; cp = 0xff; zeros = 0xff; ones = 0xff; for (i = 0; i < 256; i++) { 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) { int k, line, col; u16int out, omask; u32int xorecc, mask, imask; if (calcecc == *storedecc) return NandEccErrorGood; if (reportbad) print("nandecccorrect: calculated ecc %.6lux stored ecc %.6lux; ", calcecc, *storedecc); xorecc = calcecc ^ *storedecc; if (((xorecc ^ (xorecc >> 1)) & Corrmask) == Corrmask) { omask = 0x800; out = 0; for (imask = 0x800000; imask; imask >>= 2){ if (xorecc & imask) out |= omask; omask >>= 1; } 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; } k = 0; for (mask = 0x800000; 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; }