diff options
author | Bjarne Steinsbo <bsteinsbo@gmail.com> | 2011-02-15 20:23:40 +0100 |
---|---|---|
committer | Øyvind Harboe <oyvind.harboe@zylin.com> | 2011-02-15 20:23:40 +0100 |
commit | 3f4b9e334b867a16c35b1c6d9a1f9aefd35fd91b (patch) | |
tree | 3b599ba715c6f74ffdc07d93a22e9dc950f2a50f /src/flash/nand/ecc.c | |
parent | fe0894015fd3d25593ce3a7211b1540ebfbab1f3 (diff) | |
download | openocd+libswd-3f4b9e334b867a16c35b1c6d9a1f9aefd35fd91b.tar.gz openocd+libswd-3f4b9e334b867a16c35b1c6d9a1f9aefd35fd91b.tar.bz2 openocd+libswd-3f4b9e334b867a16c35b1c6d9a1f9aefd35fd91b.tar.xz openocd+libswd-3f4b9e334b867a16c35b1c6d9a1f9aefd35fd91b.zip |
lpc32xx: Flash driver
Based on the lpc3180 driver, but released as a separate driver for two reasons:
1) I don't have an lpc3180 to test it against, so it might unintentionally break compatibility.
2) It's using a different OOB layout than lpc3180.
Rewritten so that it no longer borrows code from the NXP CDL library. Instead borrowing code from the u-boot port to lpc32xx, written by Kevin Wells.
Tested on lpc3250 (Hitex LPC3250-Stick). OOB layout is compatible with LPCLinux.
Diffstat (limited to 'src/flash/nand/ecc.c')
-rw-r--r-- | src/flash/nand/ecc.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/src/flash/nand/ecc.c b/src/flash/nand/ecc.c index 2de12d42..b4039976 100644 --- a/src/flash/nand/ecc.c +++ b/src/flash/nand/ecc.c @@ -120,3 +120,64 @@ int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ec return 0; } + +static inline int countbits(uint32_t byte) +{ + int res = 0; + + for (;byte; byte >>= 1) + res += byte & 0x01; + return res; +} + +/** + * nand_correct_data - Detect and correct a 1 bit error for 256 byte block + */ +int nand_correct_data(struct nand_device *nand, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + uint8_t s0, s1, s2; + +#ifdef NAND_ECC_SMC + s0 = calc_ecc[0] ^ read_ecc[0]; + s1 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; +#else + s1 = calc_ecc[0] ^ read_ecc[0]; + s0 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; +#endif + if ((s0 | s1 | s2) == 0) + return 0; + + /* Check for a single bit error */ + if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && + ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && + ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { + + uint32_t byteoffs, bitnum; + + byteoffs = (s1 << 0) & 0x80; + byteoffs |= (s1 << 1) & 0x40; + byteoffs |= (s1 << 2) & 0x20; + byteoffs |= (s1 << 3) & 0x10; + + byteoffs |= (s0 >> 4) & 0x08; + byteoffs |= (s0 >> 3) & 0x04; + byteoffs |= (s0 >> 2) & 0x02; + byteoffs |= (s0 >> 1) & 0x01; + + bitnum = (s2 >> 5) & 0x04; + bitnum |= (s2 >> 4) & 0x02; + bitnum |= (s2 >> 3) & 0x01; + + dat[byteoffs] ^= (1 << bitnum); + + return 1; + } + + if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) + return 1; + + return -1; +} |