Onda VX747: get NAND driver working

generic NAND ID driver: clean up


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19817 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Maurus Cuelenaere 2009-01-22 00:04:20 +00:00
parent e79fc8aaef
commit 311d2f12ed
3 changed files with 66 additions and 54 deletions

View file

@ -29,30 +29,33 @@ struct nand_manufacturer
unsigned short total; unsigned short total;
}; };
/* { pages_per_block, blocks_per_bank, page_size, spare_size, col_cycles, row_cycles } */
static const struct nand_info samsung[] = static const struct nand_info samsung[] =
{ {
/* { id1, id2, pages_per_block, blocks_per_bank, page_size, spare_size, col_cycles, row_cycles } */
/* K9F4G08UOM */ /* K9F4G08UOM */
{0xDC, 0x10, 64, 4096, 2048, 64, 2, 3}, {0xDC, 0x10, 64, 4096, 2048, 64, 2, 3 },
/* K9K8G08UOM */ /* K9K8G08UOM */
{0xD3, 0x51, 64, 8192, 2048, 64, 2, 3}, {0xD3, 0x51, 64, 8192, 2048, 64, 2, 3 },
/* K9LAG08UOM */ /* K9LAG08UOM */
{0xD5, 0x55, 128, 8192, 2048, 64, 2, 3}, {0xD5, 0x55, 128, 8192, 2048, 64, 2, 3 },
/* K9LBG08UOM, K9HBG08U1M, K9MCG08U5M */ /* K9LBG08UOM, K9HBG08U1M, K9MCG08U5M */
{0xD7, 0x55, 128, 8192, 4096, 128, 2, 3} {0xD7, 0x55, 128, 8192, 4096, 128, 2, 3 },
}; };
#define M(id, x) {id, (struct nand_info*)x, (sizeof(x)/sizeof(struct nand_info))} #define NI(id, x) {id, (struct nand_info*)x, (sizeof(x)/sizeof(struct nand_info))}
static const struct nand_manufacturer all[] = static const struct nand_manufacturer all[] =
{ {
M(0xEC, samsung), NI(0xEC, samsung),
}; };
// --------------------------------------------------------------------------------------------------
struct nand_info* nand_identify(unsigned char data[5]) struct nand_info* nand_identify(unsigned char data[5])
{ {
unsigned int i; unsigned int i;
int found = -1; int found = -1;
for(i = 0; i < (sizeof(all)/sizeof(struct nand_manufacturer)); i++) for(i = 0; i < (sizeof(all)/sizeof(struct nand_manufacturer)); i++)
{ {
if(data[0] == all[i].id) if(data[0] == all[i].id)
@ -61,6 +64,7 @@ struct nand_info* nand_identify(unsigned char data[5])
break; break;
} }
} }
if(found < 0) if(found < 0)
return NULL; return NULL;

View file

@ -1770,6 +1770,8 @@
#define EMC_NFCSR_NFE2 (1 << 2) #define EMC_NFCSR_NFE2 (1 << 2)
#define EMC_NFCSR_NFCE1 (1 << 1) #define EMC_NFCSR_NFCE1 (1 << 1)
#define EMC_NFCSR_NFE1 (1 << 0) #define EMC_NFCSR_NFE1 (1 << 0)
#define EMC_NFCSR_NFE(n) (1 << (((n)-1)*2))
#define EMC_NFCSR_NFCE(n) (1 << (((n)*2)-1))
/* NAND Flash ECC Control Register */ /* NAND Flash ECC Control Register */
#define EMC_NFECR_PRDY (1 << 4) /* Parity Ready */ #define EMC_NFECR_PRDY (1 << 4) /* Parity Ready */

View file

