xref: /plan9/sys/src/9/port/ecc.c (revision bbcdcb7c8996d26fc1afbfaebd7a40f34bf2c28a)
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