106f6463aSDavid du Colombier /* error correcting code for nand flash */
206f6463aSDavid du Colombier #include "u.h"
306f6463aSDavid du Colombier #include "../port/lib.h"
406f6463aSDavid du Colombier #include "mem.h"
506f6463aSDavid du Colombier #include "dat.h"
606f6463aSDavid du Colombier #include "fns.h"
706f6463aSDavid du Colombier #include "io.h"
806f6463aSDavid du Colombier #include "../port/error.h"
906f6463aSDavid du Colombier #include "nandecc.h"
1006f6463aSDavid du Colombier
1106f6463aSDavid du Colombier #define CORRECTABLEMASK 0x545555
1206f6463aSDavid du Colombier
1306f6463aSDavid du Colombier static uchar ecctab[] = {
1406f6463aSDavid du Colombier 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
1506f6463aSDavid du Colombier 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
1606f6463aSDavid du Colombier 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
1706f6463aSDavid du Colombier 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
1806f6463aSDavid du Colombier 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
1906f6463aSDavid du Colombier 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
2006f6463aSDavid du Colombier 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
2106f6463aSDavid du Colombier 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
2206f6463aSDavid du Colombier 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
2306f6463aSDavid du Colombier 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
2406f6463aSDavid du Colombier 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
2506f6463aSDavid du Colombier 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
2606f6463aSDavid du Colombier 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
2706f6463aSDavid du Colombier 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
2806f6463aSDavid du Colombier 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
2906f6463aSDavid du Colombier 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
3006f6463aSDavid du Colombier 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
3106f6463aSDavid du Colombier 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
3206f6463aSDavid du Colombier 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
3306f6463aSDavid du Colombier 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
3406f6463aSDavid du Colombier 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
3506f6463aSDavid du Colombier 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
3606f6463aSDavid du Colombier 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
3706f6463aSDavid du Colombier 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
3806f6463aSDavid du Colombier 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
3906f6463aSDavid du Colombier 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
4006f6463aSDavid du Colombier 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
4106f6463aSDavid du Colombier 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
4206f6463aSDavid du Colombier 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
4306f6463aSDavid du Colombier 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
4406f6463aSDavid du Colombier 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
4506f6463aSDavid du Colombier 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
4606f6463aSDavid du Colombier };
4706f6463aSDavid du Colombier
4806f6463aSDavid du Colombier ulong
nandecc(uchar * buf)4906f6463aSDavid du Colombier nandecc(uchar *buf)
5006f6463aSDavid du Colombier {
5106f6463aSDavid du Colombier int cp, zeros, ones, im, lp, om, i;
5206f6463aSDavid du Colombier
5306f6463aSDavid du Colombier cp = 0xff;
5406f6463aSDavid du Colombier zeros = 0xff;
5506f6463aSDavid du Colombier ones = 0xff;
5606f6463aSDavid du Colombier for (i = 0; i < 256; i++) {
5706f6463aSDavid du Colombier int tabent = ecctab[buf[i]];
5806f6463aSDavid du Colombier
5906f6463aSDavid du Colombier cp ^= tabent;
6006f6463aSDavid du Colombier if (tabent & 1) {
6106f6463aSDavid du Colombier zeros ^= ~i;
6206f6463aSDavid du Colombier ones ^= i;
6306f6463aSDavid du Colombier }
6406f6463aSDavid du Colombier }
6506f6463aSDavid du Colombier lp = 0;
6606f6463aSDavid du Colombier for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
6706f6463aSDavid du Colombier if (ones & im)
6806f6463aSDavid du Colombier lp |= om;
6906f6463aSDavid du Colombier om >>= 1;
7006f6463aSDavid du Colombier if (zeros & im)
7106f6463aSDavid du Colombier lp |= om;
7206f6463aSDavid du Colombier }
7306f6463aSDavid du Colombier return (((cp & 0xff) | 3) << 16) | lp;
7406f6463aSDavid du Colombier }
7506f6463aSDavid du Colombier
7606f6463aSDavid du Colombier NandEccError
nandecccorrect(uchar * buf,ulong calcecc,ulong * storedecc,int reportbad)7706f6463aSDavid du Colombier nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
7806f6463aSDavid du Colombier {
7906f6463aSDavid du Colombier ulong xorecc, mask;
8006f6463aSDavid du Colombier int k;
8106f6463aSDavid du Colombier
8206f6463aSDavid du Colombier if (calcecc == *storedecc)
8306f6463aSDavid du Colombier return NandEccErrorGood;
8406f6463aSDavid du Colombier if (reportbad)
8506f6463aSDavid du Colombier print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n",
8606f6463aSDavid du Colombier calcecc, *storedecc);
8706f6463aSDavid du Colombier xorecc = calcecc ^ *storedecc;
8806f6463aSDavid du Colombier if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
8906f6463aSDavid du Colombier ulong imask;
9006f6463aSDavid du Colombier ushort out, omask;
9106f6463aSDavid du Colombier int line, col;
9206f6463aSDavid du Colombier
9306f6463aSDavid du Colombier for (imask = 0x800000, omask = 0x800, out = 0; imask;
9406f6463aSDavid du Colombier imask >>= 2, omask >>= 1)
9506f6463aSDavid du Colombier if (xorecc & imask)
9606f6463aSDavid du Colombier out |= omask;
9706f6463aSDavid du Colombier line = out & 0xff;
9806f6463aSDavid du Colombier col = out >> 9;
9906f6463aSDavid du Colombier if (reportbad)
10006f6463aSDavid du Colombier print("nandecccorrect: single bit error line %d col %d\n",
10106f6463aSDavid du Colombier line, col);
10206f6463aSDavid du Colombier buf[line] ^= (1 << col);
10306f6463aSDavid du Colombier *storedecc = calcecc;
10406f6463aSDavid du Colombier return NandEccErrorOneBit;
10506f6463aSDavid du Colombier }
10606f6463aSDavid du Colombier for (mask = 0x800000, k = 0; mask; mask >>= 1)
10706f6463aSDavid du Colombier if (mask & xorecc)
10806f6463aSDavid du Colombier k++;
10906f6463aSDavid du Colombier if (k == 1) {
11006f6463aSDavid du Colombier if (reportbad)
11106f6463aSDavid du Colombier print("nandecccorrect: single bit error in ecc\n");
112*bbcdcb7cSDavid du Colombier /* assume the stored ecc was wrong */
11306f6463aSDavid du Colombier *storedecc = calcecc;
11406f6463aSDavid du Colombier return NandEccErrorOneBitInEcc;
11506f6463aSDavid du Colombier }
11606f6463aSDavid du Colombier if (reportbad)
11706f6463aSDavid du Colombier print("nandecccorrect: 2 bit error\n");
11806f6463aSDavid du Colombier return NandEccErrorBad;
11906f6463aSDavid du Colombier }
120