From d1f9fa8a3a4c2ab735c7bfaec11f61159811b389 Mon Sep 17 00:00:00 2001 From: marcan Date: Sat, 7 Mar 2009 17:31:45 +0100 Subject: [PATCH] Add NAND ECC correction to miniios and use for boot2 loads --- boot2.c | 5 +++++ main.c | 1 - nand.c | 42 ++++++++++++++++++++++++++++++++++++++++++ nand.h | 6 ++++++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/boot2.c b/boot2.c index 756dd2b..47f6a14 100644 --- a/boot2.c +++ b/boot2.c @@ -42,6 +42,10 @@ void boot2_init() { for (i = 0x40; i < 0x140; i++, ptr += 2048) { nand_read_page(i, ptr, ecc); nand_wait(); + if(nand_correct(i, ptr, ecc) < 0) { + gecko_printf("boot2 is corrupted, cannot load!\n"); + return; + } } if (hdr->len != sizeof(struct wadheader)) @@ -75,6 +79,7 @@ void boot2_init() { memcpy(boot2, cntptr, datalen); boot2_initialized = 1; + gecko_printf("boot2 loaded\n"); } static u32 match[] = { diff --git a/main.c b/main.c index c10872d..cf5f92f 100644 --- a/main.c +++ b/main.c @@ -178,7 +178,6 @@ void *_main(void *base) gecko_puts("NAND initialized.\n"); boot2_init(); - gecko_puts("Boot2 loaded to memory.\n"); gecko_puts("Initializing IPC...\n"); ipc_initialize(); diff --git a/nand.c b/nand.c index 56ba728..5ca9422 100644 --- a/nand.c +++ b/nand.c @@ -200,6 +200,48 @@ void nand_initialize(void) irq_enable(IRQ_NAND); } +int nand_correct(u32 pageno, void *data, void *ecc) +{ + u8 *dp = (u8*)data; + u32 *ecc_read = (u32*)((u8*)ecc)+0x30; + u32 *ecc_calc = (u32*)((u8*)ecc)+0x40; + int i; + int uncorrectable = 0; + int corrected = 0; + + for(i=0;i<4;i++) { + u32 syndrome = *ecc_read ^ *ecc_calc; //calculate ECC syncrome + if(syndrome) { + if(!((syndrome-1)&syndrome)) { + // single-bit error in ECC + corrected++; + } else { + // byteswap and extract odd and even halves + u16 even = (syndrome >> 24) | ((syndrome >> 8) & 0xf00); + u16 odd = ((syndrome << 8) & 0xf00) | ((syndrome >> 8) & 0x0ff); + if((even ^ odd) != 0xfff) { + // oops, can't fix this one + uncorrectable++; + } else { + // fix the bad bit + dp[odd >> 3] ^= 1<<(odd&7); + corrected++; + } + } + } + dp += 0x200; + ecc_read++; + ecc_calc++; + } + if(uncorrectable || corrected) + gecko_printf("ECC stats for NAND page 0x%x: %d uncorrectable, %d corrected\n", uncorrectable, corrected); + if(uncorrectable) + return NAND_ECC_UNCORRECTABLE; + if(corrected) + return NAND_ECC_CORRECTED; + return NAND_ECC_OK; +} + void nand_ipc(volatile ipc_request *req) { if (ipc_code != 0 || ipc_tag != 0) { diff --git a/nand.h b/nand.h index e0f073d..171443e 100644 --- a/nand.h +++ b/nand.h @@ -17,6 +17,12 @@ void nand_wait(void); void nand_read_cluster(u32 clusterno, void *data); +#define NAND_ECC_OK 0 +#define NAND_ECC_CORRECTED 1 +#define NAND_ECC_UNCORRECTABLE -1 + +int nand_correct(u32 pageno, void *data, void *ecc); + void nand_initialize(); void nand_ipc(volatile ipc_request *req);