xref: /qemu/hw/block/ecc.c (revision 2abf0da2)
1 /*
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.
9  *
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.
12  */
13 
14 #include "qemu/osdep.h"
15 #include "migration/vmstate.h"
16 #include "hw/block/flash.h"
17 
18 /*
19  * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux.
20  */
21 static const uint8_t nand_ecc_precalc_table[] = {
22     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
23     0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
24     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
25     0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
26     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
27     0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
28     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
29     0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
30     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
31     0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
32     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
33     0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
34     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
35     0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
36     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
37     0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
38     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
39     0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
40     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
41     0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
42     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
43     0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
44     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
45     0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
46     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
47     0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
48     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
49     0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
50     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
51     0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
52     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
53     0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
54 };
55 
56 /* Update ECC parity count.  */
57 uint8_t ecc_digest(ECCState *s, uint8_t sample)
58 {
59     uint8_t idx = nand_ecc_precalc_table[sample];
60 
61     s->cp ^= idx & 0x3f;
62     if (idx & 0x40) {
63         s->lp[0] ^= ~s->count;
64         s->lp[1] ^= s->count;
65     }
66     s->count ++;
67 
68     return sample;
69 }
70 
71 /* Reinitialise the counters.  */
72 void ecc_reset(ECCState *s)
73 {
74     s->lp[0] = 0x0000;
75     s->lp[1] = 0x0000;
76     s->cp = 0x00;
77     s->count = 0;
78 }
79 
80 /* Save/restore */
81 const VMStateDescription vmstate_ecc_state = {
82     .name = "ecc-state",
83     .version_id = 0,
84     .minimum_version_id = 0,
85     .fields = (const VMStateField[]) {
86         VMSTATE_UINT8(cp, ECCState),
87         VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
88         VMSTATE_UINT16(count, ECCState),
89         VMSTATE_END_OF_LIST(),
90     },
91 };
92