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