@ -30,8 +30,10 @@
#include "storage.h" #include "storage.h"
#include "buffer.h" #include "buffer.h"
#include "string.h" #include "string.h"
#include "logf.h"
//#define USE_DMA //#define USE_DMA
//#define USE_ECC
/* /*
* Standard NAND flash commands * Standard NAND flash commands
@ -69,8 +71,8 @@ struct nand_param
{ {
unsigned int bus_width; /* data bus width: 8-bit/16-bit */ unsigned int bus_width; /* data bus width: 8-bit/16-bit */
unsigned int row_cycle; /* row address cycles: 2/3 */ unsigned int row_cycle; /* row address cycles: 2/3 */
unsigned int page_size; /* page size in bytes: 512/2048 */ unsigned int page_size; /* page size in bytes: 512/2048/4096 */
unsigned int oob_size; /* oob size in bytes: 16/64 */ unsigned int oob_size; /* oob size in bytes: 16/64/128 */
unsigned int page_per_block; /* pages per block: 32/64/128 */ unsigned int page_per_block; /* pages per block: 32/64/128 */
}; };
@ -83,9 +85,9 @@ struct nand_param
* *
*/ */
#define NAND_DATAPORT 0xb8000000 #define NAND_DATAPORT 0xB8000000
#define NAND_ADDRPORT 0xb8010000 #define NAND_ADDRPORT 0xB8010000
#define NAND_COMMPORT 0xb8008000 #define NAND_COMMPORT 0xB8008000
#define ECC_BLOCK 512 #define ECC_BLOCK 512
#define ECC_POS 6 #define ECC_POS 6
@ -93,8 +95,8 @@ struct nand_param
#define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n))
#define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n))
#define __nand_data8() REG8(NAND_DATAPORT) #define __nand_data8() (REG8(NAND_DATAPORT))
#define __nand_data16() REG16(NAND_DATAPORT) #define __nand_data16() (REG16(NAND_DATAPORT))
#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) #define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1)
#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) #define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1))
@ -118,17 +120,16 @@ static unsigned char temp_page[4096]; /* Max page size */
static inline void jz_nand_wait_ready(void) static inline void jz_nand_wait_ready(void)
{ {
unsigned int timeout = 1000; register unsigned int timeout = 1000;
while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--); while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--);
while (!(REG_GPIO_PXPIN(2) & 0x40000000)); while (!(REG_GPIO_PXPIN(2) & 0x40000000));
} }
#ifndef USE_DMA #ifndef USE_DMA
static inline void jz_nand_read_buf16(void *buf, int count) static inline void jz_nand_read_buf16(void *buf, int count)
{ {
int i; register int i;
unsigned short *p = (unsigned short *)buf; register unsigned short *p = (unsigned short *)buf;
for (i = 0; i < count; i += 2) for (i = 0; i < count; i += 2)
*p++ = __nand_data16(); *p++ = __nand_data16();
@ -136,15 +137,13 @@ static inline void jz_nand_read_buf16(void *buf, int count)
static inline void jz_nand_read_buf8(void *buf, int count) static inline void jz_nand_read_buf8(void *buf, int count)
{ {
int i; register int i;
unsigned char *p = (unsigned char *)buf; register unsigned char *p = (unsigned char *)buf;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
*p++ = __nand_data8(); *p++ = __nand_data8();
} }
#else #else
static void jz_nand_write_dma(void *source, unsigned int len, int bw) static void jz_nand_write_dma(void *source, unsigned int len, int bw)
{ {
mutex_lock(&nand_mtx); mutex_lock(&nand_mtx);
@ -226,8 +225,7 @@ void DMA_CALLBACK(DMA_NAND_CHANNEL)(void)
wakeup_signal(&nand_wkup); wakeup_signal(&nand_wkup);
} }
#endif /* USE_DMA */
#endif
static inline void jz_nand_read_buf(void *buf, int count, int bw) static inline void jz_nand_read_buf(void *buf, int count, int bw)
{ {
@ -244,6 +242,7 @@ static inline void jz_nand_read_buf(void *buf, int count, int bw)
#endif #endif
} }
#ifdef USE_ECC
/* /*
* Correct 1~9-bit errors in 512-bytes data * Correct 1~9-bit errors in 512-bytes data
*/ */
@ -258,7 +257,8 @@ static void jz_rs_correct(unsigned char *dat, int idx, int mask)
i = (j == 0) ? (i - 1) : i; i = (j == 0) ? (i - 1) : i;
j = (j == 0) ? 7 : (j - 1); j = (j == 0) ? 7 : (j - 1);
if (i > 512) return; if (i > 512)
return;
if (i == 512) if (i == 512)
d = dat[i - 1]; d = dat[i - 1];
@ -275,11 +275,12 @@ static void jz_rs_correct(unsigned char *dat, int idx, int mask)
if (i < 512) if (i < 512)
dat[i] = (d >> 8) & 0xff; dat[i] = (d >> 8) & 0xff;
} }
#endif
/* /*
* Read oob * Read oob
*/ */
static int jz_nand_read_oob(int page_addr, unsigned char *buf, int size) static int jz_nand_read_oob(unsigned long page_addr, unsigned char *buf, int size)
{ {
struct nand_param *nandp = &internal_param; struct nand_param *nandp = &internal_param;
int page_size, row_cycle, bus_width; int page_size, row_cycle, bus_width;
@ -335,14 +336,14 @@ static int jz_nand_read_oob(int page_addr, unsigned char *buf, int size)
* page - page number within a block: 0, 1, 2, ... * page - page number within a block: 0, 1, 2, ...
* dst - pointer to target buffer * dst - pointer to target buffer
*/ */
static int jz_nand_read_page(int block, int page, unsigned char *dst) static int jz_nand_read_page(unsigned long page_addr, unsigned char *dst)
{ {
struct nand_param *nandp = &internal_param; struct nand_param *nandp = &internal_param;
int page_size, oob_size, page_per_block; int page_size, oob_size, page_per_block;
int row_cycle, bus_width, ecc_count; int row_cycle, bus_width, ecc_count;
int page_addr, i, j; int i, j;
unsigned char *data_buf; unsigned char *data_buf;
unsigned char oob_buf[128]; unsigned char oob_buf[nandp->oob_size];
page_size = nandp->page_size; page_size = nandp->page_size;
oob_size = nandp->oob_size; oob_size = nandp->oob_size;
@ -350,8 +351,6 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst)
row_cycle = nandp->row_cycle; row_cycle = nandp->row_cycle;
bus_width = nandp->bus_width; bus_width = nandp->bus_width;
page_addr = page + block * page_per_block;
/* /*
* Read oob data * Read oob data
*/ */
@ -372,7 +371,7 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst)
/* Send page address */ /* Send page address */
__nand_addr(page_addr & 0xff); __nand_addr(page_addr & 0xff);
__nand_addr((page_addr >> 8) & 0xff); __nand_addr((page_addr >> 8) & 0xff);
if (row_cycle == 3) if (row_cycle >= 3)
__nand_addr((page_addr >> 16) & 0xff); __nand_addr((page_addr >> 16) & 0xff);
/* Send READSTART command for 2048 ps NAND */ /* Send READSTART command for 2048 ps NAND */
@ -389,16 +388,19 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst)
for (i = 0; i < ecc_count; i++) for (i = 0; i < ecc_count; i++)
{ {
#ifdef USE_ECC
volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0; volatile unsigned char *paraddr = (volatile unsigned char *)EMC_NFPAR0;
unsigned int stat; unsigned int stat;
/* Enable RS decoding */ /* Enable RS decoding */
REG_EMC_NFINTS = 0x0; REG_EMC_NFINTS = 0x0;
__nand_ecc_rs_decoding(); __nand_ecc_rs_decoding();
#endif
/* Read data */ /* Read data */
jz_nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width); jz_nand_read_buf((void *)data_buf, ECC_BLOCK, bus_width);
#ifdef USE_ECC
/* Set PAR values */ /* Set PAR values */
for (j = 0; j < PAR_SIZE; j++) for (j = 0; j < PAR_SIZE; j++)
*paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j]; *paraddr++ = oob_buf[ECC_POS + i*PAR_SIZE + j];
@ -420,7 +422,7 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst)
if (stat & EMC_NFINTS_UNCOR) if (stat & EMC_NFINTS_UNCOR)
{ {
/* Uncorrectable error occurred */ /* Uncorrectable error occurred */
panicf("Uncorrectable ECC error at NAND page 0x%x block 0x%x", page, block); panicf("Uncorrectable ECC error at NAND page address 0x%lx", page_addr);
return -1; return -1;
} }
else else
@ -452,6 +454,7 @@ static int jz_nand_read_page(int block, int page, unsigned char *dst)
} }
} }
} }
#endif
data_buf += ECC_BLOCK; data_buf += ECC_BLOCK;
} }
@ -502,7 +505,7 @@ static int jz_nand_init(void)
internal_param.bus_width = 8; internal_param.bus_width = 8;
internal_param.row_cycle = chip_info->row_cycles; internal_param.row_cycle = chip_info->row_cycles;
internal_param.page_size = chip_info->page_size; internal_param.page_size = chip_info->page_size;
internal_param.oob_size = chip_info->page_size/32; internal_param.oob_size = chip_info->spare_size;
internal_param.page_per_block = chip_info->pages_per_block; internal_param.page_per_block = chip_info->pages_per_block;
return 0; return 0;
@ -532,21 +535,24 @@ int nand_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* b
{ {
int i, ret = 0; int i, ret = 0;
logf("nand_read_sectors(%ld, %d, 0x%x)", start, count, (int)buf);
start *= 512; start *= 512;
count *= 512; count *= 512;
if(count <= chip_info->page_size) if(count <= chip_info->page_size)
{ {
ret = jz_nand_read_page(start % (chip_info->page_size * chip_info->pages_per_block), start % chip_info->page_size, temp_page); ret = jz_nand_read_page(start/chip_info->page_size, temp_page);
memcpy(buf, temp_page, count); memcpy(buf, temp_page+(start%chip_info->page_size), count);
return ret; return ret;
} }
else else
{ {
for(i=0; i<count && ret == 0; i+=chip_info->page_size) for(i=0; i<count && ret==0; i+=chip_info->page_size)
{ {
ret = jz_nand_read_page((start+i) % (chip_info->page_size * chip_info->pages_per_block), (start+i) % chip_info->page_size, temp_page); ret = jz_nand_read_page((start+i)/chip_info->page_size, temp_page);
memcpy(buf+i, temp_page, (count-i < chip_info->page_size ? count-i : chip_info->page_size)); memcpy(buf+i, temp_page+((start+i)%chip_info->page_size),
(count-i < chip_info->page_size ? count-i : chip_info->page_size));
} }
return ret; return ret;
} }
@ -607,7 +613,7 @@ void nand_get_info(IF_MV2(int drive,) struct storage_info *info)
/* blocks count */ /* blocks count */
/* TODO: proper amount of sectors! */ /* TODO: proper amount of sectors! */
info->num_sectors = (chip_info->page_size / 512) * chip_info->pages_per_block * chip_info->blocks_per_bank; info->num_sectors = ((chip_info->page_size+chip_info->spare_size) / 512) * chip_info->pages_per_block * chip_info->blocks_per_bank;
info->sector_size = 512; info->sector_size = 512;
} }
#endif #endif