55273c58f7622e7e0ca2341a9f1de6a2b4a8a968
[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 <flash/nand.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 = 0;
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 /*
126 * Shift bytes 503..0 (in that order) into r0, followed
127 * by eight zero bytes, while reducing the polynomial by the
128 * generator polynomial in every step.
129 */
130 for (i = 503; i >= -8; i--) {
131 unsigned int d;
132
133 d = 0;
134 if (i >= 0)
135 d = data[i];
136
137 if (r7) {
138 uint16_t *t = gf_exp + gf_log[r7];
139
140 r7 = r6 ^ t[0x21c];
141 r6 = r5 ^ t[0x181];
142 r5 = r4 ^ t[0x18e];
143 r4 = r3 ^ t[0x25f];
144 r3 = r2 ^ t[0x197];
145 r2 = r1 ^ t[0x193];
146 r1 = r0 ^ t[0x237];
147 r0 = d ^ t[0x024];
148 } else {
149 r7 = r6;
150 r6 = r5;
151 r5 = r4;
152 r4 = r3;
153 r3 = r2;
154 r2 = r1;
155 r1 = r0;
156 r0 = d;
157 }
158 }
159
160 ecc[0] = r0;
161 ecc[1] = (r0 >> 8) | (r1 << 2);
162 ecc[2] = (r1 >> 6) | (r2 << 4);
163 ecc[3] = (r2 >> 4) | (r3 << 6);
164 ecc[4] = (r3 >> 2);
165 ecc[5] = r4;
166 ecc[6] = (r4 >> 8) | (r5 << 2);
167 ecc[7] = (r5 >> 6) | (r6 << 4);
168 ecc[8] = (r6 >> 4) | (r7 << 6);
169 ecc[9] = (r7 >> 2);
170
171 return 0;
172 }

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)