nand: fix return value
[openocd.git] / src / flash / nand / ecc_kw.c
1 /*
2 * Reed-Solomon ECC handling for the Marvell Kirkwood SOC
3 * Copyright (C) 2009 Marvell Semiconductor, Inc.
4 *
5 * Authors: Lennert Buytenhek <buytenh@wantstofly.org>
6 * Nicolas Pitre <nico@fluxnic.net>
7 *
8 * This file is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 or (at your option) any
11 * later version.
12 *
13 * This file is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "core.h"
24
25 /*****************************************************************************
26 * Arithmetic in GF(2^10) ("F") modulo x^10 + x^3 + 1.
27 *
28 * For multiplication, a discrete log/exponent table is used, with
29 * primitive element x (F is a primitive field, so x is primitive).
30 */
31 #define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */
32
33 /*
34 * Maps an integer a [0..1022] to a polynomial b = gf_exp[a] in
35 * GF(2^10) mod x^10 + x^3 + 1 such that b = x ^ a. There's two
36 * identical copies of this array back-to-back so that we can save
37 * the mod 1023 operation when doing a GF multiplication.
38 */
39 static uint16_t gf_exp[1023 + 1023];
40
41 /*
42 * Maps a polynomial b in GF(2^10) mod x^10 + x^3 + 1 to an index
43 * a = gf_log[b] in [0..1022] such that b = x ^ a.
44 */
45 static uint16_t gf_log[1024];
46
47 static void gf_build_log_exp_table(void)
48 {
49 int i;
50 int p_i;
51
52 /*
53 * p_i = x ^ i
54 *
55 * Initialise to 1 for i = 0.
56 */
57 p_i = 1;
58
59 for (i = 0; i < 1023; i++) {
60 gf_exp[i] = p_i;
61 gf_exp[i + 1023] = p_i;
62 gf_log[p_i] = i;
63
64 /*
65 * p_i = p_i * x
66 */
67 p_i <<= 1;
68 if (p_i & (1 << 10))
69 p_i ^= MODPOLY;
70 }
71 }
72
73
74 /*****************************************************************************
75 * Reed-Solomon code
76 *
77 * This implements a (1023,1015) Reed-Solomon ECC code over GF(2^10)
78 * mod x^10 + x^3 + 1, shortened to (520,512). The ECC data consists
79 * of 8 10-bit symbols, or 10 8-bit bytes.
80 *
81 * Given 512 bytes of data, computes 10 bytes of ECC.
82 *
83 * This is done by converting the 512 bytes to 512 10-bit symbols
84 * (elements of F), interpreting those symbols as a polynomial in F[X]
85 * by taking symbol 0 as the coefficient of X^8 and symbol 511 as the
86 * coefficient of X^519, and calculating the residue of that polynomial
87 * divided by the generator polynomial, which gives us the 8 ECC symbols
88 * as the remainder. Finally, we convert the 8 10-bit ECC symbols to 10
89 * 8-bit bytes.
90 *
91 * The generator polynomial is hardcoded, as that is faster, but it
92 * can be computed by taking the primitive element a = x (in F), and
93 * constructing a polynomial in F[X] with roots a, a^2, a^3, ..., a^8
94 * by multiplying the minimal polynomials for those roots (which are
95 * just 'x - a^i' for each i).
96 *
97 * Note: due to unfortunate circumstances, the bootrom in the Kirkwood SOC
98 * expects the ECC to be computed backward, i.e. from the last byte down
99 * to the first one.
100 */
101 int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t *ecc)
102 {
103 unsigned int r7, r6, r5, r4, r3, r2, r1, r0;
104 int i;
105 static int tables_initialized;
106
107 if (!tables_initialized) {
108 gf_build_log_exp_table();
109 tables_initialized = 1;
110 }
111
112 /*
113 * Load bytes 504..511 of the data into r.
114 */
115 r0 = data[504];
116 r1 = data[505];
117 r2 = data[506];
118 r3 = data[507];
119 r4 = data[508];
120 r5 = data[509];
121 r6 = data[510];
122 r7 = data[511];
123
124 /*
125 * Shift bytes 503..0 (in that order) into r0, followed
126 * by eight zero bytes, while reducing the polynomial by the
127 * generator polynomial in every step.
128 */
129 for (i = 503; i >= -8; i--) {
130 unsigned int d;
131
132 d = 0;
133 if (i >= 0)
134 d = data[i];
135
136 if (r7) {
137 uint16_t *t = gf_exp + gf_log[r7];
138
139 r7 = r6 ^ t[0x21c];
140 r6 = r5 ^ t[0x181];
141 r5 = r4 ^ t[0x18e];
142 r4 = r3 ^ t[0x25f];
143 r3 = r2 ^ t[0x197];
144 r2 = r1 ^ t[0x193];
145 r1 = r0 ^ t[0x237];
146 r0 = d ^ t[0x024];
147 } else {
148 r7 = r6;
149 r6 = r5;
150 r5 = r4;
151 r4 = r3;
152 r3 = r2;
153 r2 = r1;
154 r1 = r0;
155 r0 = d;
156 }
157 }
158
159 ecc[0] = r0;
160 ecc[1] = (r0 >> 8) | (r1 << 2);
161 ecc[2] = (r1 >> 6) | (r2 << 4);
162 ecc[3] = (r2 >> 4) | (r3 << 6);
163 ecc[4] = (r3 >> 2);
164 ecc[5] = r4;
165 ecc[6] = (r4 >> 8) | (r5 << 2);
166 ecc[7] = (r5 >> 6) | (r6 << 4);
167 ecc[8] = (r6 >> 4) | (r7 << 6);
168 ecc[9] = (r7 >> 2);
169
170 return 0;
171 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)