aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2009-04-03 22:48:05 +0200
committerWolfgang Denk <wd@denx.de>2009-04-03 22:48:05 +0200
commit8ddfe804c49f7b738eebfdc6a5d0e406581faf49 (patch)
tree9952f1a4ab23f6b92c5fed8caa7f1632e6f1d8bc
parentca41ef301b21b3ac25af71750624e0b3d5ddbb3e (diff)
parent99067b08f4a0ce20ff337a35211239f334d8f451 (diff)
Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
-rw-r--r--common/cmd_doc.c4
-rw-r--r--doc/README.nand109
-rw-r--r--drivers/mtd/nand_legacy/nand_legacy.c3
-rw-r--r--onenand_ipl/onenand_boot.c2
-rw-r--r--onenand_ipl/onenand_ipl.h8
-rw-r--r--onenand_ipl/onenand_read.c58
6 files changed, 64 insertions, 120 deletions
diff --git a/common/cmd_doc.c b/common/cmd_doc.c
index e2d4a42d1..3385c6736 100644
--- a/common/cmd_doc.c
+++ b/common/cmd_doc.c
@@ -14,6 +14,10 @@
#include <linux/mtd/nftl.h>
#include <linux/mtd/doc2000.h>
+#error This code is broken and will be removed outright in the next release.
+#error If you need diskonchip support, please update the Linux driver in
+#error drivers/mtd/nand/diskonchip.c to work with u-boot.
+
/*
* ! BROKEN !
*
diff --git a/doc/README.nand b/doc/README.nand
index fc62f92e0..bb722892d 100644
--- a/doc/README.nand
+++ b/doc/README.nand
@@ -98,83 +98,10 @@ Configuration Options:
CONFIG_SYS_MAX_NAND_DEVICE
The maximum number of NAND devices you want to support.
-NAND Interface:
-
- #define NAND_WAIT_READY(nand)
- Wait until the NAND flash is ready. Typically this would be a
- loop waiting for the READY/BUSY line from the flash to indicate it
- it is ready.
-
- #define WRITE_NAND_COMMAND(d, adr)
- Write the command byte `d' to the flash at `adr' with the
- CLE (command latch enable) line true. If your board uses writes to
- different addresses to control CLE and ALE, you can modify `adr'
- to be the appropriate address here. If your board uses I/O registers
- to control them, it is probably better to let NAND_CTL_SETCLE()
- and company do it.
-
- #define WRITE_NAND_ADDRESS(d, adr)
- Write the address byte `d' to the flash at `adr' with the
- ALE (address latch enable) line true. If your board uses writes to
- different addresses to control CLE and ALE, you can modify `adr'
- to be the appropriate address here. If your board uses I/O registers
- to control them, it is probably better to let NAND_CTL_SETALE()
- and company do it.
-
- #define WRITE_NAND(d, adr)
- Write the data byte `d' to the flash at `adr' with the
- ALE and CLE lines false. If your board uses writes to
- different addresses to control CLE and ALE, you can modify `adr'
- to be the appropriate address here. If your board uses I/O registers
- to control them, it is probably better to let NAND_CTL_CLRALE()
- and company do it.
-
- #define READ_NAND(adr)
- Read a data byte from the flash at `adr' with the
- ALE and CLE lines false. If your board uses reads from
- different addresses to control CLE and ALE, you can modify `adr'
- to be the appropriate address here. If your board uses I/O registers
- to control them, it is probably better to let NAND_CTL_CLRALE()
- and company do it.
-
- #define NAND_DISABLE_CE(nand)
- Set CE (Chip Enable) low to enable the NAND flash.
-
- #define NAND_ENABLE_CE(nand)
- Set CE (Chip Enable) high to disable the NAND flash.
-
- #define NAND_CTL_CLRALE(nandptr)
- Set ALE (address latch enable) low. If ALE control is handled by
- WRITE_NAND_ADDRESS() this can be empty.
-
- #define NAND_CTL_SETALE(nandptr)
- Set ALE (address latch enable) high. If ALE control is handled by
- WRITE_NAND_ADDRESS() this can be empty.
-
- #define NAND_CTL_CLRCLE(nandptr)
- Set CLE (command latch enable) low. If CLE control is handled by
- WRITE_NAND_ADDRESS() this can be empty.
-
- #define NAND_CTL_SETCLE(nandptr)
- Set CLE (command latch enable) high. If CLE control is handled by
- WRITE_NAND_ADDRESS() this can be empty.
-
-More Definitions:
-
- These definitions are needed in the board configuration for now, but
- may really belong in a header file.
- TODO: Figure which ones are truly configuration settings and rename
- them to CONFIG_SYS_NAND_... and move the rest somewhere appropriate.
-
- #define SECTORSIZE 512
- #define ADDR_COLUMN 1
- #define ADDR_PAGE 2
- #define ADDR_COLUMN_PAGE 3
- #define NAND_ChipID_UNKNOWN 0x00
- #define NAND_MAX_FLOORS 1
- #define CONFIG_SYS_NAND_MAX_CHIPS 1
-
- #define CONFIG_SYS_DAVINCI_BROKEN_ECC
+ CONFIG_SYS_NAND_MAX_CHIPS
+ The maximum number of NAND chips per device to be supported.
+
+ CONFIG_SYS_DAVINCI_BROKEN_ECC
Versions of U-Boot <= 1.3.3 and Montavista Linux kernels
generated bogus ECCs on large-page NAND. Both large and small page
NAND ECCs were incompatible with the Linux davinci git tree (since
@@ -186,27 +113,17 @@ More Definitions:
NOTE:
=====
-We now use a complete rewrite of the NAND code based on what is in
-2.6.12 Linux kernel.
-
-The old NAND handling code has been re-factored and is now confined
-to only board-specific files and - unfortunately - to the DoC code
-(see below). A new configuration variable has been introduced:
-CONFIG_NAND_LEGACY, which has to be defined in the board config file if
-that board uses legacy code.
-
-The necessary changes have been made to all affected boards, and no
-build breakage has been introduced, except for NETTA and NETTA_ISDN
-targets from MAKEALL. This is due to the fact that these two boards
-use JFFS, which has been adopted to use the new NAND, and at the same
-time use NAND in legacy mode. The breakage will disappear when the
-board-specific code is changed to the new NAND.
+The current NAND implementation is based on what is in recent
+Linux kernels. The old legacy implementation has been disabled,
+and will be removed soon.
-As mentioned above, the legacy code is still used by the DoC subsystem.
-The consequence of this is that the legacy NAND can't be removed from
-the tree until the DoC is ported to use the new NAND support (or boards
-with DoC will break).
+If you have board code which used CONFIG_NAND_LEGACY, you'll need
+to convert to the current NAND interface for it to continue to work.
+The Disk On Chip driver is currently broken and has been for some time.
+There is a driver in drivers/mtd/nand, taken from Linux, that works with
+the current NAND system but has not yet been adapted to the u-boot
+environment.
Additional improvements to the NAND subsystem by Guido Classen, 10-10-2006
diff --git a/drivers/mtd/nand_legacy/nand_legacy.c b/drivers/mtd/nand_legacy/nand_legacy.c
index 441780ac2..d9ae9c78b 100644
--- a/drivers/mtd/nand_legacy/nand_legacy.c
+++ b/drivers/mtd/nand_legacy/nand_legacy.c
@@ -18,6 +18,9 @@
#include <linux/mtd/nand_ids.h>
#include <jffs2/jffs2.h>
+#error Legacy NAND is deprecated. Please convert to the current NAND interface.
+#error This code will be removed outright in the next release.
+
#ifdef CONFIG_OMAP1510
void archflashwp(void *archdata, int wp);
#endif
diff --git a/onenand_ipl/onenand_boot.c b/onenand_ipl/onenand_boot.c
index 86428cc05..63995ce50 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 57e54f5cb..412572a08 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 6d04943ba..d1a842dd6 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;