root / hw / block / ecc.c @ f53f81e0
History | View | Annotate | Download (3 kB)
1 | 3e3d5815 | balrog | /*
|
---|---|---|---|
2 | 3e3d5815 | balrog | * Calculate Error-correcting Codes. Used by NAND Flash controllers
|
3 | 3e3d5815 | balrog | * (not by NAND chips).
|
4 | 3e3d5815 | balrog | *
|
5 | 3e3d5815 | balrog | * Copyright (c) 2006 Openedhand Ltd.
|
6 | 3e3d5815 | balrog | * Written by Andrzej Zaborowski <balrog@zabor.org>
|
7 | 3e3d5815 | balrog | *
|
8 | 3e3d5815 | balrog | * This code is licensed under the GNU GPL v2.
|
9 | 6b620ca3 | Paolo Bonzini | *
|
10 | 6b620ca3 | Paolo Bonzini | * Contributions after 2012-01-13 are licensed under the terms of the
|
11 | 6b620ca3 | Paolo Bonzini | * GNU GPL, version 2 or (at your option) any later version.
|
12 | 3e3d5815 | balrog | */
|
13 | 3e3d5815 | balrog | |
14 | 83c9f4ca | Paolo Bonzini | #include "hw/hw.h" |
15 | 0d09e41a | Paolo Bonzini | #include "hw/block/flash.h" |
16 | 3e3d5815 | balrog | |
17 | 3e3d5815 | balrog | /*
|
18 | 3e3d5815 | balrog | * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux.
|
19 | 3e3d5815 | balrog | */
|
20 | 3e3d5815 | balrog | static const uint8_t nand_ecc_precalc_table[] = { |
21 | 3e3d5815 | balrog | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, |
22 | 3e3d5815 | balrog | 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, |
23 | 3e3d5815 | balrog | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, |
24 | 3e3d5815 | balrog | 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, |
25 | 3e3d5815 | balrog | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, |
26 | 3e3d5815 | balrog | 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, |
27 | 3e3d5815 | balrog | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, |
28 | 3e3d5815 | balrog | 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, |
29 | 3e3d5815 | balrog | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, |
30 | 3e3d5815 | balrog | 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, |
31 | 3e3d5815 | balrog | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, |
32 | 3e3d5815 | balrog | 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, |
33 | 3e3d5815 | balrog | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, |
34 | 3e3d5815 | balrog | 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, |
35 | 3e3d5815 | balrog | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, |
36 | 3e3d5815 | balrog | 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, |
37 | 3e3d5815 | balrog | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, |
38 | 3e3d5815 | balrog | 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, |
39 | 3e3d5815 | balrog | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, |
40 | 3e3d5815 | balrog | 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, |
41 | 3e3d5815 | balrog | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, |
42 | 3e3d5815 | balrog | 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, |
43 | 3e3d5815 | balrog | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, |
44 | 3e3d5815 | balrog | 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, |
45 | 3e3d5815 | balrog | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, |
46 | 3e3d5815 | balrog | 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, |
47 | 3e3d5815 | balrog | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, |
48 | 3e3d5815 | balrog | 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, |
49 | 3e3d5815 | balrog | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, |
50 | 3e3d5815 | balrog | 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, |
51 | 3e3d5815 | balrog | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, |
52 | 3e3d5815 | balrog | 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, |
53 | 3e3d5815 | balrog | }; |
54 | 3e3d5815 | balrog | |
55 | 3e3d5815 | balrog | /* Update ECC parity count. */
|
56 | bc24a225 | Paul Brook | uint8_t ecc_digest(ECCState *s, uint8_t sample) |
57 | 3e3d5815 | balrog | { |
58 | 3e3d5815 | balrog | uint8_t idx = nand_ecc_precalc_table[sample]; |
59 | 3e3d5815 | balrog | |
60 | 3e3d5815 | balrog | s->cp ^= idx & 0x3f;
|
61 | 3e3d5815 | balrog | if (idx & 0x40) { |
62 | 3e3d5815 | balrog | s->lp[0] ^= ~s->count;
|
63 | 3e3d5815 | balrog | s->lp[1] ^= s->count;
|
64 | 3e3d5815 | balrog | } |
65 | 3e3d5815 | balrog | s->count ++; |
66 | 3e3d5815 | balrog | |
67 | 3e3d5815 | balrog | return sample;
|
68 | 3e3d5815 | balrog | } |
69 | 3e3d5815 | balrog | |
70 | 3e3d5815 | balrog | /* Reinitialise the counters. */
|
71 | bc24a225 | Paul Brook | void ecc_reset(ECCState *s)
|
72 | 3e3d5815 | balrog | { |
73 | 3e3d5815 | balrog | s->lp[0] = 0x0000; |
74 | 3e3d5815 | balrog | s->lp[1] = 0x0000; |
75 | 3e3d5815 | balrog | s->cp = 0x00;
|
76 | 3e3d5815 | balrog | s->count = 0;
|
77 | 3e3d5815 | balrog | } |
78 | aa941b94 | balrog | |
79 | aa941b94 | balrog | /* Save/restore */
|
80 | 34f9f0b5 | Dmitry Eremin-Solenikov | VMStateDescription vmstate_ecc_state = { |
81 | 34f9f0b5 | Dmitry Eremin-Solenikov | .name = "ecc-state",
|
82 | 34f9f0b5 | Dmitry Eremin-Solenikov | .version_id = 0,
|
83 | 34f9f0b5 | Dmitry Eremin-Solenikov | .minimum_version_id = 0,
|
84 | 34f9f0b5 | Dmitry Eremin-Solenikov | .minimum_version_id_old = 0,
|
85 | 34f9f0b5 | Dmitry Eremin-Solenikov | .fields = (VMStateField []) { |
86 | 34f9f0b5 | Dmitry Eremin-Solenikov | VMSTATE_UINT8(cp, ECCState), |
87 | 34f9f0b5 | Dmitry Eremin-Solenikov | VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
|
88 | 34f9f0b5 | Dmitry Eremin-Solenikov | VMSTATE_UINT16(count, ECCState), |
89 | 34f9f0b5 | Dmitry Eremin-Solenikov | VMSTATE_END_OF_LIST(), |
90 | 34f9f0b5 | Dmitry Eremin-Solenikov | }, |
91 | 34f9f0b5 | Dmitry Eremin-Solenikov | }; |