|  | /* | 
|  | * 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 "hw/hw.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 */ | 
|  | VMStateDescription vmstate_ecc_state = { | 
|  | .name = "ecc-state", | 
|  | .version_id = 0, | 
|  | .minimum_version_id = 0, | 
|  | .fields = (VMStateField[]) { | 
|  | VMSTATE_UINT8(cp, ECCState), | 
|  | VMSTATE_UINT16_ARRAY(lp, ECCState, 2), | 
|  | VMSTATE_UINT16(count, ECCState), | 
|  | VMSTATE_END_OF_LIST(), | 
|  | }, | 
|  | }; |