xref: /linux/drivers/mtd/nand/ecc-sw-hamming.c (revision d8467112d645ec56760c78928e1e5a3f6faa9b74)
1e5acf9c8SMiquel Raynal // SPDX-License-Identifier: GPL-2.0-or-later
2e5acf9c8SMiquel Raynal /*
3e5acf9c8SMiquel Raynal  * This file contains an ECC algorithm that detects and corrects 1 bit
4e5acf9c8SMiquel Raynal  * errors in a 256 byte block of data.
5e5acf9c8SMiquel Raynal  *
6e5acf9c8SMiquel Raynal  * Copyright © 2008 Koninklijke Philips Electronics NV.
7e5acf9c8SMiquel Raynal  *                  Author: Frans Meulenbroeks
8e5acf9c8SMiquel Raynal  *
9e5acf9c8SMiquel Raynal  * Completely replaces the previous ECC implementation which was written by:
10e5acf9c8SMiquel Raynal  *   Steven J. Hill (sjhill@realitydiluted.com)
11e5acf9c8SMiquel Raynal  *   Thomas Gleixner (tglx@linutronix.de)
12e5acf9c8SMiquel Raynal  *
13e5acf9c8SMiquel Raynal  * Information on how this algorithm works and how it was developed
14e5acf9c8SMiquel Raynal  * can be found in Documentation/driver-api/mtd/nand_ecc.rst
15e5acf9c8SMiquel Raynal  */
16e5acf9c8SMiquel Raynal 
17e5acf9c8SMiquel Raynal #include <linux/types.h>
18e5acf9c8SMiquel Raynal #include <linux/kernel.h>
19e5acf9c8SMiquel Raynal #include <linux/module.h>
2035fe1b98SMiquel Raynal #include <linux/mtd/nand.h>
21e5acf9c8SMiquel Raynal #include <linux/mtd/nand-ecc-sw-hamming.h>
2235fe1b98SMiquel Raynal #include <linux/slab.h>
23e5acf9c8SMiquel Raynal #include <asm/byteorder.h>
24e5acf9c8SMiquel Raynal 
25e5acf9c8SMiquel Raynal /*
26e5acf9c8SMiquel Raynal  * invparity is a 256 byte table that contains the odd parity
27e5acf9c8SMiquel Raynal  * for each byte. So if the number of bits in a byte is even,
28e5acf9c8SMiquel Raynal  * the array element is 1, and when the number of bits is odd
29e5acf9c8SMiquel Raynal  * the array eleemnt is 0.
30e5acf9c8SMiquel Raynal  */
31e5acf9c8SMiquel Raynal static const char invparity[256] = {
32e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
33e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
34e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
35e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
36e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
37e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
38e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
39e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
40e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
41e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
42e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
43e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
44e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
45e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
46e5acf9c8SMiquel Raynal 	0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
47e5acf9c8SMiquel Raynal 	1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
48e5acf9c8SMiquel Raynal };
49e5acf9c8SMiquel Raynal 
50e5acf9c8SMiquel Raynal /*
51e5acf9c8SMiquel Raynal  * bitsperbyte contains the number of bits per byte
52e5acf9c8SMiquel Raynal  * this is only used for testing and repairing parity
53e5acf9c8SMiquel Raynal  * (a precalculated value slightly improves performance)
54e5acf9c8SMiquel Raynal  */
55e5acf9c8SMiquel Raynal static const char bitsperbyte[256] = {
56e5acf9c8SMiquel Raynal 	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
57e5acf9c8SMiquel Raynal 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
58e5acf9c8SMiquel Raynal 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
59e5acf9c8SMiquel Raynal 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
60e5acf9c8SMiquel Raynal 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
61e5acf9c8SMiquel Raynal 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
62e5acf9c8SMiquel Raynal 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
63e5acf9c8SMiquel Raynal 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
64e5acf9c8SMiquel Raynal 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
65e5acf9c8SMiquel Raynal 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
66e5acf9c8SMiquel Raynal 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
67e5acf9c8SMiquel Raynal 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
68e5acf9c8SMiquel Raynal 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
69e5acf9c8SMiquel Raynal 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
70e5acf9c8SMiquel Raynal 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
71e5acf9c8SMiquel Raynal 	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
72e5acf9c8SMiquel Raynal };
73e5acf9c8SMiquel Raynal 
74e5acf9c8SMiquel Raynal /*
75e5acf9c8SMiquel Raynal  * addressbits is a lookup table to filter out the bits from the xor-ed
76e5acf9c8SMiquel Raynal  * ECC data that identify the faulty location.
77e5acf9c8SMiquel Raynal  * this is only used for repairing parity
7890ccf0a0SMiquel Raynal  * see the comments in nand_ecc_sw_hamming_correct for more details
79e5acf9c8SMiquel Raynal  */
80e5acf9c8SMiquel Raynal static const char addressbits[256] = {
81e5acf9c8SMiquel Raynal 	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
82e5acf9c8SMiquel Raynal 	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
83e5acf9c8SMiquel Raynal 	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
84e5acf9c8SMiquel Raynal 	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
85e5acf9c8SMiquel Raynal 	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
86e5acf9c8SMiquel Raynal 	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
87e5acf9c8SMiquel Raynal 	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
88e5acf9c8SMiquel Raynal 	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
89e5acf9c8SMiquel Raynal 	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
90e5acf9c8SMiquel Raynal 	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
91e5acf9c8SMiquel Raynal 	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
92e5acf9c8SMiquel Raynal 	0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
93e5acf9c8SMiquel Raynal 	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
94e5acf9c8SMiquel Raynal 	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
95e5acf9c8SMiquel Raynal 	0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
96e5acf9c8SMiquel Raynal 	0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
97e5acf9c8SMiquel Raynal 	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
98e5acf9c8SMiquel Raynal 	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
99e5acf9c8SMiquel Raynal 	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
100e5acf9c8SMiquel Raynal 	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
101e5acf9c8SMiquel Raynal 	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
102e5acf9c8SMiquel Raynal 	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
103e5acf9c8SMiquel Raynal 	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
104e5acf9c8SMiquel Raynal 	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
105e5acf9c8SMiquel Raynal 	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
106e5acf9c8SMiquel Raynal 	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
107e5acf9c8SMiquel Raynal 	0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
108e5acf9c8SMiquel Raynal 	0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
109e5acf9c8SMiquel Raynal 	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
110e5acf9c8SMiquel Raynal 	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
111e5acf9c8SMiquel Raynal 	0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
112e5acf9c8SMiquel Raynal 	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
113e5acf9c8SMiquel Raynal };
114e5acf9c8SMiquel Raynal 
11590ccf0a0SMiquel Raynal int ecc_sw_hamming_calculate(const unsigned char *buf, unsigned int step_size,
116e5acf9c8SMiquel Raynal 			     unsigned char *code, bool sm_order)
117e5acf9c8SMiquel Raynal {
118b551fa30SMiquel Raynal 	const u32 *bp = (uint32_t *)buf;
1191771af5cSMiquel Raynal 	const u32 eccsize_mult = (step_size == 256) ? 1 : 2;
120b551fa30SMiquel Raynal 	/* current value in buffer */
121b551fa30SMiquel Raynal 	u32 cur;
122b551fa30SMiquel Raynal 	/* rp0..rp17 are the various accumulated parities (per byte) */
123b551fa30SMiquel Raynal 	u32 rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8, rp9, rp10, rp11, rp12,
124b551fa30SMiquel Raynal 		rp13, rp14, rp15, rp16, rp17;
125b551fa30SMiquel Raynal 	/* Cumulative parity for all data */
126b551fa30SMiquel Raynal 	u32 par;
127b551fa30SMiquel Raynal 	/* Cumulative parity at the end of the loop (rp12, rp14, rp16) */
128b551fa30SMiquel Raynal 	u32 tmppar;
129e5acf9c8SMiquel Raynal 	int i;
130e5acf9c8SMiquel Raynal 
131e5acf9c8SMiquel Raynal 	par = 0;
132e5acf9c8SMiquel Raynal 	rp4 = 0;
133e5acf9c8SMiquel Raynal 	rp6 = 0;
134e5acf9c8SMiquel Raynal 	rp8 = 0;
135e5acf9c8SMiquel Raynal 	rp10 = 0;
136e5acf9c8SMiquel Raynal 	rp12 = 0;
137e5acf9c8SMiquel Raynal 	rp14 = 0;
138e5acf9c8SMiquel Raynal 	rp16 = 0;
1391771af5cSMiquel Raynal 	rp17 = 0;
140e5acf9c8SMiquel Raynal 
141e5acf9c8SMiquel Raynal 	/*
142e5acf9c8SMiquel Raynal 	 * The loop is unrolled a number of times;
143e5acf9c8SMiquel Raynal 	 * This avoids if statements to decide on which rp value to update
144e5acf9c8SMiquel Raynal 	 * Also we process the data by longwords.
145e5acf9c8SMiquel Raynal 	 * Note: passing unaligned data might give a performance penalty.
146e5acf9c8SMiquel Raynal 	 * It is assumed that the buffers are aligned.
147e5acf9c8SMiquel Raynal 	 * tmppar is the cumulative sum of this iteration.
148e5acf9c8SMiquel Raynal 	 * needed for calculating rp12, rp14, rp16 and par
149e5acf9c8SMiquel Raynal 	 * also used as a performance improvement for rp6, rp8 and rp10
150e5acf9c8SMiquel Raynal 	 */
151e5acf9c8SMiquel Raynal 	for (i = 0; i < eccsize_mult << 2; i++) {
152e5acf9c8SMiquel Raynal 		cur = *bp++;
153e5acf9c8SMiquel Raynal 		tmppar = cur;
154e5acf9c8SMiquel Raynal 		rp4 ^= cur;
155e5acf9c8SMiquel Raynal 		cur = *bp++;
156e5acf9c8SMiquel Raynal 		tmppar ^= cur;
157e5acf9c8SMiquel Raynal 		rp6 ^= tmppar;
158e5acf9c8SMiquel Raynal 		cur = *bp++;
159e5acf9c8SMiquel Raynal 		tmppar ^= cur;
160e5acf9c8SMiquel Raynal 		rp4 ^= cur;
161e5acf9c8SMiquel Raynal 		cur = *bp++;
162e5acf9c8SMiquel Raynal 		tmppar ^= cur;
163e5acf9c8SMiquel Raynal 		rp8 ^= tmppar;
164e5acf9c8SMiquel Raynal 
165e5acf9c8SMiquel Raynal 		cur = *bp++;
166e5acf9c8SMiquel Raynal 		tmppar ^= cur;
167e5acf9c8SMiquel Raynal 		rp4 ^= cur;
168e5acf9c8SMiquel Raynal 		rp6 ^= cur;
169e5acf9c8SMiquel Raynal 		cur = *bp++;
170e5acf9c8SMiquel Raynal 		tmppar ^= cur;
171e5acf9c8SMiquel Raynal 		rp6 ^= cur;
172e5acf9c8SMiquel Raynal 		cur = *bp++;
173e5acf9c8SMiquel Raynal 		tmppar ^= cur;
174e5acf9c8SMiquel Raynal 		rp4 ^= cur;
175e5acf9c8SMiquel Raynal 		cur = *bp++;
176e5acf9c8SMiquel Raynal 		tmppar ^= cur;
177e5acf9c8SMiquel Raynal 		rp10 ^= tmppar;
178e5acf9c8SMiquel Raynal 
179e5acf9c8SMiquel Raynal 		cur = *bp++;
180e5acf9c8SMiquel Raynal 		tmppar ^= cur;
181e5acf9c8SMiquel Raynal 		rp4 ^= cur;
182e5acf9c8SMiquel Raynal 		rp6 ^= cur;
183e5acf9c8SMiquel Raynal 		rp8 ^= cur;
184e5acf9c8SMiquel Raynal 		cur = *bp++;
185e5acf9c8SMiquel Raynal 		tmppar ^= cur;
186e5acf9c8SMiquel Raynal 		rp6 ^= cur;
187e5acf9c8SMiquel Raynal 		rp8 ^= cur;
188e5acf9c8SMiquel Raynal 		cur = *bp++;
189e5acf9c8SMiquel Raynal 		tmppar ^= cur;
190e5acf9c8SMiquel Raynal 		rp4 ^= cur;
191e5acf9c8SMiquel Raynal 		rp8 ^= cur;
192e5acf9c8SMiquel Raynal 		cur = *bp++;
193e5acf9c8SMiquel Raynal 		tmppar ^= cur;
194e5acf9c8SMiquel Raynal 		rp8 ^= cur;
195e5acf9c8SMiquel Raynal 
196e5acf9c8SMiquel Raynal 		cur = *bp++;
197e5acf9c8SMiquel Raynal 		tmppar ^= cur;
198e5acf9c8SMiquel Raynal 		rp4 ^= cur;
199e5acf9c8SMiquel Raynal 		rp6 ^= cur;
200e5acf9c8SMiquel Raynal 		cur = *bp++;
201e5acf9c8SMiquel Raynal 		tmppar ^= cur;
202e5acf9c8SMiquel Raynal 		rp6 ^= cur;
203e5acf9c8SMiquel Raynal 		cur = *bp++;
204e5acf9c8SMiquel Raynal 		tmppar ^= cur;
205e5acf9c8SMiquel Raynal 		rp4 ^= cur;
206e5acf9c8SMiquel Raynal 		cur = *bp++;
207e5acf9c8SMiquel Raynal 		tmppar ^= cur;
208e5acf9c8SMiquel Raynal 
209e5acf9c8SMiquel Raynal 		par ^= tmppar;
210e5acf9c8SMiquel Raynal 		if ((i & 0x1) == 0)
211e5acf9c8SMiquel Raynal 			rp12 ^= tmppar;
212e5acf9c8SMiquel Raynal 		if ((i & 0x2) == 0)
213e5acf9c8SMiquel Raynal 			rp14 ^= tmppar;
214e5acf9c8SMiquel Raynal 		if (eccsize_mult == 2 && (i & 0x4) == 0)
215e5acf9c8SMiquel Raynal 			rp16 ^= tmppar;
216e5acf9c8SMiquel Raynal 	}
217e5acf9c8SMiquel Raynal 
218e5acf9c8SMiquel Raynal 	/*
219e5acf9c8SMiquel Raynal 	 * handle the fact that we use longword operations
220e5acf9c8SMiquel Raynal 	 * we'll bring rp4..rp14..rp16 back to single byte entities by
221e5acf9c8SMiquel Raynal 	 * shifting and xoring first fold the upper and lower 16 bits,
222e5acf9c8SMiquel Raynal 	 * then the upper and lower 8 bits.
223e5acf9c8SMiquel Raynal 	 */
224e5acf9c8SMiquel Raynal 	rp4 ^= (rp4 >> 16);
225e5acf9c8SMiquel Raynal 	rp4 ^= (rp4 >> 8);
226e5acf9c8SMiquel Raynal 	rp4 &= 0xff;
227e5acf9c8SMiquel Raynal 	rp6 ^= (rp6 >> 16);
228e5acf9c8SMiquel Raynal 	rp6 ^= (rp6 >> 8);
229e5acf9c8SMiquel Raynal 	rp6 &= 0xff;
230e5acf9c8SMiquel Raynal 	rp8 ^= (rp8 >> 16);
231e5acf9c8SMiquel Raynal 	rp8 ^= (rp8 >> 8);
232e5acf9c8SMiquel Raynal 	rp8 &= 0xff;
233e5acf9c8SMiquel Raynal 	rp10 ^= (rp10 >> 16);
234e5acf9c8SMiquel Raynal 	rp10 ^= (rp10 >> 8);
235e5acf9c8SMiquel Raynal 	rp10 &= 0xff;
236e5acf9c8SMiquel Raynal 	rp12 ^= (rp12 >> 16);
237e5acf9c8SMiquel Raynal 	rp12 ^= (rp12 >> 8);
238e5acf9c8SMiquel Raynal 	rp12 &= 0xff;
239e5acf9c8SMiquel Raynal 	rp14 ^= (rp14 >> 16);
240e5acf9c8SMiquel Raynal 	rp14 ^= (rp14 >> 8);
241e5acf9c8SMiquel Raynal 	rp14 &= 0xff;
242e5acf9c8SMiquel Raynal 	if (eccsize_mult == 2) {
243e5acf9c8SMiquel Raynal 		rp16 ^= (rp16 >> 16);
244e5acf9c8SMiquel Raynal 		rp16 ^= (rp16 >> 8);
245e5acf9c8SMiquel Raynal 		rp16 &= 0xff;
246e5acf9c8SMiquel Raynal 	}
247e5acf9c8SMiquel Raynal 
248e5acf9c8SMiquel Raynal 	/*
249e5acf9c8SMiquel Raynal 	 * we also need to calculate the row parity for rp0..rp3
250e5acf9c8SMiquel Raynal 	 * This is present in par, because par is now
251e5acf9c8SMiquel Raynal 	 * rp3 rp3 rp2 rp2 in little endian and
252e5acf9c8SMiquel Raynal 	 * rp2 rp2 rp3 rp3 in big endian
253e5acf9c8SMiquel Raynal 	 * as well as
254e5acf9c8SMiquel Raynal 	 * rp1 rp0 rp1 rp0 in little endian and
255e5acf9c8SMiquel Raynal 	 * rp0 rp1 rp0 rp1 in big endian
256e5acf9c8SMiquel Raynal 	 * First calculate rp2 and rp3
257e5acf9c8SMiquel Raynal 	 */
258e5acf9c8SMiquel Raynal #ifdef __BIG_ENDIAN
259e5acf9c8SMiquel Raynal 	rp2 = (par >> 16);
260e5acf9c8SMiquel Raynal 	rp2 ^= (rp2 >> 8);
261e5acf9c8SMiquel Raynal 	rp2 &= 0xff;
262e5acf9c8SMiquel Raynal 	rp3 = par & 0xffff;
263e5acf9c8SMiquel Raynal 	rp3 ^= (rp3 >> 8);
264e5acf9c8SMiquel Raynal 	rp3 &= 0xff;
265e5acf9c8SMiquel Raynal #else
266e5acf9c8SMiquel Raynal 	rp3 = (par >> 16);
267e5acf9c8SMiquel Raynal 	rp3 ^= (rp3 >> 8);
268e5acf9c8SMiquel Raynal 	rp3 &= 0xff;
269e5acf9c8SMiquel Raynal 	rp2 = par & 0xffff;
270e5acf9c8SMiquel Raynal 	rp2 ^= (rp2 >> 8);
271e5acf9c8SMiquel Raynal 	rp2 &= 0xff;
272e5acf9c8SMiquel Raynal #endif
273e5acf9c8SMiquel Raynal 
274e5acf9c8SMiquel Raynal 	/* reduce par to 16 bits then calculate rp1 and rp0 */
275e5acf9c8SMiquel Raynal 	par ^= (par >> 16);
276e5acf9c8SMiquel Raynal #ifdef __BIG_ENDIAN
277e5acf9c8SMiquel Raynal 	rp0 = (par >> 8) & 0xff;
278e5acf9c8SMiquel Raynal 	rp1 = (par & 0xff);
279e5acf9c8SMiquel Raynal #else
280e5acf9c8SMiquel Raynal 	rp1 = (par >> 8) & 0xff;
281e5acf9c8SMiquel Raynal 	rp0 = (par & 0xff);
282e5acf9c8SMiquel Raynal #endif
283e5acf9c8SMiquel Raynal 
284e5acf9c8SMiquel Raynal 	/* finally reduce par to 8 bits */
285e5acf9c8SMiquel Raynal 	par ^= (par >> 8);
286e5acf9c8SMiquel Raynal 	par &= 0xff;
287e5acf9c8SMiquel Raynal 
288e5acf9c8SMiquel Raynal 	/*
289e5acf9c8SMiquel Raynal 	 * and calculate rp5..rp15..rp17
290e5acf9c8SMiquel Raynal 	 * note that par = rp4 ^ rp5 and due to the commutative property
291e5acf9c8SMiquel Raynal 	 * of the ^ operator we can say:
292e5acf9c8SMiquel Raynal 	 * rp5 = (par ^ rp4);
293e5acf9c8SMiquel Raynal 	 * The & 0xff seems superfluous, but benchmarking learned that
294e5acf9c8SMiquel Raynal 	 * leaving it out gives slightly worse results. No idea why, probably
295e5acf9c8SMiquel Raynal 	 * it has to do with the way the pipeline in pentium is organized.
296e5acf9c8SMiquel Raynal 	 */
297e5acf9c8SMiquel Raynal 	rp5 = (par ^ rp4) & 0xff;
298e5acf9c8SMiquel Raynal 	rp7 = (par ^ rp6) & 0xff;
299e5acf9c8SMiquel Raynal 	rp9 = (par ^ rp8) & 0xff;
300e5acf9c8SMiquel Raynal 	rp11 = (par ^ rp10) & 0xff;
301e5acf9c8SMiquel Raynal 	rp13 = (par ^ rp12) & 0xff;
302e5acf9c8SMiquel Raynal 	rp15 = (par ^ rp14) & 0xff;
303e5acf9c8SMiquel Raynal 	if (eccsize_mult == 2)
304e5acf9c8SMiquel Raynal 		rp17 = (par ^ rp16) & 0xff;
305e5acf9c8SMiquel Raynal 
306e5acf9c8SMiquel Raynal 	/*
307e5acf9c8SMiquel Raynal 	 * Finally calculate the ECC bits.
308e5acf9c8SMiquel Raynal 	 * Again here it might seem that there are performance optimisations
309e5acf9c8SMiquel Raynal 	 * possible, but benchmarks showed that on the system this is developed
310e5acf9c8SMiquel Raynal 	 * the code below is the fastest
311e5acf9c8SMiquel Raynal 	 */
312e5acf9c8SMiquel Raynal 	if (sm_order) {
313e5acf9c8SMiquel Raynal 		code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
314e5acf9c8SMiquel Raynal 			  (invparity[rp5] << 5) | (invparity[rp4] << 4) |
315e5acf9c8SMiquel Raynal 			  (invparity[rp3] << 3) | (invparity[rp2] << 2) |
316e5acf9c8SMiquel Raynal 			  (invparity[rp1] << 1) | (invparity[rp0]);
317e5acf9c8SMiquel Raynal 		code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
318e5acf9c8SMiquel Raynal 			  (invparity[rp13] << 5) | (invparity[rp12] << 4) |
319e5acf9c8SMiquel Raynal 			  (invparity[rp11] << 3) | (invparity[rp10] << 2) |
320e5acf9c8SMiquel Raynal 			  (invparity[rp9] << 1) | (invparity[rp8]);
321e5acf9c8SMiquel Raynal 	} else {
322e5acf9c8SMiquel Raynal 		code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
323e5acf9c8SMiquel Raynal 			  (invparity[rp5] << 5) | (invparity[rp4] << 4) |
324e5acf9c8SMiquel Raynal 			  (invparity[rp3] << 3) | (invparity[rp2] << 2) |
325e5acf9c8SMiquel Raynal 			  (invparity[rp1] << 1) | (invparity[rp0]);
326e5acf9c8SMiquel Raynal 		code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
327e5acf9c8SMiquel Raynal 			  (invparity[rp13] << 5) | (invparity[rp12] << 4) |
328e5acf9c8SMiquel Raynal 			  (invparity[rp11] << 3) | (invparity[rp10] << 2) |
329e5acf9c8SMiquel Raynal 			  (invparity[rp9] << 1) | (invparity[rp8]);
330e5acf9c8SMiquel Raynal 	}
331e5acf9c8SMiquel Raynal 
332e5acf9c8SMiquel Raynal 	if (eccsize_mult == 1)
333e5acf9c8SMiquel Raynal 		code[2] =
334e5acf9c8SMiquel Raynal 		    (invparity[par & 0xf0] << 7) |
335e5acf9c8SMiquel Raynal 		    (invparity[par & 0x0f] << 6) |
336e5acf9c8SMiquel Raynal 		    (invparity[par & 0xcc] << 5) |
337e5acf9c8SMiquel Raynal 		    (invparity[par & 0x33] << 4) |
338e5acf9c8SMiquel Raynal 		    (invparity[par & 0xaa] << 3) |
339e5acf9c8SMiquel Raynal 		    (invparity[par & 0x55] << 2) |
340e5acf9c8SMiquel Raynal 		    3;
341e5acf9c8SMiquel Raynal 	else
342e5acf9c8SMiquel Raynal 		code[2] =
343e5acf9c8SMiquel Raynal 		    (invparity[par & 0xf0] << 7) |
344e5acf9c8SMiquel Raynal 		    (invparity[par & 0x0f] << 6) |
345e5acf9c8SMiquel Raynal 		    (invparity[par & 0xcc] << 5) |
346e5acf9c8SMiquel Raynal 		    (invparity[par & 0x33] << 4) |
347e5acf9c8SMiquel Raynal 		    (invparity[par & 0xaa] << 3) |
348e5acf9c8SMiquel Raynal 		    (invparity[par & 0x55] << 2) |
349e5acf9c8SMiquel Raynal 		    (invparity[rp17] << 1) |
350e5acf9c8SMiquel Raynal 		    (invparity[rp16] << 0);
351e5acf9c8SMiquel Raynal 
352e5acf9c8SMiquel Raynal 	return 0;
353e5acf9c8SMiquel Raynal }
35490ccf0a0SMiquel Raynal EXPORT_SYMBOL(ecc_sw_hamming_calculate);
355e5acf9c8SMiquel Raynal 
35690ccf0a0SMiquel Raynal /**
35790ccf0a0SMiquel Raynal  * nand_ecc_sw_hamming_calculate - Calculate 3-byte ECC for 256/512-byte block
35890ccf0a0SMiquel Raynal  * @nand: NAND device
35990ccf0a0SMiquel Raynal  * @buf: Input buffer with raw data
36090ccf0a0SMiquel Raynal  * @code: Output buffer with ECC
36190ccf0a0SMiquel Raynal  */
36290ccf0a0SMiquel Raynal int nand_ecc_sw_hamming_calculate(struct nand_device *nand,
36390ccf0a0SMiquel Raynal 				  const unsigned char *buf, unsigned char *code)
364e5acf9c8SMiquel Raynal {
36519b2ce18SMiquel Raynal 	struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
36619b2ce18SMiquel Raynal 	unsigned int step_size = nand->ecc.ctx.conf.step_size;
367*d8467112SMiquel Raynal 	bool sm_order = engine_conf ? engine_conf->sm_order : false;
36890ccf0a0SMiquel Raynal 
369*d8467112SMiquel Raynal 	return ecc_sw_hamming_calculate(buf, step_size, code, sm_order);
37090ccf0a0SMiquel Raynal }
37190ccf0a0SMiquel Raynal EXPORT_SYMBOL(nand_ecc_sw_hamming_calculate);
37290ccf0a0SMiquel Raynal 
37390ccf0a0SMiquel Raynal int ecc_sw_hamming_correct(unsigned char *buf, unsigned char *read_ecc,
37490ccf0a0SMiquel Raynal 			   unsigned char *calc_ecc, unsigned int step_size,
37590ccf0a0SMiquel Raynal 			   bool sm_order)
37690ccf0a0SMiquel Raynal {
37790ccf0a0SMiquel Raynal 	const u32 eccsize_mult = step_size >> 8;
378e5acf9c8SMiquel Raynal 	unsigned char b0, b1, b2, bit_addr;
379e5acf9c8SMiquel Raynal 	unsigned int byte_addr;
380e5acf9c8SMiquel Raynal 
381e5acf9c8SMiquel Raynal 	/*
382e5acf9c8SMiquel Raynal 	 * b0 to b2 indicate which bit is faulty (if any)
383e5acf9c8SMiquel Raynal 	 * we might need the xor result  more than once,
384e5acf9c8SMiquel Raynal 	 * so keep them in a local var
385e5acf9c8SMiquel Raynal 	*/
386e5acf9c8SMiquel Raynal 	if (sm_order) {
387e5acf9c8SMiquel Raynal 		b0 = read_ecc[0] ^ calc_ecc[0];
388e5acf9c8SMiquel Raynal 		b1 = read_ecc[1] ^ calc_ecc[1];
389e5acf9c8SMiquel Raynal 	} else {
390e5acf9c8SMiquel Raynal 		b0 = read_ecc[1] ^ calc_ecc[1];
391e5acf9c8SMiquel Raynal 		b1 = read_ecc[0] ^ calc_ecc[0];
392e5acf9c8SMiquel Raynal 	}
393e5acf9c8SMiquel Raynal 
394e5acf9c8SMiquel Raynal 	b2 = read_ecc[2] ^ calc_ecc[2];
395e5acf9c8SMiquel Raynal 
396e5acf9c8SMiquel Raynal 	/* check if there are any bitfaults */
397e5acf9c8SMiquel Raynal 
398e5acf9c8SMiquel Raynal 	/* repeated if statements are slightly more efficient than switch ... */
399e5acf9c8SMiquel Raynal 	/* ordered in order of likelihood */
400e5acf9c8SMiquel Raynal 
401e5acf9c8SMiquel Raynal 	if ((b0 | b1 | b2) == 0)
402e5acf9c8SMiquel Raynal 		return 0;	/* no error */
403e5acf9c8SMiquel Raynal 
404e5acf9c8SMiquel Raynal 	if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
405e5acf9c8SMiquel Raynal 	    (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
406e5acf9c8SMiquel Raynal 	    ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
407e5acf9c8SMiquel Raynal 	     (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
408e5acf9c8SMiquel Raynal 	/* single bit error */
409e5acf9c8SMiquel Raynal 		/*
410e5acf9c8SMiquel Raynal 		 * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
411e5acf9c8SMiquel Raynal 		 * byte, cp 5/3/1 indicate the faulty bit.
412e5acf9c8SMiquel Raynal 		 * A lookup table (called addressbits) is used to filter
413e5acf9c8SMiquel Raynal 		 * the bits from the byte they are in.
414e5acf9c8SMiquel Raynal 		 * A marginal optimisation is possible by having three
415e5acf9c8SMiquel Raynal 		 * different lookup tables.
416e5acf9c8SMiquel Raynal 		 * One as we have now (for b0), one for b2
417e5acf9c8SMiquel Raynal 		 * (that would avoid the >> 1), and one for b1 (with all values
418e5acf9c8SMiquel Raynal 		 * << 4). However it was felt that introducing two more tables
419e5acf9c8SMiquel Raynal 		 * hardly justify the gain.
420e5acf9c8SMiquel Raynal 		 *
421e5acf9c8SMiquel Raynal 		 * The b2 shift is there to get rid of the lowest two bits.
422e5acf9c8SMiquel Raynal 		 * We could also do addressbits[b2] >> 1 but for the
423e5acf9c8SMiquel Raynal 		 * performance it does not make any difference
424e5acf9c8SMiquel Raynal 		 */
425e5acf9c8SMiquel Raynal 		if (eccsize_mult == 1)
426e5acf9c8SMiquel Raynal 			byte_addr = (addressbits[b1] << 4) + addressbits[b0];
427e5acf9c8SMiquel Raynal 		else
428e5acf9c8SMiquel Raynal 			byte_addr = (addressbits[b2 & 0x3] << 8) +
429e5acf9c8SMiquel Raynal 				    (addressbits[b1] << 4) + addressbits[b0];
430e5acf9c8SMiquel Raynal 		bit_addr = addressbits[b2 >> 2];
431e5acf9c8SMiquel Raynal 		/* flip the bit */
432e5acf9c8SMiquel Raynal 		buf[byte_addr] ^= (1 << bit_addr);
433e5acf9c8SMiquel Raynal 		return 1;
434e5acf9c8SMiquel Raynal 
435e5acf9c8SMiquel Raynal 	}
436e5acf9c8SMiquel Raynal 	/* count nr of bits; use table lookup, faster than calculating it */
437e5acf9c8SMiquel Raynal 	if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
438e5acf9c8SMiquel Raynal 		return 1;	/* error in ECC data; no action needed */
439e5acf9c8SMiquel Raynal 
440e5acf9c8SMiquel Raynal 	pr_err("%s: uncorrectable ECC error\n", __func__);
441e5acf9c8SMiquel Raynal 	return -EBADMSG;
442e5acf9c8SMiquel Raynal }
44390ccf0a0SMiquel Raynal EXPORT_SYMBOL(ecc_sw_hamming_correct);
444e5acf9c8SMiquel Raynal 
445e5acf9c8SMiquel Raynal /**
44690ccf0a0SMiquel Raynal  * nand_ecc_sw_hamming_correct - Detect and correct bit error(s)
44790ccf0a0SMiquel Raynal  * @nand: NAND device
448c50e7f3cSMiquel Raynal  * @buf: Raw data read from the chip
449c50e7f3cSMiquel Raynal  * @read_ecc: ECC bytes read from the chip
450c50e7f3cSMiquel Raynal  * @calc_ecc: ECC calculated from the raw data
451e5acf9c8SMiquel Raynal  *
452c50e7f3cSMiquel Raynal  * Detect and correct up to 1 bit error per 256/512-byte block.
453e5acf9c8SMiquel Raynal  */
45490ccf0a0SMiquel Raynal int nand_ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
45590ccf0a0SMiquel Raynal 				unsigned char *read_ecc,
45690ccf0a0SMiquel Raynal 				unsigned char *calc_ecc)
457e5acf9c8SMiquel Raynal {
45819b2ce18SMiquel Raynal 	struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
45919b2ce18SMiquel Raynal 	unsigned int step_size = nand->ecc.ctx.conf.step_size;
460*d8467112SMiquel Raynal 	bool sm_order = engine_conf ? engine_conf->sm_order : false;
461e5acf9c8SMiquel Raynal 
46219b2ce18SMiquel Raynal 	return ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, step_size,
463*d8467112SMiquel Raynal 				      sm_order);
464e5acf9c8SMiquel Raynal }
46590ccf0a0SMiquel Raynal EXPORT_SYMBOL(nand_ecc_sw_hamming_correct);
466e5acf9c8SMiquel Raynal 
46735fe1b98SMiquel Raynal int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand)
46835fe1b98SMiquel Raynal {
46935fe1b98SMiquel Raynal 	struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
47035fe1b98SMiquel Raynal 	struct nand_ecc_sw_hamming_conf *engine_conf;
47135fe1b98SMiquel Raynal 	struct mtd_info *mtd = nanddev_to_mtd(nand);
47235fe1b98SMiquel Raynal 	int ret;
47335fe1b98SMiquel Raynal 
47435fe1b98SMiquel Raynal 	if (!mtd->ooblayout) {
47535fe1b98SMiquel Raynal 		switch (mtd->oobsize) {
47635fe1b98SMiquel Raynal 		case 8:
47735fe1b98SMiquel Raynal 		case 16:
47835fe1b98SMiquel Raynal 			mtd_set_ooblayout(mtd, nand_get_small_page_ooblayout());
47935fe1b98SMiquel Raynal 			break;
48035fe1b98SMiquel Raynal 		case 64:
48135fe1b98SMiquel Raynal 		case 128:
48235fe1b98SMiquel Raynal 			mtd_set_ooblayout(mtd,
48335fe1b98SMiquel Raynal 					  nand_get_large_page_hamming_ooblayout());
48435fe1b98SMiquel Raynal 			break;
48535fe1b98SMiquel Raynal 		default:
48635fe1b98SMiquel Raynal 			return -ENOTSUPP;
48735fe1b98SMiquel Raynal 		}
48835fe1b98SMiquel Raynal 	}
48935fe1b98SMiquel Raynal 
49035fe1b98SMiquel Raynal 	conf->engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
49135fe1b98SMiquel Raynal 	conf->algo = NAND_ECC_ALGO_HAMMING;
49235fe1b98SMiquel Raynal 	conf->step_size = nand->ecc.user_conf.step_size;
49335fe1b98SMiquel Raynal 	conf->strength = 1;
49435fe1b98SMiquel Raynal 
49535fe1b98SMiquel Raynal 	/* Use the strongest configuration by default */
49635fe1b98SMiquel Raynal 	if (conf->step_size != 256 && conf->step_size != 512)
49735fe1b98SMiquel Raynal 		conf->step_size = 256;
49835fe1b98SMiquel Raynal 
49935fe1b98SMiquel Raynal 	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
50035fe1b98SMiquel Raynal 	if (!engine_conf)
50135fe1b98SMiquel Raynal 		return -ENOMEM;
50235fe1b98SMiquel Raynal 
50335fe1b98SMiquel Raynal 	ret = nand_ecc_init_req_tweaking(&engine_conf->req_ctx, nand);
50435fe1b98SMiquel Raynal 	if (ret)
50535fe1b98SMiquel Raynal 		goto free_engine_conf;
50635fe1b98SMiquel Raynal 
50735fe1b98SMiquel Raynal 	engine_conf->code_size = 3;
50835fe1b98SMiquel Raynal 	engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
50935fe1b98SMiquel Raynal 	engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
51035fe1b98SMiquel Raynal 	if (!engine_conf->calc_buf || !engine_conf->code_buf) {
51135fe1b98SMiquel Raynal 		ret = -ENOMEM;
51235fe1b98SMiquel Raynal 		goto free_bufs;
51335fe1b98SMiquel Raynal 	}
51435fe1b98SMiquel Raynal 
51535fe1b98SMiquel Raynal 	nand->ecc.ctx.priv = engine_conf;
51612e0df0cSMiquel Raynal 	nand->ecc.ctx.nsteps = mtd->writesize / conf->step_size;
517bf3816d2SMiquel Raynal 	nand->ecc.ctx.total = nand->ecc.ctx.nsteps * engine_conf->code_size;
51835fe1b98SMiquel Raynal 
51935fe1b98SMiquel Raynal 	return 0;
52035fe1b98SMiquel Raynal 
52135fe1b98SMiquel Raynal free_bufs:
52235fe1b98SMiquel Raynal 	nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
52335fe1b98SMiquel Raynal 	kfree(engine_conf->calc_buf);
52435fe1b98SMiquel Raynal 	kfree(engine_conf->code_buf);
52535fe1b98SMiquel Raynal free_engine_conf:
52635fe1b98SMiquel Raynal 	kfree(engine_conf);
52735fe1b98SMiquel Raynal 
52835fe1b98SMiquel Raynal 	return ret;
52935fe1b98SMiquel Raynal }
53035fe1b98SMiquel Raynal EXPORT_SYMBOL(nand_ecc_sw_hamming_init_ctx);
53135fe1b98SMiquel Raynal 
53235fe1b98SMiquel Raynal void nand_ecc_sw_hamming_cleanup_ctx(struct nand_device *nand)
53335fe1b98SMiquel Raynal {
53435fe1b98SMiquel Raynal 	struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
53535fe1b98SMiquel Raynal 
53635fe1b98SMiquel Raynal 	if (engine_conf) {
53735fe1b98SMiquel Raynal 		nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
53835fe1b98SMiquel Raynal 		kfree(engine_conf->calc_buf);
53935fe1b98SMiquel Raynal 		kfree(engine_conf->code_buf);
54035fe1b98SMiquel Raynal 		kfree(engine_conf);
54135fe1b98SMiquel Raynal 	}
54235fe1b98SMiquel Raynal }
54335fe1b98SMiquel Raynal EXPORT_SYMBOL(nand_ecc_sw_hamming_cleanup_ctx);
54435fe1b98SMiquel Raynal 
54535fe1b98SMiquel Raynal static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand,
54635fe1b98SMiquel Raynal 					      struct nand_page_io_req *req)
54735fe1b98SMiquel Raynal {
54835fe1b98SMiquel Raynal 	struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
54935fe1b98SMiquel Raynal 	struct mtd_info *mtd = nanddev_to_mtd(nand);
55035fe1b98SMiquel Raynal 	int eccsize = nand->ecc.ctx.conf.step_size;
55135fe1b98SMiquel Raynal 	int eccbytes = engine_conf->code_size;
552bf3816d2SMiquel Raynal 	int eccsteps = nand->ecc.ctx.nsteps;
55335fe1b98SMiquel Raynal 	int total = nand->ecc.ctx.total;
55435fe1b98SMiquel Raynal 	u8 *ecccalc = engine_conf->calc_buf;
55535fe1b98SMiquel Raynal 	const u8 *data;
55635fe1b98SMiquel Raynal 	int i;
55735fe1b98SMiquel Raynal 
55835fe1b98SMiquel Raynal 	/* Nothing to do for a raw operation */
55935fe1b98SMiquel Raynal 	if (req->mode == MTD_OPS_RAW)
56035fe1b98SMiquel Raynal 		return 0;
56135fe1b98SMiquel Raynal 
56235fe1b98SMiquel Raynal 	/* This engine does not provide BBM/free OOB bytes protection */
56335fe1b98SMiquel Raynal 	if (!req->datalen)
56435fe1b98SMiquel Raynal 		return 0;
56535fe1b98SMiquel Raynal 
56635fe1b98SMiquel Raynal 	nand_ecc_tweak_req(&engine_conf->req_ctx, req);
56735fe1b98SMiquel Raynal 
56835fe1b98SMiquel Raynal 	/* No more preparation for page read */
56935fe1b98SMiquel Raynal 	if (req->type == NAND_PAGE_READ)
57035fe1b98SMiquel Raynal 		return 0;
57135fe1b98SMiquel Raynal 
57235fe1b98SMiquel Raynal 	/* Preparation for page write: derive the ECC bytes and place them */
57335fe1b98SMiquel Raynal 	for (i = 0, data = req->databuf.out;
57435fe1b98SMiquel Raynal 	     eccsteps;
57535fe1b98SMiquel Raynal 	     eccsteps--, i += eccbytes, data += eccsize)
57635fe1b98SMiquel Raynal 		nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]);
57735fe1b98SMiquel Raynal 
57835fe1b98SMiquel Raynal 	return mtd_ooblayout_set_eccbytes(mtd, ecccalc, (void *)req->oobbuf.out,
57935fe1b98SMiquel Raynal 					  0, total);
58035fe1b98SMiquel Raynal }
58135fe1b98SMiquel Raynal 
58235fe1b98SMiquel Raynal static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand,
58335fe1b98SMiquel Raynal 					     struct nand_page_io_req *req)
58435fe1b98SMiquel Raynal {
58535fe1b98SMiquel Raynal 	struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
58635fe1b98SMiquel Raynal 	struct mtd_info *mtd = nanddev_to_mtd(nand);
58735fe1b98SMiquel Raynal 	int eccsize = nand->ecc.ctx.conf.step_size;
58835fe1b98SMiquel Raynal 	int total = nand->ecc.ctx.total;
58935fe1b98SMiquel Raynal 	int eccbytes = engine_conf->code_size;
590bf3816d2SMiquel Raynal 	int eccsteps = nand->ecc.ctx.nsteps;
59135fe1b98SMiquel Raynal 	u8 *ecccalc = engine_conf->calc_buf;
59235fe1b98SMiquel Raynal 	u8 *ecccode = engine_conf->code_buf;
59335fe1b98SMiquel Raynal 	unsigned int max_bitflips = 0;
59435fe1b98SMiquel Raynal 	u8 *data = req->databuf.in;
59535fe1b98SMiquel Raynal 	int i, ret;
59635fe1b98SMiquel Raynal 
59735fe1b98SMiquel Raynal 	/* Nothing to do for a raw operation */
59835fe1b98SMiquel Raynal 	if (req->mode == MTD_OPS_RAW)
59935fe1b98SMiquel Raynal 		return 0;
60035fe1b98SMiquel Raynal 
60135fe1b98SMiquel Raynal 	/* This engine does not provide BBM/free OOB bytes protection */
60235fe1b98SMiquel Raynal 	if (!req->datalen)
60335fe1b98SMiquel Raynal 		return 0;
60435fe1b98SMiquel Raynal 
60535fe1b98SMiquel Raynal 	/* No more preparation for page write */
60635fe1b98SMiquel Raynal 	if (req->type == NAND_PAGE_WRITE) {
60735fe1b98SMiquel Raynal 		nand_ecc_restore_req(&engine_conf->req_ctx, req);
60835fe1b98SMiquel Raynal 		return 0;
60935fe1b98SMiquel Raynal 	}
61035fe1b98SMiquel Raynal 
61135fe1b98SMiquel Raynal 	/* Finish a page read: retrieve the (raw) ECC bytes*/
61235fe1b98SMiquel Raynal 	ret = mtd_ooblayout_get_eccbytes(mtd, ecccode, req->oobbuf.in, 0,
61335fe1b98SMiquel Raynal 					 total);
61435fe1b98SMiquel Raynal 	if (ret)
61535fe1b98SMiquel Raynal 		return ret;
61635fe1b98SMiquel Raynal 
61735fe1b98SMiquel Raynal 	/* Calculate the ECC bytes */
61835fe1b98SMiquel Raynal 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize)
61935fe1b98SMiquel Raynal 		nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]);
62035fe1b98SMiquel Raynal 
62135fe1b98SMiquel Raynal 	/* Finish a page read: compare and correct */
622bf3816d2SMiquel Raynal 	for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in;
62335fe1b98SMiquel Raynal 	     eccsteps;
62435fe1b98SMiquel Raynal 	     eccsteps--, i += eccbytes, data += eccsize) {
62535fe1b98SMiquel Raynal 		int stat =  nand_ecc_sw_hamming_correct(nand, data,
62635fe1b98SMiquel Raynal 							&ecccode[i],
62735fe1b98SMiquel Raynal 							&ecccalc[i]);
62835fe1b98SMiquel Raynal 		if (stat < 0) {
62935fe1b98SMiquel Raynal 			mtd->ecc_stats.failed++;
63035fe1b98SMiquel Raynal 		} else {
63135fe1b98SMiquel Raynal 			mtd->ecc_stats.corrected += stat;
63235fe1b98SMiquel Raynal 			max_bitflips = max_t(unsigned int, max_bitflips, stat);
63335fe1b98SMiquel Raynal 		}
63435fe1b98SMiquel Raynal 	}
63535fe1b98SMiquel Raynal 
63635fe1b98SMiquel Raynal 	nand_ecc_restore_req(&engine_conf->req_ctx, req);
63735fe1b98SMiquel Raynal 
63835fe1b98SMiquel Raynal 	return max_bitflips;
63935fe1b98SMiquel Raynal }
64035fe1b98SMiquel Raynal 
64135fe1b98SMiquel Raynal static struct nand_ecc_engine_ops nand_ecc_sw_hamming_engine_ops = {
64235fe1b98SMiquel Raynal 	.init_ctx = nand_ecc_sw_hamming_init_ctx,
64335fe1b98SMiquel Raynal 	.cleanup_ctx = nand_ecc_sw_hamming_cleanup_ctx,
64435fe1b98SMiquel Raynal 	.prepare_io_req = nand_ecc_sw_hamming_prepare_io_req,
64535fe1b98SMiquel Raynal 	.finish_io_req = nand_ecc_sw_hamming_finish_io_req,
64635fe1b98SMiquel Raynal };
64735fe1b98SMiquel Raynal 
64835fe1b98SMiquel Raynal static struct nand_ecc_engine nand_ecc_sw_hamming_engine = {
64935fe1b98SMiquel Raynal 	.ops = &nand_ecc_sw_hamming_engine_ops,
65035fe1b98SMiquel Raynal };
65135fe1b98SMiquel Raynal 
65235fe1b98SMiquel Raynal struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void)
65335fe1b98SMiquel Raynal {
65435fe1b98SMiquel Raynal 	return &nand_ecc_sw_hamming_engine;
65535fe1b98SMiquel Raynal }
65635fe1b98SMiquel Raynal EXPORT_SYMBOL(nand_ecc_sw_hamming_get_engine);
65735fe1b98SMiquel Raynal 
658e5acf9c8SMiquel Raynal MODULE_LICENSE("GPL");
659e5acf9c8SMiquel Raynal MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
6602dbe0192SMiquel Raynal MODULE_DESCRIPTION("NAND software Hamming ECC support");
661