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 | VMStateDescription vmstate_ecc_state = { |
82 | .name = "ecc-state" , |
83 | .version_id = 0, |
84 | .minimum_version_id = 0, |
85 | .fields = (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 | |