diff options
-rw-r--r-- | onenand_ipl/onenand_boot.c | 2 | ||||
-rw-r--r-- | onenand_ipl/onenand_ipl.h | 8 | ||||
-rw-r--r-- | onenand_ipl/onenand_read.c | 58 |
3 files changed, 44 insertions, 24 deletions
diff --git a/onenand_ipl/onenand_boot.c b/onenand_ipl/onenand_boot.c index 86428cc052..63995ce504 100644 --- a/onenand_ipl/onenand_boot.c +++ b/onenand_ipl/onenand_boot.c @@ -36,7 +36,7 @@ void start_oneboot(void) buf = (uchar *) CONFIG_SYS_LOAD_ADDR; - onenand_read_block0(buf); + onenand_read_block(buf); ((init_fnc_t *)CONFIG_SYS_LOAD_ADDR)(); diff --git a/onenand_ipl/onenand_ipl.h b/onenand_ipl/onenand_ipl.h index 57e54f5cbc..412572a08d 100644 --- a/onenand_ipl/onenand_ipl.h +++ b/onenand_ipl/onenand_ipl.h @@ -23,15 +23,13 @@ #include <linux/mtd/onenand_regs.h> -#define onenand_readw(a) readw(a) -#define onenand_writew(v, a) writew(v, a) +#define onenand_readw(a) readw(THIS_ONENAND(a)) +#define onenand_writew(v, a) writew(v, THIS_ONENAND(a)) #define THIS_ONENAND(a) (CONFIG_SYS_ONENAND_BASE + (a)) #define READ_INTERRUPT() \ onenand_readw(THIS_ONENAND(ONENAND_REG_INTERRUPT)) -#define ONENAND_PAGE_SIZE 2048 - -extern int onenand_read_block0(unsigned char *buf); +extern int onenand_read_block(unsigned char *buf); #endif diff --git a/onenand_ipl/onenand_read.c b/onenand_ipl/onenand_read.c index 6d04943ba1..d1a842dd67 100644 --- a/onenand_ipl/onenand_read.c +++ b/onenand_ipl/onenand_read.c @@ -49,20 +49,20 @@ static inline int onenand_read_page(ulong block, ulong page, #endif onenand_writew(onenand_block_address(block), - THIS_ONENAND(ONENAND_REG_START_ADDRESS1)); + ONENAND_REG_START_ADDRESS1); onenand_writew(onenand_bufferram_address(block), - THIS_ONENAND(ONENAND_REG_START_ADDRESS2)); + ONENAND_REG_START_ADDRESS2); onenand_writew(onenand_sector_address(page), - THIS_ONENAND(ONENAND_REG_START_ADDRESS8)); + ONENAND_REG_START_ADDRESS8); onenand_writew(onenand_buffer_address(), - THIS_ONENAND(ONENAND_REG_START_BUFFER)); + ONENAND_REG_START_BUFFER); - onenand_writew(ONENAND_INT_CLEAR, THIS_ONENAND(ONENAND_REG_INTERRUPT)); + onenand_writew(ONENAND_INT_CLEAR, ONENAND_REG_INTERRUPT); - onenand_writew(ONENAND_CMD_READ, THIS_ONENAND(ONENAND_REG_COMMAND)); + onenand_writew(ONENAND_CMD_READ, ONENAND_REG_COMMAND); #ifndef __HAVE_ARCH_MEMCPY32 p = (unsigned long *) buf; @@ -72,6 +72,10 @@ static inline int onenand_read_page(ulong block, ulong page, while (!(READ_INTERRUPT() & ONENAND_INT_READ)) continue; + /* Check for invalid block mark */ + if (page < 2 && (onenand_readw(ONENAND_SPARERAM) != 0xffff)) + return 1; + #ifdef __HAVE_ARCH_MEMCPY32 /* 32 bytes boundary memory copy */ memcpy32(buf, base, pagesize); @@ -89,25 +93,43 @@ static inline int onenand_read_page(ulong block, ulong page, #define ONENAND_PAGES_PER_BLOCK 64 /** - * onenand_read_block - Read a block data to buf + * onenand_read_block - Read CONFIG_SYS_MONITOR_LEN from begining + * of OneNAND, skipping bad blocks * @return 0 on success */ -int onenand_read_block0(unsigned char *buf) +int onenand_read_block(unsigned char *buf) { - int page, offset = 0; - int pagesize = ONENAND_PAGE_SIZE; + int block; + int page = ONENAND_START_PAGE, offset = 0; + int pagesize = 0, erase_shift = 0; + int erasesize = 0, nblocks = 0; + + if (onenand_readw(ONENAND_REG_TECHNOLOGY)) { + pagesize = 4096; /* MLC OneNAND has 4KiB pagesize */ + erase_shift = 18; + } else { + pagesize = 2048; + erase_shift = 17; + } - /* MLC OneNAND has 4KiB page size */ - if (onenand_readw(THIS_ONENAND(ONENAND_REG_TECHNOLOGY))) - pagesize <<= 1; + erasesize = ONENAND_PAGES_PER_BLOCK * pagesize; + nblocks = (CONFIG_SYS_MONITOR_LEN + erasesize - 1) >> erase_shift; /* NOTE: you must read page from page 1 of block 0 */ /* read the block page by page*/ - for (page = ONENAND_START_PAGE; - page < ONENAND_PAGES_PER_BLOCK; page++) { - - onenand_read_page(0, page, buf + offset, pagesize); - offset += pagesize; + for (block = 0; block < nblocks; block++) { + for (; page < ONENAND_PAGES_PER_BLOCK; page++) { + if (onenand_read_page(block, page, buf + offset, + pagesize)) { + /* This block is bad. Skip it + * and read next block */ + offset -= page * pagesize; + nblocks++; + break; + } + offset += pagesize; + } + page = 0; } return 0; |