mirror of
https://github.com/fail0verflow/mini.git
synced 2024-11-28 14:14:18 +01:00
Add shadow buffer for NAND IPC to prevent MEM1 issues, fix some stuff
This commit is contained in:
parent
d1f9fa8a3a
commit
8ce5433382
81
nand.c
81
nand.c
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user