2007-04-30 04:09:25 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
2012-01-13 17:44:23 +01:00
|
|
|
*
|
|
|
|
* Contributions after 2012-01-13 are licensed under the terms of the
|
|
|
|
* GNU GPL, version 2 or (at your option) any later version.
|
2007-04-30 04:09:25 +02:00
|
|
|
*/
|
|
|
|
|
2007-11-17 18:14:51 +01:00
|
|
|
#include "hw.h"
|
|
|
|
#include "flash.h"
|
2007-04-30 04:09:25 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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. */
|
2009-05-10 02:44:56 +02:00
|
|
|
uint8_t ecc_digest(ECCState *s, uint8_t sample)
|
2007-04-30 04:09:25 +02:00
|
|
|
{
|
|
|
|
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. */
|
2009-05-10 02:44:56 +02:00
|
|
|
void ecc_reset(ECCState *s)
|
2007-04-30 04:09:25 +02:00
|
|
|
{
|
|
|
|
s->lp[0] = 0x0000;
|
|
|
|
s->lp[1] = 0x0000;
|
|
|
|
s->cp = 0x00;
|
|
|
|
s->count = 0;
|
|
|
|
}
|
2007-05-24 20:50:09 +02:00
|
|
|
|
|
|
|
/* Save/restore */
|
2011-01-21 11:12:11 +01:00
|
|
|
VMStateDescription vmstate_ecc_state = {
|
|
|
|
.name = "ecc-state",
|
|
|
|
.version_id = 0,
|
|
|
|
.minimum_version_id = 0,
|
|
|
|
.minimum_version_id_old = 0,
|
|
|
|
.fields = (VMStateField []) {
|
|
|
|
VMSTATE_UINT8(cp, ECCState),
|
|
|
|
VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
|
|
|
|
VMSTATE_UINT16(count, ECCState),
|
|
|
|
VMSTATE_END_OF_LIST(),
|
|
|
|
},
|
|
|
|
};
|