blob: 10bb2330894ac648ccf53e543277966a2e1985a8 [file] [log] [blame]
balrog3e3d5812007-04-30 02:09:25 +00001/*
2 * Calculate Error-correcting Codes. Used by NAND Flash controllers
3 * (not by NAND chips).
4 *
5 * Copyright (c) 2006 Openedhand Ltd.
6 * Written by Andrzej Zaborowski <balrog@zabor.org>
7 *
8 * This code is licensed under the GNU GPL v2.
Paolo Bonzini6b620ca2012-01-13 17:44:23 +01009 *
10 * Contributions after 2012-01-13 are licensed under the terms of the
11 * GNU GPL, version 2 or (at your option) any later version.
balrog3e3d5812007-04-30 02:09:25 +000012 */
13
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010014#include "hw/hw.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010015#include "hw/block/flash.h"
balrog3e3d5812007-04-30 02:09:25 +000016
17/*
18 * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux.
19 */
20static const uint8_t nand_ecc_precalc_table[] = {
21 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
22 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
23 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
24 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
25 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
26 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
27 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
28 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
29 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
30 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
31 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
32 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
33 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
34 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
35 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
36 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
37 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
38 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
39 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
40 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
41 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
42 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
43 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
44 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
45 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
46 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
47 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
48 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
49 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
50 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
51 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
52 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
53};
54
55/* Update ECC parity count. */
Paul Brookbc24a222009-05-10 01:44:56 +010056uint8_t ecc_digest(ECCState *s, uint8_t sample)
balrog3e3d5812007-04-30 02:09:25 +000057{
58 uint8_t idx = nand_ecc_precalc_table[sample];
59
60 s->cp ^= idx & 0x3f;
61 if (idx & 0x40) {
62 s->lp[0] ^= ~s->count;
63 s->lp[1] ^= s->count;
64 }
65 s->count ++;
66
67 return sample;
68}
69
70/* Reinitialise the counters. */
Paul Brookbc24a222009-05-10 01:44:56 +010071void ecc_reset(ECCState *s)
balrog3e3d5812007-04-30 02:09:25 +000072{
73 s->lp[0] = 0x0000;
74 s->lp[1] = 0x0000;
75 s->cp = 0x00;
76 s->count = 0;
77}
balrogaa941b92007-05-24 18:50:09 +000078
79/* Save/restore */
Dmitry Eremin-Solenikov34f9f0b2011-01-21 13:12:11 +030080VMStateDescription vmstate_ecc_state = {
81 .name = "ecc-state",
82 .version_id = 0,
83 .minimum_version_id = 0,
Juan Quintela8f1e8842014-05-13 16:09:35 +010084 .fields = (VMStateField[]) {
Dmitry Eremin-Solenikov34f9f0b2011-01-21 13:12:11 +030085 VMSTATE_UINT8(cp, ECCState),
86 VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
87 VMSTATE_UINT16(count, ECCState),
88 VMSTATE_END_OF_LIST(),
89 },
90};