Add shadow buffer for NAND IPC to prevent MEM1 issues, fix some stuff

This commit is contained in:
marcan 2009-03-07 20:12:41 +01:00 committed by bushing
parent d1f9fa8a3a
commit 8ce5433382

81
nand.c
View File

@ -8,6 +8,7 @@
#include "irq.h" #include "irq.h"
#include "ipc.h" #include "ipc.h"
#include "gecko.h" #include "gecko.h"
#include "types.h"
//#define NAND_DEBUG 1 //#define NAND_DEBUG 1
#undef NAND_SUPPORT_WRITE #undef NAND_SUPPORT_WRITE
@ -49,10 +50,14 @@ type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
#define PAGE_SIZE 2048 #define PAGE_SIZE 2048
#define PAGE_SPARE_SIZE 64 #define PAGE_SPARE_SIZE 64
#define ECC_BUFFER_SIZE (PAGE_SPARE_SIZE+16)
#define NAND_MAX_PAGE 0x40000 #define NAND_MAX_PAGE 0x40000
static int ipc_code = 0; ipc_request current_request;
static int ipc_tag = 0;
u8 ipc_data[PAGE_SIZE] MEM2_BSS ALIGNED(32);
// keep cache aligned size
u8 ipc_ecc[ECC_BUFFER_SIZE+16] MEM2_BSS ALIGNED(128); //128 alignment REQUIRED
static inline u32 __nand_read32(u32 addr) static inline u32 __nand_read32(u32 addr)
{ {
@ -61,16 +66,30 @@ static inline u32 __nand_read32(u32 addr)
void nand_irq(void) void nand_irq(void)
{ {
int code, tag; int code, tag, err = 0;
if(__nand_read32(NAND_CMD) & NAND_ERROR) if(__nand_read32(NAND_CMD) & NAND_ERROR) {
gecko_printf("NAND: Error on IRQ\n"); gecko_printf("NAND: Error on IRQ\n");
err = -1;
}
ahb_memflush(NAND); ahb_memflush(NAND);
magic_bullshit(0); magic_bullshit(0);
if (ipc_code != 0) { if (current_request.code != 0) {
code = ipc_code; switch (current_request.req) {
tag = ipc_tag; case IPC_NAND_GETID:
ipc_code = ipc_tag = 0; memcpy32((void*)current_request.args[0], ipc_data, 0x40);
ipc_post(code, tag, 0); dc_flushrange((void*)current_request.args[0], 0x40);
break;
case IPC_NAND_READ:
memcpy32((void*)current_request.args[1], ipc_data, PAGE_SIZE);
memcpy32((void*)current_request.args[2], ipc_ecc, ECC_BUFFER_SIZE);
dc_flushrange((void*)current_request.args[1], PAGE_SIZE);
dc_flushrange((void*)current_request.args[2], ECC_BUFFER_SIZE);
break;
}
code = current_request.code;
tag = current_request.tag;
current_request.code = 0;
ipc_post(code, tag, 1, err);
} }
} }
@ -107,12 +126,13 @@ void __nand_set_address(s32 page_off, s32 pageno) {
void __nand_setup_dma(u8 *data, u8 *spare) { void __nand_setup_dma(u8 *data, u8 *spare) {
NAND_debug("nand_setup_dma: %p, %p\n", data, spare); NAND_debug("nand_setup_dma: %p, %p\n", data, spare);
if (((s32)data) != -1) { if (((s32)data) != -1) {
dc_invalidaterange(data, 0x800);
__nand_write32(NAND_DATA, dma_addr(data)); __nand_write32(NAND_DATA, dma_addr(data));
} }
if (((s32)spare) != -1) { if (((s32)spare) != -1) {
dc_invalidaterange(spare, 0x50); // +0x10 for calculated syndrome? u32 addr = dma_addr(spare);
__nand_write32(NAND_ECC, dma_addr(spare)); if(addr & 0x7f)
gecko_printf("NAND: Spare buffer 0x%08x is not aligned, data will be corrupted\n", addr);
__nand_write32(NAND_ECC, addr);
} }
} }
@ -152,8 +172,8 @@ void nand_read_page(u32 pageno, void *data, void *ecc) {
__nand_set_address(0, pageno); __nand_set_address(0, pageno);
nand_send_command(NAND_READ_PRE, 0x1f, 0, 0); nand_send_command(NAND_READ_PRE, 0x1f, 0, 0);
dc_invalidaterange(data, 0x800); dc_invalidaterange(data, PAGE_SIZE);
dc_invalidaterange(ecc, 0x50); dc_invalidaterange(ecc, ECC_BUFFER_SIZE);
__nand_setup_dma(data, ecc); __nand_setup_dma(data, ecc);
nand_send_command(NAND_READ_POST, 0, NAND_FLAGS_IRQ | NAND_FLAGS_WAIT | NAND_FLAGS_RD | NAND_FLAGS_ECC, 0x840); nand_send_command(NAND_READ_POST, 0, NAND_FLAGS_IRQ | NAND_FLAGS_WAIT | NAND_FLAGS_RD | NAND_FLAGS_ECC, 0x840);
@ -170,8 +190,8 @@ void nand_write_page(u32 pageno, void *data, void *ecc) {
printf("Error: nand_write to page %d forbidden\n", pageno); printf("Error: nand_write to page %d forbidden\n", pageno);
return; return;
} }
dc_flushrange(data, 0x800); dc_flushrange(data, PAGE_SIZE);
dc_flushrange(ecc, 0x40); dc_flushrange(ecc, PAGE_SPARE_SIZE);
__nand_set_address(0, pageno); __nand_set_address(0, pageno);
__nand_setup_dma(data, ecc); __nand_setup_dma(data, ecc);
nand_send_command(NAND_WRITE_PRE, 0x1f, NAND_FLAGS_IRQ | NAND_FLAGS_WR | NAND_FLAGS_ECC, 0x840); nand_send_command(NAND_WRITE_PRE, 0x1f, NAND_FLAGS_IRQ | NAND_FLAGS_WR | NAND_FLAGS_ECC, 0x840);
@ -195,7 +215,7 @@ void nand_erase_block(u32 pageno) {
void nand_initialize(void) void nand_initialize(void)
{ {
ipc_code = ipc_tag = 0; current_request.code = 0;
nand_reset(); nand_reset();
irq_enable(IRQ_NAND); irq_enable(IRQ_NAND);
} }
@ -244,12 +264,11 @@ int nand_correct(u32 pageno, void *data, void *ecc)
void nand_ipc(volatile ipc_request *req) void nand_ipc(volatile ipc_request *req)
{ {
if (ipc_code != 0 || ipc_tag != 0) { if (current_request.code != 0) {
gecko_printf("NAND: previous IPC request is not done yet."); gecko_printf("NAND: previous IPC request is not done yet.");
ipc_post(req->code, req->tag, 1, -1); ipc_post(req->code, req->tag, 1, -1);
return; return;
} }
switch (req->req) { switch (req->req) {
case IPC_NAND_RESET: case IPC_NAND_RESET:
nand_reset(); nand_reset();
@ -257,9 +276,8 @@ void nand_ipc(volatile ipc_request *req)
break; break;
case IPC_NAND_GETID: case IPC_NAND_GETID:
ipc_code = req->code; current_request = *req;
ipc_tag = req->tag; nand_get_id(ipc_data);
nand_get_id((u8 *)req->args[0]);
break; break;
case IPC_NAND_STATUS: case IPC_NAND_STATUS:
@ -269,23 +287,22 @@ void nand_ipc(volatile ipc_request *req)
break; break;
case IPC_NAND_READ: case IPC_NAND_READ:
ipc_code = req->code; current_request = *req;
ipc_tag = req->tag; nand_read_page(req->args[0], ipc_data, ipc_ecc);
nand_read_page(req->args[0], (void *)req->args[1],
(void *)req->args[2]);
break; break;
#ifdef NAND_SUPPORT_WRITE #ifdef NAND_SUPPORT_WRITE
case IPC_NAND_WRITE: case IPC_NAND_WRITE:
ipc_code = req->code; current_request = *req;
ipc_tag = req->tag; dc_invalidaterange((void*)req->args[1], PAGE_SIZE);
nand_write_page(req->args[0], (void *)req->args[1], dc_invalidaterange((void*)req->args[2], PAGE_SPARE_SIZE);
(void *)req->args[2]); memcpy(ipc_data, (void*)req->args[1], PAGE_SIZE);
memcpy(ipc_ecc, (void*)req->args[2], PAGE_SPARE_SIZE);
nand_write_page(req->args[0], ipc_data, ipc_ecc);
break; break;
#endif #endif
#ifdef NAND_SUPPORT_ERASE #ifdef NAND_SUPPORT_ERASE
case IPC_NAND_ERASE: case IPC_NAND_ERASE:
ipc_code = req->code; current_request = *req;
ipc_tag = req->tag;
nand_erase_block(req->args[0]); nand_erase_block(req->args[0]);
break; break;
#endif #endif