| /* | 
 |  * Calculate Error-correcting Codes. Used by NAND Flash controllers | 
 |  * (not by NAND chips). | 
 |  * | 
 |  * Copyright (c) 2006 Openedhand Ltd. | 
 |  * Written by Andrzej Zaborowski <balrog@zabor.org> | 
 |  * | 
 |  * This code is licensed under the GNU GPL v2. | 
 |  * | 
 |  * Contributions after 2012-01-13 are licensed under the terms of the | 
 |  * GNU GPL, version 2 or (at your option) any later version. | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 | #include "migration/vmstate.h" | 
 | #include "hw/block/flash.h" | 
 |  | 
 | /* | 
 |  * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux. | 
 |  */ | 
 | static const uint8_t nand_ecc_precalc_table[] = { | 
 |     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, | 
 |     0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, | 
 |     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, | 
 |     0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | 
 |     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, | 
 |     0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | 
 |     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, | 
 |     0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | 
 |     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, | 
 |     0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | 
 |     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, | 
 |     0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | 
 |     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, | 
 |     0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | 
 |     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, | 
 |     0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | 
 |     0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, | 
 |     0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | 
 |     0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, | 
 |     0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | 
 |     0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, | 
 |     0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | 
 |     0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, | 
 |     0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | 
 |     0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, | 
 |     0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | 
 |     0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, | 
 |     0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | 
 |     0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, | 
 |     0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | 
 |     0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, | 
 |     0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, | 
 | }; | 
 |  | 
 | /* Update ECC parity count.  */ | 
 | uint8_t ecc_digest(ECCState *s, uint8_t sample) | 
 | { | 
 |     uint8_t idx = nand_ecc_precalc_table[sample]; | 
 |  | 
 |     s->cp ^= idx & 0x3f; | 
 |     if (idx & 0x40) { | 
 |         s->lp[0] ^= ~s->count; | 
 |         s->lp[1] ^= s->count; | 
 |     } | 
 |     s->count ++; | 
 |  | 
 |     return sample; | 
 | } | 
 |  | 
 | /* Reinitialise the counters.  */ | 
 | void ecc_reset(ECCState *s) | 
 | { | 
 |     s->lp[0] = 0x0000; | 
 |     s->lp[1] = 0x0000; | 
 |     s->cp = 0x00; | 
 |     s->count = 0; | 
 | } | 
 |  | 
 | /* Save/restore */ | 
 | const VMStateDescription vmstate_ecc_state = { | 
 |     .name = "ecc-state", | 
 |     .version_id = 0, | 
 |     .minimum_version_id = 0, | 
 |     .fields = (const VMStateField[]) { | 
 |         VMSTATE_UINT8(cp, ECCState), | 
 |         VMSTATE_UINT16_ARRAY(lp, ECCState, 2), | 
 |         VMSTATE_UINT16(count, ECCState), | 
 |         VMSTATE_END_OF_LIST(), | 
 |     }, | 
 | }; |