2007-04-30 06:09:25 +04: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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct ecc_state_s {
|
|
|
|
uint8_t cp; /* Column parity */
|
|
|
|
uint16_t lp[2]; /* Line parity */
|
|
|
|
uint16_t count;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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. */
|
|
|
|
static inline uint8_t ecc_digest(struct ecc_state_s *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. */
|
|
|
|
static inline void ecc_reset(struct ecc_state_s *s)
|
|
|
|
{
|
|
|
|
s->lp[0] = 0x0000;
|
|
|
|
s->lp[1] = 0x0000;
|
|
|
|
s->cp = 0x00;
|
|
|
|
s->count = 0;
|
|
|
|
}
|
2007-05-24 22:50:09 +04:00
|
|
|
|
|
|
|
/* Save/restore */
|
|
|
|
static inline void ecc_put(QEMUFile *f, struct ecc_state_s *s)
|
|
|
|
{
|
|
|
|
qemu_put_8s(f, &s->cp);
|
|
|
|
qemu_put_be16s(f, &s->lp[0]);
|
|
|
|
qemu_put_be16s(f, &s->lp[1]);
|
|
|
|
qemu_put_be16s(f, &s->count);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void ecc_get(QEMUFile *f, struct ecc_state_s *s)
|
|
|
|
{
|
|
|
|
qemu_get_8s(f, &s->cp);
|
|
|
|
qemu_get_be16s(f, &s->lp[0]);
|
|
|
|
qemu_get_be16s(f, &s->lp[1]);
|
|
|
|
qemu_get_be16s(f, &s->count);
|
|
|
|
}
|