blob: 53aee60e390d8d0c7f8253a4feac3b1009bdbd57 [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001#include <linux/mtd/zftl_ecc.h>
2#include <linux/bitops.h>
3
4
5
6static const unsigned char column_parity_table[] = {
7 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
8 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
9 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
10 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
11 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
12 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
13 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
14 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
15 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
16 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
17 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
18 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
19 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
20 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
21 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
22 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
23 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
24 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
25 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
26 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
27 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
28 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
29 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
30 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
31 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
32 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
33 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
34 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
35 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
36 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
37 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
38 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
39};
40
41
42void zftl_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
43 struct zftl_ecc_other *ecc_other)
44{
45 unsigned int i;
46
47 unsigned char col_parity = 0;
48 unsigned line_parity = 0;
49 unsigned line_parity_prime = 0;
50 unsigned char b;
51
52 for (i = 0; i < n_bytes; i++) {
53 b = column_parity_table[*data++];
54 col_parity ^= b;
55
56 if (b & 0x01) {
57 /* odd number of bits in the byte */
58 line_parity ^= i;
59 line_parity_prime ^= ~i;
60 }
61
62 }
63
64 ecc_other->col_parity = (col_parity >> 2) & 0x3f;
65 ecc_other->line_parity = line_parity;
66 ecc_other->line_parity_prime = line_parity_prime;
67}
68
69int zftl_ecc_correct_other(unsigned char *data, unsigned n_bytes,
70 struct zftl_ecc_other *read_ecc,
71 const struct zftl_ecc_other *test_ecc)
72{
73 unsigned char delta_col; /* column parity delta */
74 unsigned delta_line; /* line parity delta */
75 unsigned delta_line_prime; /* line parity delta */
76 unsigned bit;
77
78 delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
79 delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
80 delta_line_prime =
81 read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
82
83 if ((delta_col | delta_line | delta_line_prime) == 0)
84 return 0; /* no error */
85
86 if (delta_line == ~delta_line_prime &&
87 (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
88 /* Single bit (recoverable) error in data */
89
90 bit = 0;
91
92 if (delta_col & 0x20)
93 bit |= 0x04;
94 if (delta_col & 0x08)
95 bit |= 0x02;
96 if (delta_col & 0x02)
97 bit |= 0x01;
98
99 if (delta_line >= n_bytes)
100 return -1;
101
102 data[delta_line] ^= (1 << bit);
103
104 return 1; /* corrected */
105 }
106
107 if ((hweight32(delta_line) +
108 hweight32(delta_line_prime) +
109 hweight8(delta_col)) == 1) {
110 /* Reccoverable error in ecc */
111
112 *read_ecc = *test_ecc;
113 return 1; /* corrected */
114 }
115
116 /* Unrecoverable error */
117
118 return -1;
119}