NAND finally working. Two bugs fixed:
* For READ_STATUS and READID commands always 8 bytes need to be read from NDDB. Otherwise they stay there and get send to flash as the first data word when writing. * In nand_base.c the oob variable is not reset so this->oob_buf is overwritten what eventually screws up the bad block descriptor table.
This commit is contained in:
parent
bf7cac033b
commit
f9e029184b
|
@ -31,8 +31,13 @@
|
||||||
/* mk@tbd move this to pxa-regs */
|
/* mk@tbd move this to pxa-regs */
|
||||||
#define OSCR_CLK_FREQ 3.250 /* MHz */
|
#define OSCR_CLK_FREQ 3.250 /* MHz */
|
||||||
|
|
||||||
|
/* usefull */
|
||||||
#define CFG_DFC_DEBUG1
|
#define CFG_DFC_DEBUG1
|
||||||
#define CFG_DFC_DEBUG2
|
/* noisy */
|
||||||
|
#undef CFG_DFC_DEBUG2
|
||||||
|
/* wild west */
|
||||||
|
#undef CFG_DFC_DEBUG3
|
||||||
|
|
||||||
|
|
||||||
#ifdef CFG_DFC_DEBUG1
|
#ifdef CFG_DFC_DEBUG1
|
||||||
# define DFC_DEBUG1(fmt, args...) printf(fmt, ##args)
|
# define DFC_DEBUG1(fmt, args...) printf(fmt, ##args)
|
||||||
|
@ -46,6 +51,12 @@
|
||||||
# define DFC_DEBUG2(fmt, args...)
|
# define DFC_DEBUG2(fmt, args...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CFG_DFC_DEBUG3
|
||||||
|
# define DFC_DEBUG3(fmt, args...) printf(fmt, ##args)
|
||||||
|
#else
|
||||||
|
# define DFC_DEBUG3(fmt, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
|
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
|
||||||
|
|
||||||
static struct nand_bbt_descr delta_bbt_descr = {
|
static struct nand_bbt_descr delta_bbt_descr = {
|
||||||
|
@ -56,7 +67,7 @@ static struct nand_bbt_descr delta_bbt_descr = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nand_oobinfo delta_oob = {
|
static struct nand_oobinfo delta_oob = {
|
||||||
.useecc = MTD_NANDECC_AUTOPLACE,
|
.useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
|
||||||
.eccbytes = 6,
|
.eccbytes = 6,
|
||||||
.eccpos = {2, 3, 4, 5, 6, 7},
|
.eccpos = {2, 3, 4, 5, 6, 7},
|
||||||
.oobfree = { {8, 2}, {12, 4} }
|
.oobfree = { {8, 2}, {12, 4} }
|
||||||
|
@ -90,7 +101,8 @@ static void delta_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
unsigned long rest = len & 0x3;
|
unsigned long rest = len & 0x3;
|
||||||
unsigned long *long_buf;
|
unsigned long *long_buf;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
DFC_DEBUG2("delta_write_buf: writing %d bytes starting with 0x%x.\n", len, *((unsigned long*) buf));
|
||||||
if(bytes_multi) {
|
if(bytes_multi) {
|
||||||
for(i=0; i<bytes_multi; i+=4) {
|
for(i=0; i<bytes_multi; i+=4) {
|
||||||
long_buf = (unsigned long*) &buf[i];
|
long_buf = (unsigned long*) &buf[i];
|
||||||
|
@ -138,6 +150,7 @@ static void delta_read_buf(struct mtd_info *mtd, u_char* const buf, int len)
|
||||||
unsigned long rest = len & 0x3;
|
unsigned long rest = len & 0x3;
|
||||||
unsigned long *long_buf;
|
unsigned long *long_buf;
|
||||||
|
|
||||||
|
DFC_DEBUG3("delta_read_buf: reading %d bytes.\n", len);
|
||||||
/* if there are any, first copy multiple of 4 bytes */
|
/* if there are any, first copy multiple of 4 bytes */
|
||||||
if(bytes_multi) {
|
if(bytes_multi) {
|
||||||
for(i=0; i<bytes_multi; i+=4) {
|
for(i=0; i<bytes_multi; i+=4) {
|
||||||
|
@ -167,6 +180,7 @@ static u16 delta_read_word(struct mtd_info *mtd)
|
||||||
/* global var, too bad: mk@tbd: move to ->priv pointer */
|
/* global var, too bad: mk@tbd: move to ->priv pointer */
|
||||||
static unsigned long read_buf = 0;
|
static unsigned long read_buf = 0;
|
||||||
static int bytes_read = -1;
|
static int bytes_read = -1;
|
||||||
|
static unsigned long last_cmd = 0;
|
||||||
|
|
||||||
/* read a byte from NDDB Because we can only read 4 bytes from NDDB at
|
/* read a byte from NDDB Because we can only read 4 bytes from NDDB at
|
||||||
* a time, we buffer the remaining bytes. The buffer is reset when a
|
* a time, we buffer the remaining bytes. The buffer is reset when a
|
||||||
|
@ -176,16 +190,18 @@ static u_char delta_read_byte(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
/* struct nand_chip *this = mtd->priv; */
|
/* struct nand_chip *this = mtd->priv; */
|
||||||
unsigned char byte;
|
unsigned char byte;
|
||||||
|
unsigned long dummy;
|
||||||
|
|
||||||
if(bytes_read < 0) {
|
if(bytes_read < 0) {
|
||||||
read_buf = NDDB;
|
read_buf = NDDB;
|
||||||
|
dummy = NDDB;
|
||||||
bytes_read = 0;
|
bytes_read = 0;
|
||||||
}
|
}
|
||||||
byte = (unsigned char) (read_buf>>(8 * bytes_read++));
|
byte = (unsigned char) (read_buf>>(8 * bytes_read++));
|
||||||
if(bytes_read >= 4)
|
if(bytes_read >= 4)
|
||||||
bytes_read = -1;
|
bytes_read = -1;
|
||||||
|
|
||||||
DFC_DEBUG2("delta_read_byte: byte %u: 0x%x of (0x%x).\n", bytes_read, byte, read_buf);
|
DFC_DEBUG2("delta_read_byte: byte %u: 0x%x of (0x%x).\n", bytes_read - 1, byte, read_buf);
|
||||||
return byte;
|
return byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,13 +346,15 @@ static void delta_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||||
/* clear the ugly byte read buffer */
|
/* clear the ugly byte read buffer */
|
||||||
bytes_read = -1;
|
bytes_read = -1;
|
||||||
read_buf = 0;
|
read_buf = 0;
|
||||||
|
last_cmd = 0;
|
||||||
|
|
||||||
/* if command is a double byte cmd, we set bit double cmd bit 19 */
|
/* if command is a double byte cmd, we set bit double cmd bit 19 */
|
||||||
/* command2 = (command>>8) & 0xFF; */
|
/* command2 = (command>>8) & 0xFF; */
|
||||||
/* ndcb0 = command | ((command2 ? 1 : 0) << 19); *\/ */
|
/* ndcb0 = command | ((command2 ? 1 : 0) << 19); *\/ */
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case NAND_CMD_READ0:
|
case NAND_CMD_READ0:
|
||||||
|
DFC_DEBUG3("delta_cmdfunc: NAND_CMD_READ0, page_addr: 0x%x, column: 0x%x.\n", page_addr, (column>>1));
|
||||||
delta_new_cmd();
|
delta_new_cmd();
|
||||||
ndcb0 = (NAND_CMD_READ0 | (4<<16));
|
ndcb0 = (NAND_CMD_READ0 | (4<<16));
|
||||||
column >>= 1; /* adjust for 16 bit bus */
|
column >>= 1; /* adjust for 16 bit bus */
|
||||||
|
@ -346,7 +364,14 @@ static void delta_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||||
((page_addr<<8) & 0xff000000)); /* make this 0x01000000 ? */
|
((page_addr<<8) & 0xff000000)); /* make this 0x01000000 ? */
|
||||||
event = NDSR_RDDREQ;
|
event = NDSR_RDDREQ;
|
||||||
goto write_cmd;
|
goto write_cmd;
|
||||||
|
case NAND_CMD_READ1:
|
||||||
|
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_READ1 unimplemented!\n");
|
||||||
|
goto end;
|
||||||
|
case NAND_CMD_READOOB:
|
||||||
|
DFC_DEBUG1("delta_cmdfunc: NAND_CMD_READOOB unimplemented!\n");
|
||||||
|
goto end;
|
||||||
case NAND_CMD_READID:
|
case NAND_CMD_READID:
|
||||||
|
last_cmd = NAND_CMD_READID;
|
||||||
delta_new_cmd();
|
delta_new_cmd();
|
||||||
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_READID.\n");
|
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_READID.\n");
|
||||||
ndcb0 = (NAND_CMD_READID | (3 << 21) | (1 << 16)); /* addr cycles*/
|
ndcb0 = (NAND_CMD_READID | (3 << 21) | (1 << 16)); /* addr cycles*/
|
||||||
|
@ -357,7 +382,7 @@ static void delta_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||||
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_PAGEPROG empty due to multicmd.\n");
|
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_PAGEPROG empty due to multicmd.\n");
|
||||||
goto end;
|
goto end;
|
||||||
case NAND_CMD_ERASE1:
|
case NAND_CMD_ERASE1:
|
||||||
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_ERASE1.\n");
|
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_ERASE1, page_addr: 0x%x, column: 0x%x.\n", page_addr, (column>>1));
|
||||||
delta_new_cmd();
|
delta_new_cmd();
|
||||||
ndcb0 = (0xd060 | (1<<25) | (2<<21) | (1<<19) | (3<<16));
|
ndcb0 = (0xd060 | (1<<25) | (2<<21) | (1<<19) | (3<<16));
|
||||||
ndcb1 = (page_addr & 0x00ffffff);
|
ndcb1 = (page_addr & 0x00ffffff);
|
||||||
|
@ -368,7 +393,7 @@ static void delta_cmdfunc(struct mtd_info *mtd, unsigned command,
|
||||||
case NAND_CMD_SEQIN:
|
case NAND_CMD_SEQIN:
|
||||||
/* send PAGE_PROG command(0x1080) */
|
/* send PAGE_PROG command(0x1080) */
|
||||||
delta_new_cmd();
|
delta_new_cmd();
|
||||||
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG.\n");
|
DFC_DEBUG2("delta_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, page_addr: 0x%x, column: 0x%x.\n", page_addr, (column>>1));
|
||||||
ndcb0 = (0x1080 | (1<<25) | (1<<21) | (1<<19) | (4<<16));
|
ndcb0 = (0x1080 | (1<<25) | (1<<21) | (1<<19) | (4<<16));
|
||||||
column >>= 1; /* adjust for 16 bit bus */
|
column >>= 1; /* adjust for 16 bit bus */
|
||||||
ndcb1 = (((column>>1) & 0xff) |
|
ndcb1 = (((column>>1) & 0xff) |
|
||||||
|
@ -562,6 +587,7 @@ void board_nand_init(struct nand_chip *nand)
|
||||||
#define MIN(x, y) ((x < y) ? x : y)
|
#define MIN(x, y) ((x < y) ? x : y)
|
||||||
|
|
||||||
|
|
||||||
|
#undef CFG_TIMING_TIGHT
|
||||||
#ifndef CFG_TIMING_TIGHT
|
#ifndef CFG_TIMING_TIGHT
|
||||||
tCH = MIN(((unsigned long) (NAND_TIMING_tCH * DFC_CLK_PER_US) + 1),
|
tCH = MIN(((unsigned long) (NAND_TIMING_tCH * DFC_CLK_PER_US) + 1),
|
||||||
DFC_MAX_tCH);
|
DFC_MAX_tCH);
|
||||||
|
@ -646,7 +672,7 @@ void board_nand_init(struct nand_chip *nand)
|
||||||
NDCR = (NDCR_SPARE_EN | /* use the spare area */
|
NDCR = (NDCR_SPARE_EN | /* use the spare area */
|
||||||
NDCR_DWIDTH_C | /* 16bit DFC data bus width */
|
NDCR_DWIDTH_C | /* 16bit DFC data bus width */
|
||||||
NDCR_DWIDTH_M | /* 16 bit Flash device data bus width */
|
NDCR_DWIDTH_M | /* 16 bit Flash device data bus width */
|
||||||
(7 << 16) | /* read id count = 7 ???? mk@tbd */
|
(2 << 16) | /* read id count = 7 ???? mk@tbd */
|
||||||
NDCR_ND_ARB_EN | /* enable bus arbiter */
|
NDCR_ND_ARB_EN | /* enable bus arbiter */
|
||||||
NDCR_RDYM | /* flash device ready ir masked */
|
NDCR_RDYM | /* flash device ready ir masked */
|
||||||
NDCR_CS0_PAGEDM | /* ND_nCSx page done ir masked */
|
NDCR_CS0_PAGEDM | /* ND_nCSx page done ir masked */
|
||||||
|
|
|
@ -489,6 +489,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
return nand_write_oob (mtd, ofs , 2, &retlen, buf);
|
return nand_write_oob (mtd, ofs , 2, &retlen, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if READ_STATUS_BUG
|
||||||
/**
|
/**
|
||||||
* nand_check_wp - [GENERIC] check if the chip is write protected
|
* nand_check_wp - [GENERIC] check if the chip is write protected
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
|
@ -503,7 +504,12 @@ static int nand_check_wp (struct mtd_info *mtd)
|
||||||
this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
|
this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
|
||||||
return (this->read_byte(mtd) & 0x80) ? 0 : 1;
|
return (this->read_byte(mtd) & 0x80) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static int nand_check_wp (struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
|
@ -1721,6 +1727,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
numpages = min (totalpages, ppblock);
|
numpages = min (totalpages, ppblock);
|
||||||
page &= this->pagemask;
|
page &= this->pagemask;
|
||||||
startpage = page;
|
startpage = page;
|
||||||
|
oob = 0;
|
||||||
|
this->oobdirty = 1;
|
||||||
oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel,
|
oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel,
|
||||||
autoplace, numpages);
|
autoplace, numpages);
|
||||||
/* Check, if we cross a chip boundary */
|
/* Check, if we cross a chip boundary */
|
||||||
|
@ -2145,13 +2153,14 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
|
||||||
instr->state = MTD_ERASING;
|
instr->state = MTD_ERASING;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
|
#ifndef NAND_ALLOW_ERASE_ALL
|
||||||
/* Check if we have a bad block, we do not erase bad blocks ! */
|
/* Check if we have a bad block, we do not erase bad blocks ! */
|
||||||
if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
|
if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
|
||||||
printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
|
printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
|
||||||
instr->state = MTD_ERASE_FAILED;
|
instr->state = MTD_ERASE_FAILED;
|
||||||
goto erase_exit;
|
goto erase_exit;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
/* Invalidate the page cache, if we erase the block which contains
|
/* Invalidate the page cache, if we erase the block which contains
|
||||||
the current cached page */
|
the current cached page */
|
||||||
if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
|
if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
/*
|
/*
|
||||||
* Size of malloc() pool
|
* Size of malloc() pool
|
||||||
*/
|
*/
|
||||||
#define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128*1024)
|
#define CFG_MALLOC_LEN (CFG_ENV_SIZE + 256*1024)
|
||||||
#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
|
#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -164,7 +164,7 @@
|
||||||
*/
|
*/
|
||||||
/* Use the new NAND code. (BOARDLIBS = drivers/nand/libnand.a required) */
|
/* Use the new NAND code. (BOARDLIBS = drivers/nand/libnand.a required) */
|
||||||
#define CONFIG_NEW_NAND_CODE
|
#define CONFIG_NEW_NAND_CODE
|
||||||
#define CFG_NAND0_BASE 0x43100040 /* 0x10000000 */
|
#define CFG_NAND0_BASE 0x0 /* 0x43100040 */ /* 0x10000000 */
|
||||||
#undef CFG_NAND1_BASE
|
#undef CFG_NAND1_BASE
|
||||||
|
|
||||||
#define CFG_NAND_BASE_LIST { CFG_NAND0_BASE }
|
#define CFG_NAND_BASE_LIST { CFG_NAND0_BASE }
|
||||||
|
@ -174,9 +174,13 @@
|
||||||
#define NAND_DELAY_US 25 /* mk@tbd: could be 0, I guess */
|
#define NAND_DELAY_US 25 /* mk@tbd: could be 0, I guess */
|
||||||
|
|
||||||
/* nand timeout values */
|
/* nand timeout values */
|
||||||
#define CFG_NAND_PROG_ERASE_TO 300
|
#define CFG_NAND_PROG_ERASE_TO 3000
|
||||||
#define CFG_NAND_OTHER_TO 100
|
#define CFG_NAND_OTHER_TO 100
|
||||||
#define CFG_NAND_SENDCMD_RETRY 3
|
#define CFG_NAND_SENDCMD_RETRY 3
|
||||||
|
#define NAND_ALLOW_ERASE_ALL 1
|
||||||
|
|
||||||
|
#define CONFIG_MTD_DEBUG
|
||||||
|
#define CONFIG_MTD_DEBUG_VERBOSE 1
|
||||||
|
|
||||||
#define ADDR_COLUMN 1
|
#define ADDR_COLUMN 1
|
||||||
#define ADDR_PAGE 2
|
#define ADDR_PAGE 2
|
||||||
|
|
Loading…
Reference in New Issue