ap920t ap922_XA10 ap926ejs ap946es \
ap966 cp920t cp922_XA10 cp926ejs \
cp946es cp966 lpd7a400 mp2usb \
- mx1ads mx1fs2 omap1510inn omap1610h2 \
- omap1610inn omap730p2 scb9328 smdk2400 \
- smdk2410 trab VCMA9 versatile \
- versatileab versatilepb voiceblue
+ mx1ads mx1fs2 netstar omap1510inn \
+ omap1610h2 omap1610inn omap730p2 scb9328 \
+ smdk2400 smdk2410 trab VCMA9 \
+ versatile versatileab versatilepb voiceblue
"
#########################################################################
}
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
/*----------------------------------------------------------------------------+
ifeq ($(dbcr),1)
PLATFORM_CPPFLAGS += -DCFG_INIT_DBCR=0x8cff0000
endif
+
+# legacy nand support
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
+
PLATFORM_CPPFLAGS += -DEMBEDDED -DBIG_ENDIAN_HOST -DINCLUDE_5701_AX_FIX=1\
-DDBG=0 -DT3_JUMBO_RCV_RCB_ENTRY_COUNT=256\
-DTEXT_BASE=$(TEXT_BASE)
+
# Reserve 320 kB for Monitor
TEXT_BASE = 0xFFFB0000
-# Compile the new NAND code (needed iff #ifdef CONFIG_NEW_NAND_CODE)
+# Compile the new NAND code (CFG_NAND_LEGACY mustn't be defined)
BOARDLIBS = drivers/nand/libnand.a
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+#BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
+
#include <common.h>
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#ifdef CONFIG_NEW_NAND_CODE
-/* new NAND handling */
#include <nand.h>
/*
* Board-specific NAND initialization. The following members of the
- * argument are board-specific (per include/linux/mtd/nand_new.h):
+ * argument are board-specific (per include/linux/mtd/nand.h):
* - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
* - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
* - hwcontrol: hardwarespecific function for accesing control-lines
nand->chip_delay = NAND_BIG_DELAY_US;
nand->options = NAND_SAMSUNG_LP_OPTIONS;
}
-
-#else
-
-/* old NAND handling */
-extern ulong
-nand_probe(ulong physadr);
-
-void
-nand_init(void)
-{
- ulong totlen = 0;
-
-/*
- The HI model is equipped with a large block NAND chip not supported yet
- by U-Boot
- (CONFIG_PPCHAMELEON_MODULE_MODEL == CONFIG_PPCHAMELEON_MODULE_HI)
-*/
-
-#if (CONFIG_PPCHAMELEON_MODULE_MODEL == CONFIG_PPCHAMELEON_MODULE_ME)
- debug ("Probing at 0x%.8x\n", CFG_NAND0_BASE);
- totlen += nand_probe (CFG_NAND0_BASE);
-#endif /* CONFIG_PPCHAMELEON_MODULE_ME, CONFIG_PPCHAMELEON_MODULE_HI */
-
- debug ("Probing at 0x%.8x\n", CFG_NAND1_BASE);
- totlen += nand_probe (CFG_NAND1_BASE);
-
- printf ("%3lu MB\n", totlen >>20);
-}
-#endif
-#endif
+#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
/* ------------------------------------------------------------------------- */
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
#
TEXT_BASE = 0xFFFC0000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
/* ------------------------------------------------------------------------- */
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
#
TEXT_BASE = 0xFFFC0000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
*/
#include <common.h>
+
+#ifndef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY not defined in a file using the legacy NAND support!
+#endif
+
#include <command.h>
#include <image.h>
#include <asm/byteorder.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
#include <fat.h>
#include "auto_update.h"
#error "must define CFG_CMD_FAT"
#endif
+
+
+
extern au_image_t au_image[];
extern int N_AU_IMAGES;
#define NANDRW_JFFS2 0x02
#define NANDRW_JFFS2_SKIP 0x04
extern struct nand_chip nand_dev_desc[];
-extern int nand_rw(struct nand_chip* nand, int cmd, size_t start, size_t len,
+extern int nand_legacy_rw(struct nand_chip* nand, int cmd, size_t start, size_t len,
size_t * retlen, u_char * buf);
-extern int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
+extern int nand_legacy_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
extern block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
} else {
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
printf("Updating NAND FLASH with image %s\n", au_image[i].name);
- debug ("nand_erase(%lx, %lx);\n", start, end);
- rc = nand_erase (nand_dev_desc, start, end - start + 1, 0);
- debug ("nand_erase returned %x\n", rc);
+ debug ("nand_legacy_erase(%lx, %lx);\n", start, end);
+ rc = nand_legacy_erase (nand_dev_desc, start, end - start + 1, 0);
+ debug ("nand_legacy_erase returned %x\n", rc);
#endif
}
rc = flash_write((char *)addr, start, nbytes);
} else {
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
- debug ("nand_rw(%p, %lx %x)\n", addr, start, nbytes);
- rc = nand_rw(nand_dev_desc, NANDRW_WRITE | NANDRW_JFFS2,
+ debug ("nand_legacy_rw(%p, %lx %x)\n", addr, start, nbytes);
+ rc = nand_legacy_rw(nand_dev_desc, NANDRW_WRITE | NANDRW_JFFS2,
start, nbytes, (size_t *)&total, (uchar *)addr);
- debug ("nand_rw: ret=%x total=%d nbytes=%d\n", rc, total, nbytes);
+ debug ("nand_legacy_rw: ret=%x total=%d nbytes=%d\n", rc, total, nbytes);
#endif
}
if (rc != 0) {
rc = crc32 (0, (uchar *)(start + off), ntohl(hdr->ih_size));
} else {
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
- rc = nand_rw(nand_dev_desc, NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP,
+ rc = nand_legacy_rw(nand_dev_desc, NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP,
start, nbytes, (size_t *)&total, (uchar *)addr);
rc = crc32 (0, (uchar *)(addr + off), ntohl(hdr->ih_size));
#endif
endif
endif
endif
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
+
TEXT_BASE = 0xFFF80000
#TEXT_BASE = 0xFFFC0000
#TEXT_BASE = 0x00FC0000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
#
TEXT_BASE = 0xFFFC0000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
TEXT_BASE = 0xFFFC0000
#TEXT_BASE = 0x00FC0000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
#
TEXT_BASE = 0xFFF80000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
#
TEXT_BASE = 0xFFFC0000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
/* ------------------------------------------------------------------------- */
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
void nand_init(void)
#
TEXT_BASE = 0x40000000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern ulong nand_probe(ulong physadr);
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
# XXX TEXT_BASE = 0x20012000
TEXT_BASE = 0x13FC0000
-# Compile the new NAND code (needed iff #ifdef CONFIG_NEW_NAND_CODE)
+# Compile the new NAND code
BOARDLIBS = drivers/nand/libnand.a
.byte 0x0c @ COMP_MODE_CTRL_0
.byte 0xff
-.globl platformsetup
-platformsetup:
+.globl lowlevel_init
+lowlevel_init:
/* Improve performance a bit... */
mrc p15, 0, r1, c0, c0, 0 @ read C15 ID register
mrc p15, 0, r1, c0, c0, 1 @ read C15 Cache information register
#
TEXT_BASE = 0x40000000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern ulong nand_probe(ulong physadr);
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
#
TEXT_BASE = 0x40000000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern ulong nand_probe(ulong physadr);
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
#include <i2c.h>
#include <asm/mach-types.h>
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
#endif
#
TEXT_BASE = 0xF8000000
+
+# Compile the legacy NAND code (CFG_NAND_LEGACY must be defined)
+BOARDLIBS = drivers/nand_legacy/libnand_legacy.a
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
extern ulong nand_probe(ulong physadr);
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
cmd_i2c.o cmd_ide.o cmd_immap.o cmd_itest.o cmd_jffs2.o \
cmd_load.o cmd_log.o \
cmd_mem.o cmd_mii.o cmd_misc.o cmd_mmc.o \
- cmd_nand.o cmd_nand_new.o cmd_net.o cmd_nvedit.o \
+ cmd_nand.o cmd_net.o cmd_nvedit.o \
cmd_pci.o cmd_pcmcia.o cmd_portio.o \
cmd_reginfo.o cmd_reiser.o cmd_scsi.o cmd_spi.o cmd_universe.o \
cmd_usb.o cmd_vfd.o \
#if (CONFIG_COMMANDS & CFG_CMD_DOC)
#include <linux/mtd/nftl.h>
-#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_legacy.h>
#include <linux/mtd/nand_ids.h>
+
#include <linux/mtd/doc2000.h>
#include <linux/mtd/nftl.h>
#include <command.h>
#include <malloc.h>
#include <jffs2/jffs2.h>
-#include <linux/mtd/nand.h>
#include <linux/list.h>
#include <linux/ctype.h>
#include <cramfs/cramfs_fs.h>
-#ifdef CONFIG_NEW_NAND_CODE
+#if (CONFIG_COMMANDS & CFG_CMD_NAND)
+#ifdef CFG_NAND_LEGACY
+#include <linux/mtd/nand_legacy.h>
+#else /* !CFG_NAND_LEGACY */
+#include <linux/mtd/nand.h>
#include <nand.h>
-#endif
-
+#endif /* !CFG_NAND_LEGACY */
+#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
/* enable/disable debugging messages */
#define DEBUG_JFFS
#undef DEBUG_JFFS
}
}
-#ifndef CONFIG_NEW_NAND_CODE
+#ifdef CFG_NAND_LEGACY
jffs2_free_cache(part);
#endif
list_del(&part->link);
list_for_each_safe(entry, n, head) {
part_tmp = list_entry(entry, struct part_info, link);
-#ifndef CONFIG_NEW_NAND_CODE
+#ifdef CFG_NAND_LEGACY
jffs2_free_cache(part_tmp);
#endif
list_del(entry);
} else if (type == MTD_DEV_TYPE_NAND) {
#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND)
if (num < CFG_MAX_NAND_DEVICE) {
-#ifdef CONFIG_NEW_NAND_CODE
+#ifndef CFG_NAND_LEGACY
*size = nand_info[num].size;
#else
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
*/
#include <common.h>
+
+
+#ifndef CFG_NAND_LEGACY
+/*
+ *
+ * New NAND support
+ *
+ */
+#include <common.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_NAND)
+
+#include <command.h>
+#include <watchdog.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+#include <jffs2/jffs2.h>
+#include <nand.h>
+
+extern nand_info_t nand_info[]; /* info for NAND chips */
+
+static int nand_dump_oob(nand_info_t *nand, ulong off)
+{
+ return 0;
+}
+
+static int nand_dump(nand_info_t *nand, ulong off)
+{
+ int i;
+ u_char *buf, *p;
+
+ buf = malloc(nand->oobblock + nand->oobsize);
+ if (!buf) {
+ puts("No memory for page buffer\n");
+ return 1;
+ }
+ off &= ~(nand->oobblock - 1);
+ i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize);
+ if (i < 0) {
+ printf("Error (%d) reading page %08x\n", i, off);
+ free(buf);
+ return 1;
+ }
+ printf("Page %08x dump:\n", off);
+ i = nand->oobblock >> 4; p = buf;
+ while (i--) {
+ printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x"
+ " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+ p += 16;
+ }
+ puts("OOB:\n");
+ i = nand->oobsize >> 3;
+ while (i--) {
+ printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ }
+ free(buf);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize)
+{
+ *off = 0;
+ *size = 0;
+
+#if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART)
+ if (argc >= 1 && strcmp(argv[0], "partition") == 0) {
+ int part_num;
+ struct part_info *part;
+ const char *partstr;
+
+ if (argc >= 2)
+ partstr = argv[1];
+ else
+ partstr = getenv("partition");
+
+ if (partstr)
+ part_num = (int)simple_strtoul(partstr, NULL, 10);
+ else
+ part_num = 0;
+
+ part = jffs2_part_info(part_num);
+ if (part == NULL) {
+ printf("\nInvalid partition %d\n", part_num);
+ return;
+ }
+ *size = part->size;
+ *off = (ulong)part->offset;
+ } else
+#endif
+ {
+ if (argc >= 1)
+ *off = (ulong)simple_strtoul(argv[0], NULL, 16);
+ else
+ *off = 0;
+
+ if (argc >= 2)
+ *size = (ulong)simple_strtoul(argv[1], NULL, 16);
+ else
+ *size = totsize - *off;
+
+ }
+
+}
+
+int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int i, dev, ret;
+ ulong addr, off, size;
+ char *cmd, *s;
+ nand_info_t *nand;
+
+ /* at least two arguments please */
+ if (argc < 2)
+ goto usage;
+
+ cmd = argv[1];
+
+ if (strcmp(cmd, "info") == 0) {
+
+ putc('\n');
+ for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
+ if (nand_info[i].name)
+ printf("Device %d: %s, sector size %lu KiB\n",
+ i, nand_info[i].name,
+ nand_info[i].erasesize >> 10);
+ }
+ return 0;
+ }
+
+ if (strcmp(cmd, "device") == 0) {
+
+ if (argc < 3) {
+ if ((nand_curr_device < 0) ||
+ (nand_curr_device >= CFG_MAX_NAND_DEVICE))
+ puts("\nno devices available\n");
+ else
+ printf("\nDevice %d: %s\n", nand_curr_device,
+ nand_info[nand_curr_device].name);
+ return 0;
+ }
+ dev = (int)simple_strtoul(argv[2], NULL, 10);
+ if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
+ puts("No such device\n");
+ return 1;
+ }
+ printf("Device %d: %s", dev, nand_info[dev].name);
+ puts("... is now current device\n");
+ nand_curr_device = dev;
+ return 0;
+ }
+
+ if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
+ strncmp(cmd, "dump", 4) != 0 &&
+ strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0)
+ goto usage;
+
+ /* the following commands operate on the current device */
+ if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE ||
+ !nand_info[nand_curr_device].name) {
+ puts("\nno devices available\n");
+ return 1;
+ }
+ nand = &nand_info[nand_curr_device];
+
+ if (strcmp(cmd, "bad") == 0) {
+ printf("\nDevice %d bad blocks:\n", nand_curr_device);
+ for (off = 0; off < nand->size; off += nand->erasesize)
+ if (nand_block_isbad(nand, off))
+ printf(" %08x\n", off);
+ return 0;
+ }
+
+ if (strcmp(cmd, "erase") == 0) {
+ arg_off_size(argc - 2, argv + 2, &off, &size, nand->size);
+ if (off == 0 && size == 0)
+ return 1;
+
+ printf("\nNAND erase: device %d offset 0x%x, size 0x%x ",
+ nand_curr_device, off, size);
+ ret = nand_erase(nand, off, size);
+ printf("%s\n", ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+ }
+
+ if (strncmp(cmd, "dump", 4) == 0) {
+ if (argc < 3)
+ goto usage;
+
+ s = strchr(cmd, '.');
+ off = (int)simple_strtoul(argv[2], NULL, 16);
+
+ if (s != NULL && strcmp(s, ".oob") == 0)
+ ret = nand_dump_oob(nand, off);
+ else
+ ret = nand_dump(nand, off);
+
+ return ret == 0 ? 1 : 0;
+
+ }
+
+ /* read write */
+ if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
+ if (argc < 4)
+ goto usage;
+/*
+ s = strchr(cmd, '.');
+ clean = CLEAN_NONE;
+ if (s != NULL) {
+ if (strcmp(s, ".jffs2") == 0 || strcmp(s, ".e") == 0
+ || strcmp(s, ".i"))
+ clean = CLEAN_JFFS2;
+ }
+*/
+ addr = (ulong)simple_strtoul(argv[2], NULL, 16);
+
+ arg_off_size(argc - 3, argv + 3, &off, &size, nand->size);
+ if (off == 0 && size == 0)
+ return 1;
+
+ i = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
+ printf("\nNAND %s: device %d offset %u, size %u ... ",
+ i ? "read" : "write", nand_curr_device, off, size);
+
+ if (i)
+ ret = nand_read(nand, off, &size, (u_char *)addr);
+ else
+ ret = nand_write(nand, off, &size, (u_char *)addr);
+
+ printf(" %d bytes %s: %s\n", size,
+ i ? "read" : "written", ret ? "ERROR" : "OK");
+
+ return ret == 0 ? 0 : 1;
+ }
+usage:
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+}
+
+U_BOOT_CMD(nand, 5, 1, do_nand,
+ "nand - NAND sub-system\n",
+ "info - show available NAND devices\n"
+ "nand device [dev] - show or set current device\n"
+ "nand read[.jffs2] - addr off size\n"
+ "nand write[.jffs2] - addr off size - read/write `size' bytes starting\n"
+ " at offset `off' to/from memory address `addr'\n"
+ "nand erase [clean] [off size] - erase `size' bytes from\n"
+ " offset `off' (entire device if not specified)\n"
+ "nand bad - show bad blocks\n"
+ "nand dump[.oob] off - dump page\n"
+ "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
+ "nand markbad off - mark bad block at offset (UNSAFE)\n"
+ "nand biterr off - make a bit error at offset (UNSAFE)\n");
+
+int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ char *boot_device = NULL;
+ char *ep;
+ int dev;
+ int r;
+ ulong addr, cnt, offset = 0;
+ image_header_t *hdr;
+ nand_info_t *nand;
+
+ switch (argc) {
+ case 1:
+ addr = CFG_LOAD_ADDR;
+ boot_device = getenv("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ case 4:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ offset = simple_strtoul(argv[3], NULL, 16);
+ break;
+ default:
+ printf("Usage:\n%s\n", cmdtp->usage);
+ SHOW_BOOT_PROGRESS(-1);
+ return 1;
+ }
+
+ if (!boot_device) {
+ puts("\n** No boot device **\n");
+ SHOW_BOOT_PROGRESS(-1);
+ return 1;
+ }
+
+ dev = simple_strtoul(boot_device, &ep, 16);
+
+ if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
+ printf("\n** Device %d not available\n", dev);
+ SHOW_BOOT_PROGRESS(-1);
+ return 1;
+ }
+
+ nand = &nand_info[dev];
+ printf("\nLoading from device %d: %s (offset 0x%lx)\n",
+ dev, nand->name, offset);
+
+ cnt = nand->oobblock;
+ r = nand_read(nand, offset, &cnt, (u_char *) addr);
+ if (r) {
+ printf("** Read error on %d\n", dev);
+ SHOW_BOOT_PROGRESS(-1);
+ return 1;
+ }
+
+ hdr = (image_header_t *) addr;
+
+ if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+ printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
+ SHOW_BOOT_PROGRESS(-1);
+ return 1;
+ }
+
+ print_image_hdr(hdr);
+
+ cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t));
+
+ r = nand_read(nand, offset, &cnt, (u_char *) addr);
+ if (r) {
+ printf("** Read error on %d\n", dev);
+ SHOW_BOOT_PROGRESS(-1);
+ return 1;
+ }
+
+ /* Loading ok, update default load address */
+
+ load_addr = addr;
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
+ char *local_args[2];
+ extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
+
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+
+ printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
+
+ do_bootm(cmdtp, 0, 1, local_args);
+ return 1;
+ }
+ return 0;
+}
+
+U_BOOT_CMD(nboot, 4, 1, do_nandboot,
+ "nboot - boot from NAND device\n", "loadAddr dev\n");
+
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
+
+#else /* CFG_NAND_LEGACY */
+/*
+ *
+ * Legacy NAND support - to be phased out
+ *
+ */
#include <command.h>
#include <malloc.h>
#include <asm/io.h>
# define SHOW_BOOT_PROGRESS(arg)
#endif
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE)
-
-#include <linux/mtd/nand.h>
+#if (CONFIG_COMMANDS & CFG_CMD_NAND)
+#include <linux/mtd/nand_legacy.h>
+#if 0
#include <linux/mtd/nand_ids.h>
#include <jffs2/jffs2.h>
+#endif
#ifdef CONFIG_OMAP1510
void archflashwp(void *archdata, int wp);
#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
-/*
- * Definition of the out of band configuration structure
- */
-struct nand_oob_config {
- int ecc_pos[6]; /* position of ECC bytes inside oob */
- int badblock_pos; /* position of bad block flag inside oob -1 = inactive */
- int eccvalid_pos; /* position of ECC valid flag inside oob -1 = inactive */
-} oob_config = { {0}, 0, 0};
-
#undef NAND_DEBUG
#undef PSYCHO_DEBUG
#define CONFIG_MTD_NAND_ECC /* enable ECC */
#define CONFIG_MTD_NAND_ECC_JFFS2
-/* bits for nand_rw() `cmd'; or together as needed */
+/* bits for nand_legacy_rw() `cmd'; or together as needed */
#define NANDRW_READ 0x01
#define NANDRW_WRITE 0x00
#define NANDRW_JFFS2 0x02
#define NANDRW_JFFS2_SKIP 0x04
-/*
- * Function Prototypes
- */
-static void nand_print(struct nand_chip *nand);
-int nand_rw (struct nand_chip* nand, int cmd,
- size_t start, size_t len,
- size_t * retlen, u_char * buf);
-int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
-static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
- size_t * retlen, u_char *buf, u_char *ecc_code);
-static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
- size_t * retlen, const u_char * buf, u_char * ecc_code);
-static void nand_print_bad(struct nand_chip *nand);
-static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
- size_t * retlen, u_char * buf);
-static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
- size_t * retlen, const u_char * buf);
-static int NanD_WaitReady(struct nand_chip *nand, int ale_wait);
-#ifdef CONFIG_MTD_NAND_ECC
-static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
-#endif
-struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE] = {{0}};
-/* Current NAND Device */
-static int curr_device = -1;
+/*
+ * Imports from nand_legacy.c
+ */
+extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
+extern int curr_device;
+extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs,
+ size_t len, int clean);
+extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start,
+ size_t len, size_t *retlen, u_char *buf);
+extern void nand_print(struct nand_chip *nand);
+extern void nand_print_bad(struct nand_chip *nand);
+extern int nand_read_oob(struct nand_chip *nand, size_t ofs,
+ size_t len, size_t *retlen, u_char *buf);
+extern int nand_write_oob(struct nand_chip *nand, size_t ofs,
+ size_t len, size_t *retlen, const u_char *buf);
-/* ------------------------------------------------------------------------- */
int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
curr_device, off, size);
- ret = nand_erase (nand, off, size, 1);
+ ret = nand_legacy_erase (nand, off, size, 1);
printf("%s\n", ret ? "ERROR" : "OK");
(cmd & NANDRW_READ) ? "read" : "write",
curr_device, off, size);
- ret = nand_rw(nand_dev_desc + curr_device, cmd, off, size,
+ ret = nand_legacy_rw(nand_dev_desc + curr_device, cmd, off, size,
(size_t *)&total, (u_char*)addr);
printf (" %d bytes %s: %s\n", total,
printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
curr_device, off, size);
- ret = nand_erase (nand_dev_desc + curr_device, off, size, clean);
+ ret = nand_legacy_erase (nand_dev_desc + curr_device,
+ off, size, clean);
printf("%s\n", ret ? "ERROR" : "OK");
dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
offset);
- if (nand_rw (nand_dev_desc + dev, NANDRW_READ, offset,
- SECTORSIZE, NULL, (u_char *)addr)) {
+ if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset,
+ SECTORSIZE, NULL, (u_char *)addr)) {
printf ("** Read error on %d\n", dev);
SHOW_BOOT_PROGRESS (-1);
return 1;
return 1;
}
- if (nand_rw (nand_dev_desc + dev, NANDRW_READ, offset + SECTORSIZE, cnt,
- NULL, (u_char *)(addr+SECTORSIZE))) {
+ if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ,
+ offset + SECTORSIZE, cnt, NULL,
+ (u_char *)(addr+SECTORSIZE))) {
printf ("** Read error on %d\n", dev);
SHOW_BOOT_PROGRESS (-1);
return 1;
"loadAddr dev\n"
);
-/* returns 0 if block containing pos is OK:
- * valid erase block and
- * not marked bad, or no bad mark position is specified
- * returns 1 if marked bad or otherwise invalid
- */
-int check_block (struct nand_chip *nand, unsigned long pos)
-{
- size_t retlen;
- uint8_t oob_data;
- uint16_t oob_data16[6];
- int page0 = pos & (-nand->erasesize);
- int page1 = page0 + nand->oobblock;
- int badpos = oob_config.badblock_pos;
-
- if (pos >= nand->totlen)
- return 1;
-
- if (badpos < 0)
- return 0; /* no way to check, assume OK */
-
- if (nand->bus16) {
- if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16)
- || (oob_data16[2] & 0xff00) != 0xff00)
- return 1;
- if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16)
- || (oob_data16[2] & 0xff00) != 0xff00)
- return 1;
- } else {
- /* Note - bad block marker can be on first or second page */
- if (nand_read_oob(nand, page0 + badpos, 1, &retlen, (unsigned char *)&oob_data)
- || oob_data != 0xff
- || nand_read_oob (nand, page1 + badpos, 1, &retlen, (unsigned char *)&oob_data)
- || oob_data != 0xff)
- return 1;
- }
-
- return 0;
-}
-
-/* print bad blocks in NAND flash */
-static void nand_print_bad(struct nand_chip* nand)
-{
- unsigned long pos;
-
- for (pos = 0; pos < nand->totlen; pos += nand->erasesize) {
- if (check_block(nand, pos))
- printf(" 0x%8.8lx\n", pos);
- }
- puts("\n");
-}
-
-/* cmd: 0: NANDRW_WRITE write, fail on bad block
- * 1: NANDRW_READ read, fail on bad block
- * 2: NANDRW_WRITE | NANDRW_JFFS2 write, skip bad blocks
- * 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks
- * 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks
- */
-int nand_rw (struct nand_chip* nand, int cmd,
- size_t start, size_t len,
- size_t * retlen, u_char * buf)
-{
- int ret = 0, n, total = 0;
- char eccbuf[6];
- /* eblk (once set) is the start of the erase block containing the
- * data being processed.
- */
- unsigned long eblk = ~0; /* force mismatch on first pass */
- unsigned long erasesize = nand->erasesize;
-
- while (len) {
- if ((start & (-erasesize)) != eblk) {
- /* have crossed into new erase block, deal with
- * it if it is sure marked bad.
- */
- eblk = start & (-erasesize); /* start of block */
- if (check_block(nand, eblk)) {
- if (cmd == (NANDRW_READ | NANDRW_JFFS2)) {
- while (len > 0 &&
- start - eblk < erasesize) {
- *(buf++) = 0xff;
- ++start;
- ++total;
- --len;
- }
- continue;
- } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
- start += erasesize;
- continue;
- } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
- /* skip bad block */
- start += erasesize;
- continue;
- } else {
- ret = 1;
- break;
- }
- }
- }
- /* The ECC will not be calculated correctly if
- less than 512 is written or read */
- /* Is request at least 512 bytes AND it starts on a proper boundry */
- if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200))
- printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n");
-
- if (cmd & NANDRW_READ) {
- ret = nand_read_ecc(nand, start,
- min(len, eblk + erasesize - start),
- (size_t *)&n, (u_char*)buf, (u_char *)eccbuf);
- } else {
- ret = nand_write_ecc(nand, start,
- min(len, eblk + erasesize - start),
- (size_t *)&n, (u_char*)buf, (u_char *)eccbuf);
- }
-
- if (ret)
- break;
-
- start += n;
- buf += n;
- total += n;
- len -= n;
- }
- if (retlen)
- *retlen = total;
-
- return ret;
-}
-
-static void nand_print(struct nand_chip *nand)
-{
- if (nand->numchips > 1) {
- printf("%s at 0x%lx,\n"
- "\t %d chips %s, size %d MB, \n"
- "\t total size %ld MB, sector size %ld kB\n",
- nand->name, nand->IO_ADDR, nand->numchips,
- nand->chips_name, 1 << (nand->chipshift - 20),
- nand->totlen >> 20, nand->erasesize >> 10);
- }
- else {
- printf("%s at 0x%lx (", nand->chips_name, nand->IO_ADDR);
- print_size(nand->totlen, ", ");
- print_size(nand->erasesize, " sector)\n");
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int NanD_WaitReady(struct nand_chip *nand, int ale_wait)
-{
- /* This is inline, to optimise the common case, where it's ready instantly */
- int ret = 0;
-
-#ifdef NAND_NO_RB /* in config file, shorter delays currently wrap accesses */
- if(ale_wait)
- NAND_WAIT_READY(nand); /* do the worst case 25us wait */
- else
- udelay(10);
-#else /* has functional r/b signal */
- NAND_WAIT_READY(nand);
-#endif
- return ret;
-}
-
-/* NanD_Command: Send a flash command to the flash chip */
-
-static inline int NanD_Command(struct nand_chip *nand, unsigned char command)
-{
- unsigned long nandptr = nand->IO_ADDR;
-
- /* Assert the CLE (Command Latch Enable) line to the flash chip */
- NAND_CTL_SETCLE(nandptr);
-
- /* Send the command */
- WRITE_NAND_COMMAND(command, nandptr);
-
- /* Lower the CLE line */
- NAND_CTL_CLRCLE(nandptr);
-
-#ifdef NAND_NO_RB
- if(command == NAND_CMD_RESET){
- u_char ret_val;
- NanD_Command(nand, NAND_CMD_STATUS);
- do {
- ret_val = READ_NAND(nandptr);/* wait till ready */
- } while((ret_val & 0x40) != 0x40);
- }
-#endif
- return NanD_WaitReady(nand, 0);
-}
-
-/* NanD_Address: Set the current address for the flash chip */
-
-static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs)
-{
- unsigned long nandptr;
- int i;
-
- nandptr = nand->IO_ADDR;
-
- /* Assert the ALE (Address Latch Enable) line to the flash chip */
- NAND_CTL_SETALE(nandptr);
-
- /* Send the address */
- /* Devices with 256-byte page are addressed as:
- * Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
- * there is no device on the market with page256
- * and more than 24 bits.
- * Devices with 512-byte page are addressed as:
- * Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
- * 25-31 is sent only if the chip support it.
- * bit 8 changes the read command to be sent
- * (NAND_CMD_READ0 or NAND_CMD_READ1).
- */
-
- if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE)
- WRITE_NAND_ADDRESS(ofs, nandptr);
-
- ofs = ofs >> nand->page_shift;
+#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
- if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
- for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) {
- WRITE_NAND_ADDRESS(ofs, nandptr);
- }
- }
-
- /* Lower the ALE line */
- NAND_CTL_CLRALE(nandptr);
-
- /* Wait for the chip to respond */
- return NanD_WaitReady(nand, 1);
-}
-
-/* NanD_SelectChip: Select a given flash chip within the current floor */
-
-static inline int NanD_SelectChip(struct nand_chip *nand, int chip)
-{
- /* Wait for it to be ready */
- return NanD_WaitReady(nand, 0);
-}
-
-/* NanD_IdentChip: Identify a given NAND chip given {floor,chip} */
-
-static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip)
-{
- int mfr, id, i;
-
- NAND_ENABLE_CE(nand); /* set pin low */
- /* Reset the chip */
- if (NanD_Command(nand, NAND_CMD_RESET)) {
-#ifdef NAND_DEBUG
- printf("NanD_Command (reset) for %d,%d returned true\n",
- floor, chip);
-#endif
- NAND_DISABLE_CE(nand); /* set pin high */
- return 0;
- }
-
- /* Read the NAND chip ID: 1. Send ReadID command */
- if (NanD_Command(nand, NAND_CMD_READID)) {
-#ifdef NAND_DEBUG
- printf("NanD_Command (ReadID) for %d,%d returned true\n",
- floor, chip);
-#endif
- NAND_DISABLE_CE(nand); /* set pin high */
- return 0;
- }
-
- /* Read the NAND chip ID: 2. Send address byte zero */
- NanD_Address(nand, ADDR_COLUMN, 0);
-
- /* Read the manufacturer and device id codes from the device */
-
- mfr = READ_NAND(nand->IO_ADDR);
-
- id = READ_NAND(nand->IO_ADDR);
-
- NAND_DISABLE_CE(nand); /* set pin high */
-
-#ifdef NAND_DEBUG
- printf("NanD_Command (ReadID) got %x %x\n", mfr, id);
-#endif
- if (mfr == 0xff || mfr == 0) {
- /* No response - return failure */
- return 0;
- }
-
- /* Check it's the same as the first chip we identified.
- * M-Systems say that any given nand_chip device should only
- * contain _one_ type of flash part, although that's not a
- * hardware restriction. */
- if (nand->mfr) {
- if (nand->mfr == mfr && nand->id == id) {
- return 1; /* This is another the same the first */
- } else {
- printf("Flash chip at floor %d, chip %d is different:\n",
- floor, chip);
- }
- }
-
- /* Print and store the manufacturer and ID codes. */
- for (i = 0; nand_flash_ids[i].name != NULL; i++) {
- if (mfr == nand_flash_ids[i].manufacture_id &&
- id == nand_flash_ids[i].model_id) {
-#ifdef NAND_DEBUG
- printf("Flash chip found:\n\t Manufacturer ID: 0x%2.2X, "
- "Chip ID: 0x%2.2X (%s)\n", mfr, id,
- nand_flash_ids[i].name);
-#endif
- if (!nand->mfr) {
- nand->mfr = mfr;
- nand->id = id;
- nand->chipshift =
- nand_flash_ids[i].chipshift;
- nand->page256 = nand_flash_ids[i].page256;
- nand->eccsize = 256;
- if (nand->page256) {
- nand->oobblock = 256;
- nand->oobsize = 8;
- nand->page_shift = 8;
- } else {
- nand->oobblock = 512;
- nand->oobsize = 16;
- nand->page_shift = 9;
- }
- nand->pageadrlen = nand_flash_ids[i].pageadrlen;
- nand->erasesize = nand_flash_ids[i].erasesize;
- nand->chips_name = nand_flash_ids[i].name;
- nand->bus16 = nand_flash_ids[i].bus16;
- return 1;
- }
- return 0;
- }
- }
-
-
-#ifdef NAND_DEBUG
- /* We haven't fully identified the chip. Print as much as we know. */
- printf("Unknown flash chip found: %2.2X %2.2X\n",
- id, mfr);
-#endif
-
- return 0;
-}
-
-/* NanD_ScanChips: Find all NAND chips present in a nand_chip, and identify them */
-
-static void NanD_ScanChips(struct nand_chip *nand)
-{
- int floor, chip;
- int numchips[NAND_MAX_FLOORS];
- int maxchips = NAND_MAX_CHIPS;
- int ret = 1;
-
- nand->numchips = 0;
- nand->mfr = 0;
- nand->id = 0;
-
-
- /* For each floor, find the number of valid chips it contains */
- for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {
- ret = 1;
- numchips[floor] = 0;
- for (chip = 0; chip < maxchips && ret != 0; chip++) {
-
- ret = NanD_IdentChip(nand, floor, chip);
- if (ret) {
- numchips[floor]++;
- nand->numchips++;
- }
- }
- }
-
- /* If there are none at all that we recognise, bail */
- if (!nand->numchips) {
-#ifdef NAND_DEBUG
- puts ("No NAND flash chips recognised.\n");
-#endif
- return;
- }
-
- /* Allocate an array to hold the information for each chip */
- nand->chips = malloc(sizeof(struct Nand) * nand->numchips);
- if (!nand->chips) {
- puts ("No memory for allocating chip info structures\n");
- return;
- }
-
- ret = 0;
-
- /* Fill out the chip array with {floor, chipno} for each
- * detected chip in the device. */
- for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {
- for (chip = 0; chip < numchips[floor]; chip++) {
- nand->chips[ret].floor = floor;
- nand->chips[ret].chip = chip;
- nand->chips[ret].curadr = 0;
- nand->chips[ret].curmode = 0x50;
- ret++;
- }
- }
-
- /* Calculate and print the total size of the device */
- nand->totlen = nand->numchips * (1 << nand->chipshift);
-
-#ifdef NAND_DEBUG
- printf("%d flash chips found. Total nand_chip size: %ld MB\n",
- nand->numchips, nand->totlen >> 20);
-#endif
-}
-
-/* we need to be fast here, 1 us per read translates to 1 second per meg */
-static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr)
-{
- unsigned long nandptr = nand->IO_ADDR;
-
- NanD_Command (nand, NAND_CMD_READ0);
-
- if (nand->bus16) {
- u16 val;
-
- while (cntr >= 16) {
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- cntr -= 16;
- }
-
- while (cntr > 0) {
- val = READ_NAND (nandptr);
- *data_buf++ = val & 0xff;
- *data_buf++ = val >> 8;
- cntr -= 2;
- }
- } else {
- while (cntr >= 16) {
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- *data_buf++ = READ_NAND (nandptr);
- cntr -= 16;
- }
-
- while (cntr > 0) {
- *data_buf++ = READ_NAND (nandptr);
- cntr--;
- }
- }
-}
-
-/*
- * NAND read with ECC
- */
-static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
- size_t * retlen, u_char *buf, u_char *ecc_code)
-{
- int col, page;
- int ecc_status = 0;
-#ifdef CONFIG_MTD_NAND_ECC
- int j;
- int ecc_failed = 0;
- u_char *data_poi;
- u_char ecc_calc[6];
-#endif
-
- /* Do not allow reads past end of device */
- if ((start + len) > nand->totlen) {
- printf ("%s: Attempt read beyond end of device %x %x %x\n",
- __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen);
- *retlen = 0;
- return -1;
- }
-
- /* First we calculate the starting page */
- /*page = shr(start, nand->page_shift);*/
- page = start >> nand->page_shift;
-
- /* Get raw starting column */
- col = start & (nand->oobblock - 1);
-
- /* Initialize return value */
- *retlen = 0;
-
- /* Select the NAND device */
- NAND_ENABLE_CE(nand); /* set pin low */
-
- /* Loop until all data read */
- while (*retlen < len) {
-
-#ifdef CONFIG_MTD_NAND_ECC
- /* Do we have this page in cache ? */
- if (nand->cache_page == page)
- goto readdata;
- /* Send the read command */
- NanD_Command(nand, NAND_CMD_READ0);
- if (nand->bus16) {
- NanD_Address(nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + (col >> 1));
- } else {
- NanD_Address(nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + col);
- }
-
- /* Read in a page + oob data */
- NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize);
-
- /* copy data into cache, for read out of cache and if ecc fails */
- if (nand->data_cache) {
- memcpy (nand->data_cache, nand->data_buf,
- nand->oobblock + nand->oobsize);
- }
-
- /* Pick the ECC bytes out of the oob data */
- for (j = 0; j < 6; j++) {
- ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])];
- }
-
- /* Calculate the ECC and verify it */
- /* If block was not written with ECC, skip ECC */
- if (oob_config.eccvalid_pos != -1 &&
- (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) {
-
- nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]);
- switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) {
- case -1:
- printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);
- ecc_failed++;
- break;
- case 1:
- case 2: /* transfer ECC corrected data to cache */
- if (nand->data_cache)
- memcpy (nand->data_cache, nand->data_buf, 256);
- break;
- }
- }
-
- if (oob_config.eccvalid_pos != -1 &&
- nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) {
-
- nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]);
- switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) {
- case -1:
- printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);
- ecc_failed++;
- break;
- case 1:
- case 2: /* transfer ECC corrected data to cache */
- if (nand->data_cache)
- memcpy (&nand->data_cache[256], &nand->data_buf[256], 256);
- break;
- }
- }
-readdata:
- /* Read the data from ECC data buffer into return buffer */
- data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf;
- data_poi += col;
- if ((*retlen + (nand->oobblock - col)) >= len) {
- memcpy (buf + *retlen, data_poi, len - *retlen);
- *retlen = len;
- } else {
- memcpy (buf + *retlen, data_poi, nand->oobblock - col);
- *retlen += nand->oobblock - col;
- }
- /* Set cache page address, invalidate, if ecc_failed */
- nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1;
-
- ecc_status += ecc_failed;
- ecc_failed = 0;
-
-#else
- /* Send the read command */
- NanD_Command(nand, NAND_CMD_READ0);
- if (nand->bus16) {
- NanD_Address(nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + (col >> 1));
- } else {
- NanD_Address(nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + col);
- }
-
- /* Read the data directly into the return buffer */
- if ((*retlen + (nand->oobblock - col)) >= len) {
- NanD_ReadBuf(nand, buf + *retlen, len - *retlen);
- *retlen = len;
- /* We're done */
- continue;
- } else {
- NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col);
- *retlen += nand->oobblock - col;
- }
-#endif
- /* For subsequent reads align to page boundary. */
- col = 0;
- /* Increment page address */
- page++;
- }
-
- /* De-select the NAND device */
- NAND_DISABLE_CE(nand); /* set pin high */
-
- /*
- * Return success, if no ECC failures, else -EIO
- * fs driver will take care of that, because
- * retlen == desired len and result == -EIO
- */
- return ecc_status ? -1 : 0;
-}
-
-/*
- * Nand_page_program function is used for write and writev !
- */
-static int nand_write_page (struct nand_chip *nand,
- int page, int col, int last, u_char * ecc_code)
-{
-
- int i;
- unsigned long nandptr = nand->IO_ADDR;
-
-#ifdef CONFIG_MTD_NAND_ECC
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- int ecc_bytes = (nand->oobblock == 512) ? 6 : 3;
-#endif
-#endif
- /* pad oob area */
- for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++)
- nand->data_buf[i] = 0xff;
-
-#ifdef CONFIG_MTD_NAND_ECC
- /* Zero out the ECC array */
- for (i = 0; i < 6; i++)
- ecc_code[i] = 0x00;
-
- /* Read back previous written data, if col > 0 */
- if (col) {
- NanD_Command (nand, NAND_CMD_READ0);
- if (nand->bus16) {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + (col >> 1));
- } else {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + col);
- }
-
- if (nand->bus16) {
- u16 val;
-
- for (i = 0; i < col; i += 2) {
- val = READ_NAND (nandptr);
- nand->data_buf[i] = val & 0xff;
- nand->data_buf[i + 1] = val >> 8;
- }
- } else {
- for (i = 0; i < col; i++)
- nand->data_buf[i] = READ_NAND (nandptr);
- }
- }
-
- /* Calculate and write the ECC if we have enough data */
- if ((col < nand->eccsize) && (last >= nand->eccsize)) {
- nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0]));
- for (i = 0; i < 3; i++) {
- nand->data_buf[(nand->oobblock +
- oob_config.ecc_pos[i])] = ecc_code[i];
- }
- if (oob_config.eccvalid_pos != -1) {
- nand->data_buf[nand->oobblock +
- oob_config.eccvalid_pos] = 0xf0;
- }
- }
-
- /* Calculate and write the second ECC if we have enough data */
- if ((nand->oobblock == 512) && (last == nand->oobblock)) {
- nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3]));
- for (i = 3; i < 6; i++) {
- nand->data_buf[(nand->oobblock +
- oob_config.ecc_pos[i])] = ecc_code[i];
- }
- if (oob_config.eccvalid_pos != -1) {
- nand->data_buf[nand->oobblock +
- oob_config.eccvalid_pos] &= 0x0f;
- }
- }
-#endif
- /* Prepad for partial page programming !!! */
- for (i = 0; i < col; i++)
- nand->data_buf[i] = 0xff;
-
- /* Postpad for partial page programming !!! oob is already padded */
- for (i = last; i < nand->oobblock; i++)
- nand->data_buf[i] = 0xff;
-
- /* Send command to begin auto page programming */
- NanD_Command (nand, NAND_CMD_READ0);
- NanD_Command (nand, NAND_CMD_SEQIN);
- if (nand->bus16) {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + (col >> 1));
- } else {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + col);
- }
-
- /* Write out complete page of data */
- if (nand->bus16) {
- for (i = 0; i < (nand->oobblock + nand->oobsize); i += 2) {
- WRITE_NAND (nand->data_buf[i] +
- (nand->data_buf[i + 1] << 8),
- nand->IO_ADDR);
- }
- } else {
- for (i = 0; i < (nand->oobblock + nand->oobsize); i++)
- WRITE_NAND (nand->data_buf[i], nand->IO_ADDR);
- }
-
- /* Send command to actually program the data */
- NanD_Command (nand, NAND_CMD_PAGEPROG);
- NanD_Command (nand, NAND_CMD_STATUS);
-#ifdef NAND_NO_RB
- {
- u_char ret_val;
-
- do {
- ret_val = READ_NAND (nandptr); /* wait till ready */
- } while ((ret_val & 0x40) != 0x40);
- }
-#endif
- /* See if device thinks it succeeded */
- if (READ_NAND (nand->IO_ADDR) & 0x01) {
- printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__,
- page);
- return -1;
- }
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /*
- * The NAND device assumes that it is always writing to
- * a cleanly erased page. Hence, it performs its internal
- * write verification only on bits that transitioned from
- * 1 to 0. The device does NOT verify the whole page on a
- * byte by byte basis. It is possible that the page was
- * not completely erased or the page is becoming unusable
- * due to wear. The read with ECC would catch the error
- * later when the ECC page check fails, but we would rather
- * catch it early in the page write stage. Better to write
- * no data than invalid data.
- */
-
- /* Send command to read back the page */
- if (col < nand->eccsize)
- NanD_Command (nand, NAND_CMD_READ0);
- else
- NanD_Command (nand, NAND_CMD_READ1);
- if (nand->bus16) {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + (col >> 1));
- } else {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + col);
- }
-
- /* Loop through and verify the data */
- if (nand->bus16) {
- for (i = col; i < last; i = +2) {
- if ((nand->data_buf[i] +
- (nand->data_buf[i + 1] << 8)) != READ_NAND (nand->IO_ADDR)) {
- printf ("%s: Failed write verify, page 0x%08x ",
- __FUNCTION__, page);
- return -1;
- }
- }
- } else {
- for (i = col; i < last; i++) {
- if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) {
- printf ("%s: Failed write verify, page 0x%08x ",
- __FUNCTION__, page);
- return -1;
- }
- }
- }
-
-#ifdef CONFIG_MTD_NAND_ECC
- /*
- * We also want to check that the ECC bytes wrote
- * correctly for the same reasons stated above.
- */
- NanD_Command (nand, NAND_CMD_READOOB);
- if (nand->bus16) {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + (col >> 1));
- } else {
- NanD_Address (nand, ADDR_COLUMN_PAGE,
- (page << nand->page_shift) + col);
- }
- if (nand->bus16) {
- for (i = 0; i < nand->oobsize; i += 2) {
- u16 val;
-
- val = READ_NAND (nand->IO_ADDR);
- nand->data_buf[i] = val & 0xff;
- nand->data_buf[i + 1] = val >> 8;
- }
- } else {
- for (i = 0; i < nand->oobsize; i++) {
- nand->data_buf[i] = READ_NAND (nand->IO_ADDR);
- }
- }
- for (i = 0; i < ecc_bytes; i++) {
- if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) {
- printf ("%s: Failed ECC write "
- "verify, page 0x%08x, "
- "%6i bytes were succesful\n",
- __FUNCTION__, page, i);
- return -1;
- }
- }
-#endif /* CONFIG_MTD_NAND_ECC */
-#endif /* CONFIG_MTD_NAND_VERIFY_WRITE */
- return 0;
-}
-
-static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
- size_t * retlen, const u_char * buf, u_char * ecc_code)
-{
- int i, page, col, cnt, ret = 0;
-
- /* Do not allow write past end of device */
- if ((to + len) > nand->totlen) {
- printf ("%s: Attempt to write past end of page\n", __FUNCTION__);
- return -1;
- }
-
- /* Shift to get page */
- page = ((int) to) >> nand->page_shift;
-
- /* Get the starting column */
- col = to & (nand->oobblock - 1);
-
- /* Initialize return length value */
- *retlen = 0;
-
- /* Select the NAND device */
-#ifdef CONFIG_OMAP1510
- archflashwp(0,0);
-#endif
-#ifdef CFG_NAND_WP
- NAND_WP_OFF();
-#endif
-
- NAND_ENABLE_CE(nand); /* set pin low */
-
- /* Check the WP bit */
- NanD_Command(nand, NAND_CMD_STATUS);
- if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
- printf ("%s: Device is write protected!!!\n", __FUNCTION__);
- ret = -1;
- goto out;
- }
-
- /* Loop until all data is written */
- while (*retlen < len) {
- /* Invalidate cache, if we write to this page */
- if (nand->cache_page == page)
- nand->cache_page = -1;
-
- /* Write data into buffer */
- if ((col + len) >= nand->oobblock) {
- for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) {
- nand->data_buf[i] = buf[(*retlen + cnt)];
- }
- } else {
- for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) {
- nand->data_buf[i] = buf[(*retlen + cnt)];
- }
- }
- /* We use the same function for write and writev !) */
- ret = nand_write_page (nand, page, col, i, ecc_code);
- if (ret)
- goto out;
-
- /* Next data start at page boundary */
- col = 0;
-
- /* Update written bytes count */
- *retlen += cnt;
-
- /* Increment page address */
- page++;
- }
-
- /* Return happy */
- *retlen = len;
-
-out:
- /* De-select the NAND device */
- NAND_DISABLE_CE(nand); /* set pin high */
-#ifdef CONFIG_OMAP1510
- archflashwp(0,1);
-#endif
-#ifdef CFG_NAND_WP
- NAND_WP_ON();
-#endif
-
- return ret;
-}
-
-/* read from the 16 bytes of oob data that correspond to a 512 byte
- * page or 2 256-byte pages.
- */
-static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
- size_t * retlen, u_char * buf)
-{
- int len256 = 0;
- struct Nand *mychip;
- int ret = 0;
-
- mychip = &nand->chips[ofs >> nand->chipshift];
-
- /* update address for 2M x 8bit devices. OOB starts on the second */
- /* page to maintain compatibility with nand_read_ecc. */
- if (nand->page256) {
- if (!(ofs & 0x8))
- ofs += 0x100;
- else
- ofs -= 0x8;
- }
-
- NAND_ENABLE_CE(nand); /* set pin low */
- NanD_Command(nand, NAND_CMD_READOOB);
- if (nand->bus16) {
- NanD_Address(nand, ADDR_COLUMN_PAGE,
- ((ofs >> nand->page_shift) << nand->page_shift) +
- ((ofs & (nand->oobblock - 1)) >> 1));
- } else {
- NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
- }
-
- /* treat crossing 8-byte OOB data for 2M x 8bit devices */
- /* Note: datasheet says it should automaticaly wrap to the */
- /* next OOB block, but it didn't work here. mf. */
- if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
- len256 = (ofs | 0x7) + 1 - ofs;
- NanD_ReadBuf(nand, buf, len256);
-
- NanD_Command(nand, NAND_CMD_READOOB);
- NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
- }
-
- NanD_ReadBuf(nand, &buf[len256], len - len256);
-
- *retlen = len;
- /* Reading the full OOB data drops us off of the end of the page,
- * causing the flash device to go into busy mode, so we need
- * to wait until ready 11.4.1 and Toshiba TC58256FT nands */
-
- ret = NanD_WaitReady(nand, 1);
- NAND_DISABLE_CE(nand); /* set pin high */
-
- return ret;
-
-}
-
-/* write to the 16 bytes of oob data that correspond to a 512 byte
- * page or 2 256-byte pages.
- */
-static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
- size_t * retlen, const u_char * buf)
-{
- int len256 = 0;
- int i;
- unsigned long nandptr = nand->IO_ADDR;
-
-#ifdef PSYCHO_DEBUG
- printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",
- (long)ofs, len, buf[0], buf[1], buf[2], buf[3],
- buf[8], buf[9], buf[14],buf[15]);
-#endif
-
- NAND_ENABLE_CE(nand); /* set pin low to enable chip */
-
- /* Reset the chip */
- NanD_Command(nand, NAND_CMD_RESET);
-
- /* issue the Read2 command to set the pointer to the Spare Data Area. */
- NanD_Command(nand, NAND_CMD_READOOB);
- if (nand->bus16) {
- NanD_Address(nand, ADDR_COLUMN_PAGE,
- ((ofs >> nand->page_shift) << nand->page_shift) +
- ((ofs & (nand->oobblock - 1)) >> 1));
- } else {
- NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
- }
-
- /* update address for 2M x 8bit devices. OOB starts on the second */
- /* page to maintain compatibility with nand_read_ecc. */
- if (nand->page256) {
- if (!(ofs & 0x8))
- ofs += 0x100;
- else
- ofs -= 0x8;
- }
-
- /* issue the Serial Data In command to initial the Page Program process */
- NanD_Command(nand, NAND_CMD_SEQIN);
- if (nand->bus16) {
- NanD_Address(nand, ADDR_COLUMN_PAGE,
- ((ofs >> nand->page_shift) << nand->page_shift) +
- ((ofs & (nand->oobblock - 1)) >> 1));
- } else {
- NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
- }
-
- /* treat crossing 8-byte OOB data for 2M x 8bit devices */
- /* Note: datasheet says it should automaticaly wrap to the */
- /* next OOB block, but it didn't work here. mf. */
- if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
- len256 = (ofs | 0x7) + 1 - ofs;
- for (i = 0; i < len256; i++)
- WRITE_NAND(buf[i], nandptr);
-
- NanD_Command(nand, NAND_CMD_PAGEPROG);
- NanD_Command(nand, NAND_CMD_STATUS);
-#ifdef NAND_NO_RB
- { u_char ret_val;
- do {
- ret_val = READ_NAND(nandptr); /* wait till ready */
- } while ((ret_val & 0x40) != 0x40);
- }
-#endif
- if (READ_NAND(nandptr) & 1) {
- puts ("Error programming oob data\n");
- /* There was an error */
- NAND_DISABLE_CE(nand); /* set pin high */
- *retlen = 0;
- return -1;
- }
- NanD_Command(nand, NAND_CMD_SEQIN);
- NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
- }
-
- if (nand->bus16) {
- for (i = len256; i < len; i += 2) {
- WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr);
- }
- } else {
- for (i = len256; i < len; i++)
- WRITE_NAND(buf[i], nandptr);
- }
-
- NanD_Command(nand, NAND_CMD_PAGEPROG);
- NanD_Command(nand, NAND_CMD_STATUS);
-#ifdef NAND_NO_RB
- { u_char ret_val;
- do {
- ret_val = READ_NAND(nandptr); /* wait till ready */
- } while ((ret_val & 0x40) != 0x40);
- }
-#endif
- if (READ_NAND(nandptr) & 1) {
- puts ("Error programming oob data\n");
- /* There was an error */
- NAND_DISABLE_CE(nand); /* set pin high */
- *retlen = 0;
- return -1;
- }
-
- NAND_DISABLE_CE(nand); /* set pin high */
- *retlen = len;
- return 0;
-
-}
-
-int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean)
-{
- /* This is defined as a structure so it will work on any system
- * using native endian jffs2 (the default).
- */
- static struct jffs2_unknown_node clean_marker = {
- JFFS2_MAGIC_BITMASK,
- JFFS2_NODETYPE_CLEANMARKER,
- 8 /* 8 bytes in this node */
- };
- unsigned long nandptr;
- struct Nand *mychip;
- int ret = 0;
-
- if (ofs & (nand->erasesize-1) || len & (nand->erasesize-1)) {
- printf ("Offset and size must be sector aligned, erasesize = %d\n",
- (int) nand->erasesize);
- return -1;
- }
-
- nandptr = nand->IO_ADDR;
-
- /* Select the NAND device */
-#ifdef CONFIG_OMAP1510
- archflashwp(0,0);
-#endif
-#ifdef CFG_NAND_WP
- NAND_WP_OFF();
-#endif
- NAND_ENABLE_CE(nand); /* set pin low */
-
- /* Check the WP bit */
- NanD_Command(nand, NAND_CMD_STATUS);
- if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
- printf ("nand_write_ecc: Device is write protected!!!\n");
- ret = -1;
- goto out;
- }
-
- /* Check the WP bit */
- NanD_Command(nand, NAND_CMD_STATUS);
- if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
- printf ("%s: Device is write protected!!!\n", __FUNCTION__);
- ret = -1;
- goto out;
- }
-
- /* FIXME: Do nand in the background. Use timers or schedule_task() */
- while(len) {
- /*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/
- mychip = &nand->chips[ofs >> nand->chipshift];
-
- /* always check for bad block first, genuine bad blocks
- * should _never_ be erased.
- */
- if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) {
- /* Select the NAND device */
- NAND_ENABLE_CE(nand); /* set pin low */
-
- NanD_Command(nand, NAND_CMD_ERASE1);
- NanD_Address(nand, ADDR_PAGE, ofs);
- NanD_Command(nand, NAND_CMD_ERASE2);
-
- NanD_Command(nand, NAND_CMD_STATUS);
-
-#ifdef NAND_NO_RB
- { u_char ret_val;
- do {
- ret_val = READ_NAND(nandptr); /* wait till ready */
- } while ((ret_val & 0x40) != 0x40);
- }
-#endif
- if (READ_NAND(nandptr) & 1) {
- printf ("%s: Error erasing at 0x%lx\n",
- __FUNCTION__, (long)ofs);
- /* There was an error */
- ret = -1;
- goto out;
- }
- if (clean) {
- int n; /* return value not used */
- int p, l;
-
- /* clean marker position and size depend
- * on the page size, since 256 byte pages
- * only have 8 bytes of oob data
- */
- if (nand->page256) {
- p = NAND_JFFS2_OOB8_FSDAPOS;
- l = NAND_JFFS2_OOB8_FSDALEN;
- } else {
- p = NAND_JFFS2_OOB16_FSDAPOS;
- l = NAND_JFFS2_OOB16_FSDALEN;
- }
-
- ret = nand_write_oob(nand, ofs + p, l, (size_t *)&n,
- (u_char *)&clean_marker);
- /* quit here if write failed */
- if (ret)
- goto out;
- }
- }
- ofs += nand->erasesize;
- len -= nand->erasesize;
- }
-
-out:
- /* De-select the NAND device */
- NAND_DISABLE_CE(nand); /* set pin high */
-#ifdef CONFIG_OMAP1510
- archflashwp(0,1);
-#endif
-#ifdef CFG_NAND_WP
- NAND_WP_ON();
-#endif
-
- return ret;
-}
-
-static inline int nandcheck(unsigned long potential, unsigned long physadr)
-{
- return 0;
-}
-
-unsigned long nand_probe(unsigned long physadr)
-{
- struct nand_chip *nand = NULL;
- int i = 0, ChipID = 1;
-
-#ifdef CONFIG_MTD_NAND_ECC_JFFS2
- oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0;
- oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1;
- oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2;
- oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3;
- oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4;
- oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5;
- oob_config.eccvalid_pos = 4;
-#else
- oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0;
- oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1;
- oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2;
- oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3;
- oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4;
- oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5;
- oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS;
-#endif
- oob_config.badblock_pos = 5;
-
- for (i=0; i<CFG_MAX_NAND_DEVICE; i++) {
- if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) {
- nand = &nand_dev_desc[i];
- break;
- }
- }
- if (!nand)
- return (0);
-
- memset((char *)nand, 0, sizeof(struct nand_chip));
-
- nand->IO_ADDR = physadr;
- nand->cache_page = -1; /* init the cache page */
- NanD_ScanChips(nand);
-
- if (nand->totlen == 0) {
- /* no chips found, clean up and quit */
- memset((char *)nand, 0, sizeof(struct nand_chip));
- nand->ChipID = NAND_ChipID_UNKNOWN;
- return (0);
- }
-
- nand->ChipID = ChipID;
- if (curr_device == -1)
- curr_device = i;
-
- nand->data_buf = malloc (nand->oobblock + nand->oobsize);
- if (!nand->data_buf) {
- puts ("Cannot allocate memory for data structures.\n");
- return (0);
- }
-
- return (nand->totlen);
-}
-
-#ifdef CONFIG_MTD_NAND_ECC
-/*
- * Pre-calculated 256-way 1 byte column parity
- */
-static const u_char nand_ecc_precalc_table[] = {
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
-};
-
-
-/*
- * Creates non-inverted ECC code from line parity
- */
-static void nand_trans_result(u_char reg2, u_char reg3,
- u_char *ecc_code)
-{
- u_char a, b, i, tmp1, tmp2;
-
- /* Initialize variables */
- a = b = 0x80;
- tmp1 = tmp2 = 0;
-
- /* Calculate first ECC byte */
- for (i = 0; i < 4; i++) {
- if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
- tmp1 |= b;
- b >>= 1;
- if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
- tmp1 |= b;
- b >>= 1;
- a >>= 1;
- }
-
- /* Calculate second ECC byte */
- b = 0x80;
- for (i = 0; i < 4; i++) {
- if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
- tmp2 |= b;
- b >>= 1;
- if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
- tmp2 |= b;
- b >>= 1;
- a >>= 1;
- }
-
- /* Store two of the ECC bytes */
- ecc_code[0] = tmp1;
- ecc_code[1] = tmp2;
-}
-
-/*
- * Calculate 3 byte ECC code for 256 byte block
- */
-static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
-{
- u_char idx, reg1, reg3;
- int j;
-
- /* Initialize variables */
- reg1 = reg3 = 0;
- ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
-
- /* Build up column parity */
- for(j = 0; j < 256; j++) {
-
- /* Get CP0 - CP5 from table */
- idx = nand_ecc_precalc_table[dat[j]];
- reg1 ^= idx;
-
- /* All bit XOR = 1 ? */
- if (idx & 0x40) {
- reg3 ^= (u_char) j;
- }
- }
-
- /* Create non-inverted ECC code from line parity */
- nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
-
- /* Calculate final ECC code */
- ecc_code[0] = ~ecc_code[0];
- ecc_code[1] = ~ecc_code[1];
- ecc_code[2] = ((~reg1) << 2) | 0x03;
-}
-
-/*
- * Detect and correct a 1 bit error for 256 byte block
- */
-static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
-{
- u_char a, b, c, d1, d2, d3, add, bit, i;
-
- /* Do error detection */
- d1 = calc_ecc[0] ^ read_ecc[0];
- d2 = calc_ecc[1] ^ read_ecc[1];
- d3 = calc_ecc[2] ^ read_ecc[2];
-
- if ((d1 | d2 | d3) == 0) {
- /* No errors */
- return 0;
- } else {
- a = (d1 ^ (d1 >> 1)) & 0x55;
- b = (d2 ^ (d2 >> 1)) & 0x55;
- c = (d3 ^ (d3 >> 1)) & 0x54;
-
- /* Found and will correct single bit error in the data */
- if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
- c = 0x80;
- add = 0;
- a = 0x80;
- for (i=0; i<4; i++) {
- if (d1 & c)
- add |= a;
- c >>= 2;
- a >>= 1;
- }
- c = 0x80;
- for (i=0; i<4; i++) {
- if (d2 & c)
- add |= a;
- c >>= 2;
- a >>= 1;
- }
- bit = 0;
- b = 0x04;
- c = 0x80;
- for (i=0; i<3; i++) {
- if (d3 & c)
- bit |= b;
- c >>= 2;
- b >>= 1;
- }
- b = 0x01;
- a = dat[add];
- a ^= (b << bit);
- dat[add] = a;
- return 1;
- }
- else {
- i = 0;
- while (d1) {
- if (d1 & 0x01)
- ++i;
- d1 >>= 1;
- }
- while (d2) {
- if (d2 & 0x01)
- ++i;
- d2 >>= 1;
- }
- while (d3) {
- if (d3 & 0x01)
- ++i;
- d3 >>= 1;
- }
- if (i == 1) {
- /* ECC Code Error Correction */
- read_ecc[0] = calc_ecc[0];
- read_ecc[1] = calc_ecc[1];
- read_ecc[2] = calc_ecc[2];
- return 2;
- }
- else {
- /* Uncorrectable Error */
- return -1;
- }
- }
- }
-
- /* Should never happen */
- return -1;
-}
-
-#endif
-
-#ifdef CONFIG_JFFS2_NAND
-
-int read_jffs2_nand(size_t start, size_t len,
- size_t * retlen, u_char * buf, int nanddev)
-{
- return nand_rw(nand_dev_desc + nanddev, NANDRW_READ | NANDRW_JFFS2,
- start, len, retlen, buf);
-}
-
-#endif /* CONFIG_JFFS2_NAND */
-
-
-#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
+#endif /* CFG_NAND_LEGACY */
+++ /dev/null
-#include <common.h>
-
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined CONFIG_NEW_NAND_CODE
-
-#include <command.h>
-#include <watchdog.h>
-#include <malloc.h>
-#include <asm/byteorder.h>
-
-#ifdef CONFIG_SHOW_BOOT_PROGRESS
-# include <status_led.h>
-# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
-#else
-# define SHOW_BOOT_PROGRESS(arg)
-#endif
-
-#include <jffs2/jffs2.h>
-#include <nand.h>
-
-extern nand_info_t nand_info[]; /* info for NAND chips */
-
-static int nand_dump_oob(nand_info_t *nand, ulong off)
-{
- return 0;
-}
-
-static int nand_dump(nand_info_t *nand, ulong off)
-{
- int i;
- u_char *buf, *p;
-
- buf = malloc(nand->oobblock + nand->oobsize);
- if (!buf) {
- puts("No memory for page buffer\n");
- return 1;
- }
- off &= ~(nand->oobblock - 1);
- i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize);
- if (i < 0) {
- printf("Error (%d) reading page %08x\n", i, off);
- free(buf);
- return 1;
- }
- printf("Page %08x dump:\n", off);
- i = nand->oobblock >> 4; p = buf;
- while (i--) {
- printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x"
- " %02x %02x %02x %02x %02x %02x %02x %02x\n",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
- p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
- p += 16;
- }
- puts("OOB:\n");
- i = nand->oobsize >> 3;
- while (i--) {
- printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
- p += 8;
- }
- free(buf);
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void
-arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize)
-{
- *off = 0;
- *size = 0;
-
-#if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART)
- if (argc >= 1 && strcmp(argv[0], "partition") == 0) {
- int part_num;
- struct part_info *part;
- const char *partstr;
-
- if (argc >= 2)
- partstr = argv[1];
- else
- partstr = getenv("partition");
-
- if (partstr)
- part_num = (int)simple_strtoul(partstr, NULL, 10);
- else
- part_num = 0;
-
- part = jffs2_part_info(part_num);
- if (part == NULL) {
- printf("\nInvalid partition %d\n", part_num);
- return;
- }
- *size = part->size;
- *off = (ulong)part->offset;
- } else
-#endif
- {
- if (argc >= 1)
- *off = (ulong)simple_strtoul(argv[0], NULL, 16);
- else
- *off = 0;
-
- if (argc >= 2)
- *size = (ulong)simple_strtoul(argv[1], NULL, 16);
- else
- *size = totsize - *off;
-
- }
-
-}
-
-int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
-{
- int i, dev, ret;
- ulong addr, off, size;
- char *cmd, *s;
- nand_info_t *nand;
-
- /* at least two arguments please */
- if (argc < 2)
- goto usage;
-
- cmd = argv[1];
-
- if (strcmp(cmd, "info") == 0) {
-
- putc('\n');
- for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
- if (nand_info[i].name)
- printf("Device %d: %s\n", i, nand_info[i].name);
- }
- return 0;
- }
-
- if (strcmp(cmd, "device") == 0) {
-
- if (argc < 3) {
- if ((nand_curr_device < 0) ||
- (nand_curr_device >= CFG_MAX_NAND_DEVICE))
- puts("\nno devices available\n");
- else
- printf("\nDevice %d: %s\n", nand_curr_device,
- nand_info[nand_curr_device].name);
- return 0;
- }
- dev = (int)simple_strtoul(argv[2], NULL, 10);
- if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
- puts("No such device\n");
- return 1;
- }
- printf("Device %d: %s", dev, nand_info[dev].name);
- puts("... is now current device\n");
- nand_curr_device = dev;
- return 0;
- }
-
- if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
- strncmp(cmd, "dump", 4) != 0 &&
- strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0)
- goto usage;
-
- /* the following commands operate on the current device */
- if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE ||
- !nand_info[nand_curr_device].name) {
- puts("\nno devices available\n");
- return 1;
- }
- nand = &nand_info[nand_curr_device];
-
- if (strcmp(cmd, "bad") == 0) {
- printf("\nDevice %d bad blocks:\n", nand_curr_device);
- for (off = 0; off < nand->size; off += nand->erasesize)
- if (nand_block_isbad(nand, off))
- printf(" %08x\n", off);
- return 0;
- }
-
- if (strcmp(cmd, "erase") == 0) {
- arg_off_size(argc - 2, argv + 2, &off, &size, nand->size);
- if (off == 0 && size == 0)
- return 1;
-
- printf("\nNAND erase: device %d offset 0x%x, size 0x%x ",
- nand_curr_device, off, size);
- ret = nand_erase(nand, off, size);
- printf("%s\n", ret ? "ERROR" : "OK");
-
- return ret == 0 ? 0 : 1;
- }
-
- if (strncmp(cmd, "dump", 4) == 0) {
- if (argc < 3)
- goto usage;
-
- s = strchr(cmd, '.');
- off = (int)simple_strtoul(argv[2], NULL, 16);
-
- if (s != NULL && strcmp(s, ".oob") == 0)
- ret = nand_dump_oob(nand, off);
- else
- ret = nand_dump(nand, off);
-
- return ret == 0 ? 1 : 0;
-
- }
-
- /* read write */
- if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
- if (argc < 4)
- goto usage;
-/*
- s = strchr(cmd, '.');
- clean = CLEAN_NONE;
- if (s != NULL) {
- if (strcmp(s, ".jffs2") == 0 || strcmp(s, ".e") == 0
- || strcmp(s, ".i"))
- clean = CLEAN_JFFS2;
- }
-*/
- addr = (ulong)simple_strtoul(argv[2], NULL, 16);
-
- arg_off_size(argc - 3, argv + 3, &off, &size, nand->size);
- if (off == 0 && size == 0)
- return 1;
-
- i = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
- printf("\nNAND %s: device %d offset %u, size %u ... ",
- i ? "read" : "write", nand_curr_device, off, size);
-
- if (i)
- ret = nand_read(nand, off, &size, (u_char *)addr);
- else
- ret = nand_write(nand, off, &size, (u_char *)addr);
-
- printf(" %d bytes %s: %s\n", size,
- i ? "read" : "written", ret ? "ERROR" : "OK");
-
- return ret == 0 ? 0 : 1;
- }
-usage:
- printf("Usage:\n%s\n", cmdtp->usage);
- return 1;
-}
-
-U_BOOT_CMD(nand, 5, 1, do_nand,
- "nand - NAND sub-system\n",
- "info - show available NAND devices\n"
- "nand device [dev] - show or set current device\n"
- "nand read[.jffs2] - addr off size\n"
- "nand write[.jffs2] - addr off size - read/write `size' bytes starting\n"
- " at offset `off' to/from memory address `addr'\n"
- "nand erase [clean] [off size] - erase `size' bytes from\n"
- " offset `off' (entire device if not specified)\n"
- "nand bad - show bad blocks\n"
- "nand dump[.oob] off - dump page\n"
- "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
- "nand markbad off - mark bad block at offset (UNSAFE)\n"
- "nand biterr off - make a bit error at offset (UNSAFE)\n");
-
-int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
-{
- char *boot_device = NULL;
- char *ep;
- int dev;
- int r;
- ulong addr, cnt, offset = 0;
- image_header_t *hdr;
- nand_info_t *nand;
-
- switch (argc) {
- case 1:
- addr = CFG_LOAD_ADDR;
- boot_device = getenv("bootdevice");
- break;
- case 2:
- addr = simple_strtoul(argv[1], NULL, 16);
- boot_device = getenv("bootdevice");
- break;
- case 3:
- addr = simple_strtoul(argv[1], NULL, 16);
- boot_device = argv[2];
- break;
- case 4:
- addr = simple_strtoul(argv[1], NULL, 16);
- boot_device = argv[2];
- offset = simple_strtoul(argv[3], NULL, 16);
- break;
- default:
- printf("Usage:\n%s\n", cmdtp->usage);
- SHOW_BOOT_PROGRESS(-1);
- return 1;
- }
-
- if (!boot_device) {
- puts("\n** No boot device **\n");
- SHOW_BOOT_PROGRESS(-1);
- return 1;
- }
-
- dev = simple_strtoul(boot_device, &ep, 16);
-
- if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
- printf("\n** Device %d not available\n", dev);
- SHOW_BOOT_PROGRESS(-1);
- return 1;
- }
-
- nand = &nand_info[dev];
- printf("\nLoading from device %d: %s (offset 0x%lx)\n",
- dev, nand->name, offset);
-
- cnt = nand->oobblock;
- r = nand_read(nand, offset, &cnt, (u_char *) addr);
- if (r) {
- printf("** Read error on %d\n", dev);
- SHOW_BOOT_PROGRESS(-1);
- return 1;
- }
-
- hdr = (image_header_t *) addr;
-
- if (ntohl(hdr->ih_magic) != IH_MAGIC) {
- printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
- SHOW_BOOT_PROGRESS(-1);
- return 1;
- }
-
- print_image_hdr(hdr);
-
- cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t));
-
- r = nand_read(nand, offset, &cnt, (u_char *) addr);
- if (r) {
- printf("** Read error on %d\n", dev);
- SHOW_BOOT_PROGRESS(-1);
- return 1;
- }
-
- /* Loading ok, update default load address */
-
- load_addr = addr;
-
- /* Check if we should attempt an auto-start */
- if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
- char *local_args[2];
- extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
-
- local_args[0] = argv[0];
- local_args[1] = NULL;
-
- printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
-
- do_bootm(cmdtp, 0, 1, local_args);
- return 1;
- }
- return 0;
-}
-
-U_BOOT_CMD(nboot, 4, 1, do_nandboot,
- "nboot - boot from NAND device\n", "loadAddr dev\n");
-
-
-#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
#include <command.h>
#include <environment.h>
#include <linux/stddef.h>
-#include <linux/mtd/nand.h>
+#include <nand.h>
#if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_NAND)) == (CFG_CMD_ENV|CFG_CMD_NAND))
#define CMD_SAVEENV
#error CONFIG_INFERNO not supported yet
#endif
-/* references to names in cmd_nand.c */
-#define NANDRW_READ 0x01
-#define NANDRW_WRITE 0x00
-#define NANDRW_JFFS2 0x02
-extern struct nand_chip nand_dev_desc[];
-int nand_rw (struct nand_chip* nand, int cmd,
+int nand_legacy_rw (struct nand_chip* nand, int cmd,
size_t start, size_t len,
size_t * retlen, u_char * buf);
-int nand_erase(struct nand_chip* nand, size_t ofs,
- size_t len, int clean);
+
+/* info for NAND chips, defined in drivers/nand/nand.c */
+extern nand_info_t nand_info[];
/* references to names in env_common.c */
extern uchar default_environment[];
}
#ifdef CMD_SAVEENV
+/*
+ * The legacy NAND code saved the environment in the first NAND device i.e.,
+ * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
+ */
int saveenv(void)
{
int total, ret = 0;
- puts ("Erasing Nand...");
- if (nand_erase(nand_dev_desc + 0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))
- return 1;
+
+ puts ("Erasing Nand...");
+ if (nand_erase(&nand_info[0], CFG_NEW_OFFSET, CFG_ENV_SIZE))
+ return 1;
puts ("Writing to Nand... ");
- ret = nand_rw(nand_dev_desc + 0,
- NANDRW_WRITE | NANDRW_JFFS2, CFG_ENV_OFFSET, CFG_ENV_SIZE,
- &total, (u_char*)env_ptr);
- if (ret || total != CFG_ENV_SIZE)
+ total = CFG_ENV_SIZE;
+ ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total,
+ (u_char*) env_ptr);
+ if (ret || total != CFG_ENV_SIZE)
return 1;
- puts ("done\n");
- return ret;
+ puts ("done\n");
+ return ret;
}
#endif /* CMD_SAVEENV */
+/*
+ * The legacy NAND code saved the environment in the first NAND device i.e.,
+ * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
+ */
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
int ret, total;
- ret = nand_rw(nand_dev_desc + 0,
- NANDRW_READ | NANDRW_JFFS2, CFG_ENV_OFFSET, CFG_ENV_SIZE,
- &total, (u_char*)env_ptr);
+ total = CFG_ENV_SIZE;
+ ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total,
+ (u_char*) env_ptr);
if (ret || total != CFG_ENV_SIZE)
return use_default();
*/
#include <common.h>
-#ifdef CONFIG_NEW_NAND_CODE
+
+#ifdef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY defined in a file not using the legacy NAND support!
+#endif
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n");
-#endif /* CONFIG_NEW_NAND_CODE */
#include <common.h>
-#ifdef CONFIG_NEW_NAND_CODE
+#ifdef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY defined in a file not using the legacy NAND support!
+#endif
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#include <nand.h>
}
#endif
-#endif /* CONFIG_NEW_NAND_CODE */
-
#endif
#include <common.h>
-#ifdef CONFIG_NEW_NAND_CODE
+
+#ifdef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY defined in a file not using the legacy NAND support!
+#endif
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
break;
}
}
-
- /* XXX nand device 1 on dave (PPChameleonEVB) needs more time */
+#ifdef PPCHAMELON_NAND_TIMER_HACK
reset_timer();
while (get_timer(0) < 10);
+#endif /* PPCHAMELON_NAND_TIMER_HACK */
return this->read_byte(mtd);
}
}
#endif
-#endif /* CONFIG_NEW_NAND_CODE */
-
#include <common.h>
-#ifdef CONFIG_NEW_NAND_CODE
+#ifdef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY defined in a file not using the legacy NAND support!
+#endif
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#include <malloc.h>
}
#endif
-#endif /* CONFIG_NEW_NAND_CODE */
-
#include <common.h>
-#ifdef CONFIG_NEW_NAND_CODE
+#ifdef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY defined in a file not using the legacy NAND support!
+#endif
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#include<linux/mtd/mtd.h>
}
#endif /* CONFIG_COMMANDS & CFG_CMD_NAND */
-#endif /* CONFIG_NEW_NAND_CODE */
-
#include <common.h>
-#ifdef CONFIG_NEW_NAND_CODE
+#ifdef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY defined in a file not using the legacy NAND support!
+#endif
+
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#include <linux/mtd/nand.h>
{0x0, "Unknown"}
};
#endif
-#endif /* CONFIG_NEW_NAND_CODE */
-
--- /dev/null
+include $(TOPDIR)/config.mk
+
+LIB := libnand_legacy.a
+
+OBJS := nand_legacy.o
+all: $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend: Makefile $(OBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@
+
+sinclude .depend
--- /dev/null
+/*
+ * (C) 2006 Denx
+ * Driver for NAND support, Rick Bronson
+ * borrowed heavily from:
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Added 16-bit nand support
+ * (C) 2004 Texas Instruments
+ */
+
+#include <common.h>
+
+#ifndef CFG_NAND_LEGACY
+#error CFG_NAND_LEGACY not defined in a file using the legacy NAND support!
+#endif
+
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <watchdog.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_NAND)
+
+#include <linux/mtd/nand_legacy.h>
+#include <linux/mtd/nand_ids.h>
+#include <jffs2/jffs2.h>
+
+#ifdef CONFIG_OMAP1510
+void archflashwp(void *archdata, int wp);
+#endif
+
+#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
+
+#undef PSYCHO_DEBUG
+#undef NAND_DEBUG
+
+/* ****************** WARNING *********************
+ * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will
+ * erase (or at least attempt to erase) blocks that are marked
+ * bad. This can be very handy if you are _sure_ that the block
+ * is OK, say because you marked a good block bad to test bad
+ * block handling and you are done testing, or if you have
+ * accidentally marked blocks bad.
+ *
+ * Erasing factory marked bad blocks is a _bad_ idea. If the
+ * erase succeeds there is no reliable way to find them again,
+ * and attempting to program or erase bad blocks can affect
+ * the data in _other_ (good) blocks.
+ */
+#define ALLOW_ERASE_BAD_DEBUG 0
+
+#define CONFIG_MTD_NAND_ECC /* enable ECC */
+#define CONFIG_MTD_NAND_ECC_JFFS2
+
+/* bits for nand_legacy_rw() `cmd'; or together as needed */
+#define NANDRW_READ 0x01
+#define NANDRW_WRITE 0x00
+#define NANDRW_JFFS2 0x02
+#define NANDRW_JFFS2_SKIP 0x04
+
+
+/*
+ * Exported variables etc.
+ */
+
+/* Definition of the out of band configuration structure */
+struct nand_oob_config {
+ /* position of ECC bytes inside oob */
+ int ecc_pos[6];
+ /* position of bad blk flag inside oob -1 = inactive */
+ int badblock_pos;
+ /* position of ECC valid flag inside oob -1 = inactive */
+ int eccvalid_pos;
+} oob_config = { {0}, 0, 0};
+
+struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE] = {{0}};
+
+int curr_device = -1; /* Current NAND Device */
+
+
+/*
+ * Exported functionss
+ */
+int nand_legacy_erase(struct nand_chip* nand, size_t ofs,
+ size_t len, int clean);
+int nand_legacy_rw(struct nand_chip* nand, int cmd,
+ size_t start, size_t len,
+ size_t * retlen, u_char * buf);
+void nand_print(struct nand_chip *nand);
+void nand_print_bad(struct nand_chip *nand);
+int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, u_char * buf);
+int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, const u_char * buf);
+
+/*
+ * Internals
+ */
+static int NanD_WaitReady(struct nand_chip *nand, int ale_wait);
+static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
+ size_t * retlen, u_char *buf, u_char *ecc_code);
+static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
+ size_t * retlen, const u_char * buf,
+ u_char * ecc_code);
+#ifdef CONFIG_MTD_NAND_ECC
+static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
+#endif
+
+
+/*
+ *
+ * Function definitions
+ *
+ */
+
+/* returns 0 if block containing pos is OK:
+ * valid erase block and
+ * not marked bad, or no bad mark position is specified
+ * returns 1 if marked bad or otherwise invalid
+ */
+static int check_block (struct nand_chip *nand, unsigned long pos)
+{
+ size_t retlen;
+ uint8_t oob_data;
+ uint16_t oob_data16[6];
+ int page0 = pos & (-nand->erasesize);
+ int page1 = page0 + nand->oobblock;
+ int badpos = oob_config.badblock_pos;
+
+ if (pos >= nand->totlen)
+ return 1;
+
+ if (badpos < 0)
+ return 0; /* no way to check, assume OK */
+
+ if (nand->bus16) {
+ if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16)
+ || (oob_data16[2] & 0xff00) != 0xff00)
+ return 1;
+ if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16)
+ || (oob_data16[2] & 0xff00) != 0xff00)
+ return 1;
+ } else {
+ /* Note - bad block marker can be on first or second page */
+ if (nand_read_oob(nand, page0 + badpos, 1, &retlen, (unsigned char *)&oob_data)
+ || oob_data != 0xff
+ || nand_read_oob (nand, page1 + badpos, 1, &retlen, (unsigned char *)&oob_data)
+ || oob_data != 0xff)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* print bad blocks in NAND flash */
+void nand_print_bad(struct nand_chip* nand)
+{
+ unsigned long pos;
+
+ for (pos = 0; pos < nand->totlen; pos += nand->erasesize) {
+ if (check_block(nand, pos))
+ printf(" 0x%8.8lx\n", pos);
+ }
+ puts("\n");
+}
+
+/* cmd: 0: NANDRW_WRITE write, fail on bad block
+ * 1: NANDRW_READ read, fail on bad block
+ * 2: NANDRW_WRITE | NANDRW_JFFS2 write, skip bad blocks
+ * 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks
+ * 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks
+ */
+int nand_legacy_rw (struct nand_chip* nand, int cmd,
+ size_t start, size_t len,
+ size_t * retlen, u_char * buf)
+{
+ int ret = 0, n, total = 0;
+ char eccbuf[6];
+ /* eblk (once set) is the start of the erase block containing the
+ * data being processed.
+ */
+ unsigned long eblk = ~0; /* force mismatch on first pass */
+ unsigned long erasesize = nand->erasesize;
+
+ while (len) {
+ if ((start & (-erasesize)) != eblk) {
+ /* have crossed into new erase block, deal with
+ * it if it is sure marked bad.
+ */
+ eblk = start & (-erasesize); /* start of block */
+ if (check_block(nand, eblk)) {
+ if (cmd == (NANDRW_READ | NANDRW_JFFS2)) {
+ while (len > 0 &&
+ start - eblk < erasesize) {
+ *(buf++) = 0xff;
+ ++start;
+ ++total;
+ --len;
+ }
+ continue;
+ } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
+ start += erasesize;
+ continue;
+ } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
+ /* skip bad block */
+ start += erasesize;
+ continue;
+ } else {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ /* The ECC will not be calculated correctly if
+ less than 512 is written or read */
+ /* Is request at least 512 bytes AND it starts on a proper boundry */
+ if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200))
+ printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n");
+
+ if (cmd & NANDRW_READ) {
+ ret = nand_read_ecc(nand, start,
+ min(len, eblk + erasesize - start),
+ (size_t *)&n, (u_char*)buf, (u_char *)eccbuf);
+ } else {
+ ret = nand_write_ecc(nand, start,
+ min(len, eblk + erasesize - start),
+ (size_t *)&n, (u_char*)buf, (u_char *)eccbuf);
+ }
+
+ if (ret)
+ break;
+
+ start += n;
+ buf += n;
+ total += n;
+ len -= n;
+ }
+ if (retlen)
+ *retlen = total;
+
+ return ret;
+}
+
+void nand_print(struct nand_chip *nand)
+{
+ if (nand->numchips > 1) {
+ printf("%s at 0x%lx,\n"
+ "\t %d chips %s, size %d MB, \n"
+ "\t total size %ld MB, sector size %ld kB\n",
+ nand->name, nand->IO_ADDR, nand->numchips,
+ nand->chips_name, 1 << (nand->chipshift - 20),
+ nand->totlen >> 20, nand->erasesize >> 10);
+ }
+ else {
+ printf("%s at 0x%lx (", nand->chips_name, nand->IO_ADDR);
+ print_size(nand->totlen, ", ");
+ print_size(nand->erasesize, " sector)\n");
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int NanD_WaitReady(struct nand_chip *nand, int ale_wait)
+{
+ /* This is inline, to optimise the common case, where it's ready instantly */
+ int ret = 0;
+
+#ifdef NAND_NO_RB /* in config file, shorter delays currently wrap accesses */
+ if(ale_wait)
+ NAND_WAIT_READY(nand); /* do the worst case 25us wait */
+ else
+ udelay(10);
+#else /* has functional r/b signal */
+ NAND_WAIT_READY(nand);
+#endif
+ return ret;
+}
+
+/* NanD_Command: Send a flash command to the flash chip */
+
+static inline int NanD_Command(struct nand_chip *nand, unsigned char command)
+{
+ unsigned long nandptr = nand->IO_ADDR;
+
+ /* Assert the CLE (Command Latch Enable) line to the flash chip */
+ NAND_CTL_SETCLE(nandptr);
+
+ /* Send the command */
+ WRITE_NAND_COMMAND(command, nandptr);
+
+ /* Lower the CLE line */
+ NAND_CTL_CLRCLE(nandptr);
+
+#ifdef NAND_NO_RB
+ if(command == NAND_CMD_RESET){
+ u_char ret_val;
+ NanD_Command(nand, NAND_CMD_STATUS);
+ do {
+ ret_val = READ_NAND(nandptr);/* wait till ready */
+ } while((ret_val & 0x40) != 0x40);
+ }
+#endif
+ return NanD_WaitReady(nand, 0);
+}
+
+/* NanD_Address: Set the current address for the flash chip */
+
+static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs)
+{
+ unsigned long nandptr;
+ int i;
+
+ nandptr = nand->IO_ADDR;
+
+ /* Assert the ALE (Address Latch Enable) line to the flash chip */
+ NAND_CTL_SETALE(nandptr);
+
+ /* Send the address */
+ /* Devices with 256-byte page are addressed as:
+ * Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
+ * there is no device on the market with page256
+ * and more than 24 bits.
+ * Devices with 512-byte page are addressed as:
+ * Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
+ * 25-31 is sent only if the chip support it.
+ * bit 8 changes the read command to be sent
+ * (NAND_CMD_READ0 or NAND_CMD_READ1).
+ */
+
+ if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE)
+ WRITE_NAND_ADDRESS(ofs, nandptr);
+
+ ofs = ofs >> nand->page_shift;
+
+ if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+ for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) {
+ WRITE_NAND_ADDRESS(ofs, nandptr);
+ }
+ }
+
+ /* Lower the ALE line */
+ NAND_CTL_CLRALE(nandptr);
+
+ /* Wait for the chip to respond */
+ return NanD_WaitReady(nand, 1);
+}
+
+/* NanD_SelectChip: Select a given flash chip within the current floor */
+
+static inline int NanD_SelectChip(struct nand_chip *nand, int chip)
+{
+ /* Wait for it to be ready */
+ return NanD_WaitReady(nand, 0);
+}
+
+/* NanD_IdentChip: Identify a given NAND chip given {floor,chip} */
+
+static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip)
+{
+ int mfr, id, i;
+
+ NAND_ENABLE_CE(nand); /* set pin low */
+ /* Reset the chip */
+ if (NanD_Command(nand, NAND_CMD_RESET)) {
+#ifdef NAND_DEBUG
+ printf("NanD_Command (reset) for %d,%d returned true\n",
+ floor, chip);
+#endif
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 1. Send ReadID command */
+ if (NanD_Command(nand, NAND_CMD_READID)) {
+#ifdef NAND_DEBUG
+ printf("NanD_Command (ReadID) for %d,%d returned true\n",
+ floor, chip);
+#endif
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 2. Send address byte zero */
+ NanD_Address(nand, ADDR_COLUMN, 0);
+
+ /* Read the manufacturer and device id codes from the device */
+
+ mfr = READ_NAND(nand->IO_ADDR);
+
+ id = READ_NAND(nand->IO_ADDR);
+
+ NAND_DISABLE_CE(nand); /* set pin high */
+
+#ifdef NAND_DEBUG
+ printf("NanD_Command (ReadID) got %x %x\n", mfr, id);
+#endif
+ if (mfr == 0xff || mfr == 0) {
+ /* No response - return failure */
+ return 0;
+ }
+
+ /* Check it's the same as the first chip we identified.
+ * M-Systems say that any given nand_chip device should only
+ * contain _one_ type of flash part, although that's not a
+ * hardware restriction. */
+ if (nand->mfr) {
+ if (nand->mfr == mfr && nand->id == id) {
+ return 1; /* This is another the same the first */
+ } else {
+ printf("Flash chip at floor %d, chip %d is different:\n",
+ floor, chip);
+ }
+ }
+
+ /* Print and store the manufacturer and ID codes. */
+ for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+ if (mfr == nand_flash_ids[i].manufacture_id &&
+ id == nand_flash_ids[i].model_id) {
+#ifdef NAND_DEBUG
+ printf("Flash chip found:\n\t Manufacturer ID: 0x%2.2X, "
+ "Chip ID: 0x%2.2X (%s)\n", mfr, id,
+ nand_flash_ids[i].name);
+#endif
+ if (!nand->mfr) {
+ nand->mfr = mfr;
+ nand->id = id;
+ nand->chipshift =
+ nand_flash_ids[i].chipshift;
+ nand->page256 = nand_flash_ids[i].page256;
+ nand->eccsize = 256;
+ if (nand->page256) {
+ nand->oobblock = 256;
+ nand->oobsize = 8;
+ nand->page_shift = 8;
+ } else {
+ nand->oobblock = 512;
+ nand->oobsize = 16;
+ nand->page_shift = 9;
+ }
+ nand->pageadrlen = nand_flash_ids[i].pageadrlen;
+ nand->erasesize = nand_flash_ids[i].erasesize;
+ nand->chips_name = nand_flash_ids[i].name;
+ nand->bus16 = nand_flash_ids[i].bus16;
+ return 1;
+ }
+ return 0;
+ }
+ }
+
+
+#ifdef NAND_DEBUG
+ /* We haven't fully identified the chip. Print as much as we know. */
+ printf("Unknown flash chip found: %2.2X %2.2X\n",
+ id, mfr);
+#endif
+
+ return 0;
+}
+
+/* NanD_ScanChips: Find all NAND chips present in a nand_chip, and identify them */
+
+static void NanD_ScanChips(struct nand_chip *nand)
+{
+ int floor, chip;
+ int numchips[NAND_MAX_FLOORS];
+ int maxchips = NAND_MAX_CHIPS;
+ int ret = 1;
+
+ nand->numchips = 0;
+ nand->mfr = 0;
+ nand->id = 0;
+
+
+ /* For each floor, find the number of valid chips it contains */
+ for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {
+ ret = 1;
+ numchips[floor] = 0;
+ for (chip = 0; chip < maxchips && ret != 0; chip++) {
+
+ ret = NanD_IdentChip(nand, floor, chip);
+ if (ret) {
+ numchips[floor]++;
+ nand->numchips++;
+ }
+ }
+ }
+
+ /* If there are none at all that we recognise, bail */
+ if (!nand->numchips) {
+#ifdef NAND_DEBUG
+ puts ("No NAND flash chips recognised.\n");
+#endif
+ return;
+ }
+
+ /* Allocate an array to hold the information for each chip */
+ nand->chips = malloc(sizeof(struct Nand) * nand->numchips);
+ if (!nand->chips) {
+ puts ("No memory for allocating chip info structures\n");
+ return;
+ }
+
+ ret = 0;
+
+ /* Fill out the chip array with {floor, chipno} for each
+ * detected chip in the device. */
+ for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {
+ for (chip = 0; chip < numchips[floor]; chip++) {
+ nand->chips[ret].floor = floor;
+ nand->chips[ret].chip = chip;
+ nand->chips[ret].curadr = 0;
+ nand->chips[ret].curmode = 0x50;
+ ret++;
+ }
+ }
+
+ /* Calculate and print the total size of the device */
+ nand->totlen = nand->numchips * (1 << nand->chipshift);
+
+#ifdef NAND_DEBUG
+ printf("%d flash chips found. Total nand_chip size: %ld MB\n",
+ nand->numchips, nand->totlen >> 20);
+#endif
+}
+
+/* we need to be fast here, 1 us per read translates to 1 second per meg */
+static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr)
+{
+ unsigned long nandptr = nand->IO_ADDR;
+
+ NanD_Command (nand, NAND_CMD_READ0);
+
+ if (nand->bus16) {
+ u16 val;
+
+ while (cntr >= 16) {
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ cntr -= 16;
+ }
+
+ while (cntr > 0) {
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ cntr -= 2;
+ }
+ } else {
+ while (cntr >= 16) {
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ cntr -= 16;
+ }
+
+ while (cntr > 0) {
+ *data_buf++ = READ_NAND (nandptr);
+ cntr--;
+ }
+ }
+}
+
+/*
+ * NAND read with ECC
+ */
+static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
+ size_t * retlen, u_char *buf, u_char *ecc_code)
+{
+ int col, page;
+ int ecc_status = 0;
+#ifdef CONFIG_MTD_NAND_ECC
+ int j;
+ int ecc_failed = 0;
+ u_char *data_poi;
+ u_char ecc_calc[6];
+#endif
+
+ /* Do not allow reads past end of device */
+ if ((start + len) > nand->totlen) {
+ printf ("%s: Attempt read beyond end of device %x %x %x\n",
+ __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen);
+ *retlen = 0;
+ return -1;
+ }
+
+ /* First we calculate the starting page */
+ /*page = shr(start, nand->page_shift);*/
+ page = start >> nand->page_shift;
+
+ /* Get raw starting column */
+ col = start & (nand->oobblock - 1);
+
+ /* Initialize return value */
+ *retlen = 0;
+
+ /* Select the NAND device */
+ NAND_ENABLE_CE(nand); /* set pin low */
+
+ /* Loop until all data read */
+ while (*retlen < len) {
+
+#ifdef CONFIG_MTD_NAND_ECC
+ /* Do we have this page in cache ? */
+ if (nand->cache_page == page)
+ goto readdata;
+ /* Send the read command */
+ NanD_Command(nand, NAND_CMD_READ0);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ /* Read in a page + oob data */
+ NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize);
+
+ /* copy data into cache, for read out of cache and if ecc fails */
+ if (nand->data_cache) {
+ memcpy (nand->data_cache, nand->data_buf,
+ nand->oobblock + nand->oobsize);
+ }
+
+ /* Pick the ECC bytes out of the oob data */
+ for (j = 0; j < 6; j++) {
+ ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])];
+ }
+
+ /* Calculate the ECC and verify it */
+ /* If block was not written with ECC, skip ECC */
+ if (oob_config.eccvalid_pos != -1 &&
+ (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) {
+
+ nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]);
+ switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) {
+ case -1:
+ printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);
+ ecc_failed++;
+ break;
+ case 1:
+ case 2: /* transfer ECC corrected data to cache */
+ if (nand->data_cache)
+ memcpy (nand->data_cache, nand->data_buf, 256);
+ break;
+ }
+ }
+
+ if (oob_config.eccvalid_pos != -1 &&
+ nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) {
+
+ nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]);
+ switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) {
+ case -1:
+ printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);
+ ecc_failed++;
+ break;
+ case 1:
+ case 2: /* transfer ECC corrected data to cache */
+ if (nand->data_cache)
+ memcpy (&nand->data_cache[256], &nand->data_buf[256], 256);
+ break;
+ }
+ }
+readdata:
+ /* Read the data from ECC data buffer into return buffer */
+ data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf;
+ data_poi += col;
+ if ((*retlen + (nand->oobblock - col)) >= len) {
+ memcpy (buf + *retlen, data_poi, len - *retlen);
+ *retlen = len;
+ } else {
+ memcpy (buf + *retlen, data_poi, nand->oobblock - col);
+ *retlen += nand->oobblock - col;
+ }
+ /* Set cache page address, invalidate, if ecc_failed */
+ nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1;
+
+ ecc_status += ecc_failed;
+ ecc_failed = 0;
+
+#else
+ /* Send the read command */
+ NanD_Command(nand, NAND_CMD_READ0);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ /* Read the data directly into the return buffer */
+ if ((*retlen + (nand->oobblock - col)) >= len) {
+ NanD_ReadBuf(nand, buf + *retlen, len - *retlen);
+ *retlen = len;
+ /* We're done */
+ continue;
+ } else {
+ NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col);
+ *retlen += nand->oobblock - col;
+ }
+#endif
+ /* For subsequent reads align to page boundary. */
+ col = 0;
+ /* Increment page address */
+ page++;
+ }
+
+ /* De-select the NAND device */
+ NAND_DISABLE_CE(nand); /* set pin high */
+
+ /*
+ * Return success, if no ECC failures, else -EIO
+ * fs driver will take care of that, because
+ * retlen == desired len and result == -EIO
+ */
+ return ecc_status ? -1 : 0;
+}
+
+/*
+ * Nand_page_program function is used for write and writev !
+ */
+static int nand_write_page (struct nand_chip *nand,
+ int page, int col, int last, u_char * ecc_code)
+{
+
+ int i;
+ unsigned long nandptr = nand->IO_ADDR;
+
+#ifdef CONFIG_MTD_NAND_ECC
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+ int ecc_bytes = (nand->oobblock == 512) ? 6 : 3;
+#endif
+#endif
+ /* pad oob area */
+ for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++)
+ nand->data_buf[i] = 0xff;
+
+#ifdef CONFIG_MTD_NAND_ECC
+ /* Zero out the ECC array */
+ for (i = 0; i < 6; i++)
+ ecc_code[i] = 0x00;
+
+ /* Read back previous written data, if col > 0 */
+ if (col) {
+ NanD_Command (nand, NAND_CMD_READ0);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ if (nand->bus16) {
+ u16 val;
+
+ for (i = 0; i < col; i += 2) {
+ val = READ_NAND (nandptr);
+ nand->data_buf[i] = val & 0xff;
+ nand->data_buf[i + 1] = val >> 8;
+ }
+ } else {
+ for (i = 0; i < col; i++)
+ nand->data_buf[i] = READ_NAND (nandptr);
+ }
+ }
+
+ /* Calculate and write the ECC if we have enough data */
+ if ((col < nand->eccsize) && (last >= nand->eccsize)) {
+ nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0]));
+ for (i = 0; i < 3; i++) {
+ nand->data_buf[(nand->oobblock +
+ oob_config.ecc_pos[i])] = ecc_code[i];
+ }
+ if (oob_config.eccvalid_pos != -1) {
+ nand->data_buf[nand->oobblock +
+ oob_config.eccvalid_pos] = 0xf0;
+ }
+ }
+
+ /* Calculate and write the second ECC if we have enough data */
+ if ((nand->oobblock == 512) && (last == nand->oobblock)) {
+ nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3]));
+ for (i = 3; i < 6; i++) {
+ nand->data_buf[(nand->oobblock +
+ oob_config.ecc_pos[i])] = ecc_code[i];
+ }
+ if (oob_config.eccvalid_pos != -1) {
+ nand->data_buf[nand->oobblock +
+ oob_config.eccvalid_pos] &= 0x0f;
+ }
+ }
+#endif
+ /* Prepad for partial page programming !!! */
+ for (i = 0; i < col; i++)
+ nand->data_buf[i] = 0xff;
+
+ /* Postpad for partial page programming !!! oob is already padded */
+ for (i = last; i < nand->oobblock; i++)
+ nand->data_buf[i] = 0xff;
+
+ /* Send command to begin auto page programming */
+ NanD_Command (nand, NAND_CMD_READ0);
+ NanD_Command (nand, NAND_CMD_SEQIN);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ /* Write out complete page of data */
+ if (nand->bus16) {
+ for (i = 0; i < (nand->oobblock + nand->oobsize); i += 2) {
+ WRITE_NAND (nand->data_buf[i] +
+ (nand->data_buf[i + 1] << 8),
+ nand->IO_ADDR);
+ }
+ } else {
+ for (i = 0; i < (nand->oobblock + nand->oobsize); i++)
+ WRITE_NAND (nand->data_buf[i], nand->IO_ADDR);
+ }
+
+ /* Send command to actually program the data */
+ NanD_Command (nand, NAND_CMD_PAGEPROG);
+ NanD_Command (nand, NAND_CMD_STATUS);
+#ifdef NAND_NO_RB
+ {
+ u_char ret_val;
+
+ do {
+ ret_val = READ_NAND (nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ /* See if device thinks it succeeded */
+ if (READ_NAND (nand->IO_ADDR) & 0x01) {
+ printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__,
+ page);
+ return -1;
+ }
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+ /*
+ * The NAND device assumes that it is always writing to
+ * a cleanly erased page. Hence, it performs its internal
+ * write verification only on bits that transitioned from
+ * 1 to 0. The device does NOT verify the whole page on a
+ * byte by byte basis. It is possible that the page was
+ * not completely erased or the page is becoming unusable
+ * due to wear. The read with ECC would catch the error
+ * later when the ECC page check fails, but we would rather
+ * catch it early in the page write stage. Better to write
+ * no data than invalid data.
+ */
+
+ /* Send command to read back the page */
+ if (col < nand->eccsize)
+ NanD_Command (nand, NAND_CMD_READ0);
+ else
+ NanD_Command (nand, NAND_CMD_READ1);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ /* Loop through and verify the data */
+ if (nand->bus16) {
+ for (i = col; i < last; i = +2) {
+ if ((nand->data_buf[i] +
+ (nand->data_buf[i + 1] << 8)) != READ_NAND (nand->IO_ADDR)) {
+ printf ("%s: Failed write verify, page 0x%08x ",
+ __FUNCTION__, page);
+ return -1;
+ }
+ }
+ } else {
+ for (i = col; i < last; i++) {
+ if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) {
+ printf ("%s: Failed write verify, page 0x%08x ",
+ __FUNCTION__, page);
+ return -1;
+ }
+ }
+ }
+
+#ifdef CONFIG_MTD_NAND_ECC
+ /*
+ * We also want to check that the ECC bytes wrote
+ * correctly for the same reasons stated above.
+ */
+ NanD_Command (nand, NAND_CMD_READOOB);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+ if (nand->bus16) {
+ for (i = 0; i < nand->oobsize; i += 2) {
+ u16 val;
+
+ val = READ_NAND (nand->IO_ADDR);
+ nand->data_buf[i] = val & 0xff;
+ nand->data_buf[i + 1] = val >> 8;
+ }
+ } else {
+ for (i = 0; i < nand->oobsize; i++) {
+ nand->data_buf[i] = READ_NAND (nand->IO_ADDR);
+ }
+ }
+ for (i = 0; i < ecc_bytes; i++) {
+ if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) {
+ printf ("%s: Failed ECC write "
+ "verify, page 0x%08x, "
+ "%6i bytes were succesful\n",
+ __FUNCTION__, page, i);
+ return -1;
+ }
+ }
+#endif /* CONFIG_MTD_NAND_ECC */
+#endif /* CONFIG_MTD_NAND_VERIFY_WRITE */
+ return 0;
+}
+
+static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
+ size_t * retlen, const u_char * buf, u_char * ecc_code)
+{
+ int i, page, col, cnt, ret = 0;
+
+ /* Do not allow write past end of device */
+ if ((to + len) > nand->totlen) {
+ printf ("%s: Attempt to write past end of page\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* Shift to get page */
+ page = ((int) to) >> nand->page_shift;
+
+ /* Get the starting column */
+ col = to & (nand->oobblock - 1);
+
+ /* Initialize return length value */
+ *retlen = 0;
+
+ /* Select the NAND device */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,0);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_OFF();
+#endif
+
+ NAND_ENABLE_CE(nand); /* set pin low */
+
+ /* Check the WP bit */
+ NanD_Command(nand, NAND_CMD_STATUS);
+ if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
+ printf ("%s: Device is write protected!!!\n", __FUNCTION__);
+ ret = -1;
+ goto out;
+ }
+
+ /* Loop until all data is written */
+ while (*retlen < len) {
+ /* Invalidate cache, if we write to this page */
+ if (nand->cache_page == page)
+ nand->cache_page = -1;
+
+ /* Write data into buffer */
+ if ((col + len) >= nand->oobblock) {
+ for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) {
+ nand->data_buf[i] = buf[(*retlen + cnt)];
+ }
+ } else {
+ for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) {
+ nand->data_buf[i] = buf[(*retlen + cnt)];
+ }
+ }
+ /* We use the same function for write and writev !) */
+ ret = nand_write_page (nand, page, col, i, ecc_code);
+ if (ret)
+ goto out;
+
+ /* Next data start at page boundary */
+ col = 0;
+
+ /* Update written bytes count */
+ *retlen += cnt;
+
+ /* Increment page address */
+ page++;
+ }
+
+ /* Return happy */
+ *retlen = len;
+
+out:
+ /* De-select the NAND device */
+ NAND_DISABLE_CE(nand); /* set pin high */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,1);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_ON();
+#endif
+
+ return ret;
+}
+
+/* read from the 16 bytes of oob data that correspond to a 512 byte
+ * page or 2 256-byte pages.
+ */
+int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, u_char * buf)
+{
+ int len256 = 0;
+ struct Nand *mychip;
+ int ret = 0;
+
+ mychip = &nand->chips[ofs >> nand->chipshift];
+
+ /* update address for 2M x 8bit devices. OOB starts on the second */
+ /* page to maintain compatibility with nand_read_ecc. */
+ if (nand->page256) {
+ if (!(ofs & 0x8))
+ ofs += 0x100;
+ else
+ ofs -= 0x8;
+ }
+
+ NAND_ENABLE_CE(nand); /* set pin low */
+ NanD_Command(nand, NAND_CMD_READOOB);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ ((ofs >> nand->page_shift) << nand->page_shift) +
+ ((ofs & (nand->oobblock - 1)) >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+ }
+
+ /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+ /* Note: datasheet says it should automaticaly wrap to the */
+ /* next OOB block, but it didn't work here. mf. */
+ if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
+ len256 = (ofs | 0x7) + 1 - ofs;
+ NanD_ReadBuf(nand, buf, len256);
+
+ NanD_Command(nand, NAND_CMD_READOOB);
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
+ }
+
+ NanD_ReadBuf(nand, &buf[len256], len - len256);
+
+ *retlen = len;
+ /* Reading the full OOB data drops us off of the end of the page,
+ * causing the flash device to go into busy mode, so we need
+ * to wait until ready 11.4.1 and Toshiba TC58256FT nands */
+
+ ret = NanD_WaitReady(nand, 1);
+ NAND_DISABLE_CE(nand); /* set pin high */
+
+ return ret;
+
+}
+
+/* write to the 16 bytes of oob data that correspond to a 512 byte
+ * page or 2 256-byte pages.
+ */
+int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, const u_char * buf)
+{
+ int len256 = 0;
+ int i;
+ unsigned long nandptr = nand->IO_ADDR;
+
+#ifdef PSYCHO_DEBUG
+ printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",
+ (long)ofs, len, buf[0], buf[1], buf[2], buf[3],
+ buf[8], buf[9], buf[14],buf[15]);
+#endif
+
+ NAND_ENABLE_CE(nand); /* set pin low to enable chip */
+
+ /* Reset the chip */
+ NanD_Command(nand, NAND_CMD_RESET);
+
+ /* issue the Read2 command to set the pointer to the Spare Data Area. */
+ NanD_Command(nand, NAND_CMD_READOOB);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ ((ofs >> nand->page_shift) << nand->page_shift) +
+ ((ofs & (nand->oobblock - 1)) >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+ }
+
+ /* update address for 2M x 8bit devices. OOB starts on the second */
+ /* page to maintain compatibility with nand_read_ecc. */
+ if (nand->page256) {
+ if (!(ofs & 0x8))
+ ofs += 0x100;
+ else
+ ofs -= 0x8;
+ }
+
+ /* issue the Serial Data In command to initial the Page Program process */
+ NanD_Command(nand, NAND_CMD_SEQIN);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ ((ofs >> nand->page_shift) << nand->page_shift) +
+ ((ofs & (nand->oobblock - 1)) >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+ }
+
+ /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+ /* Note: datasheet says it should automaticaly wrap to the */
+ /* next OOB block, but it didn't work here. mf. */
+ if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
+ len256 = (ofs | 0x7) + 1 - ofs;
+ for (i = 0; i < len256; i++)
+ WRITE_NAND(buf[i], nandptr);
+
+ NanD_Command(nand, NAND_CMD_PAGEPROG);
+ NanD_Command(nand, NAND_CMD_STATUS);
+#ifdef NAND_NO_RB
+ { u_char ret_val;
+ do {
+ ret_val = READ_NAND(nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ if (READ_NAND(nandptr) & 1) {
+ puts ("Error programming oob data\n");
+ /* There was an error */
+ NAND_DISABLE_CE(nand); /* set pin high */
+ *retlen = 0;
+ return -1;
+ }
+ NanD_Command(nand, NAND_CMD_SEQIN);
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
+ }
+
+ if (nand->bus16) {
+ for (i = len256; i < len; i += 2) {
+ WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr);
+ }
+ } else {
+ for (i = len256; i < len; i++)
+ WRITE_NAND(buf[i], nandptr);
+ }
+
+ NanD_Command(nand, NAND_CMD_PAGEPROG);
+ NanD_Command(nand, NAND_CMD_STATUS);
+#ifdef NAND_NO_RB
+ { u_char ret_val;
+ do {
+ ret_val = READ_NAND(nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ if (READ_NAND(nandptr) & 1) {
+ puts ("Error programming oob data\n");
+ /* There was an error */
+ NAND_DISABLE_CE(nand); /* set pin high */
+ *retlen = 0;
+ return -1;
+ }
+
+ NAND_DISABLE_CE(nand); /* set pin high */
+ *retlen = len;
+ return 0;
+
+}
+
+int nand_legacy_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean)
+{
+ /* This is defined as a structure so it will work on any system
+ * using native endian jffs2 (the default).
+ */
+ static struct jffs2_unknown_node clean_marker = {
+ JFFS2_MAGIC_BITMASK,
+ JFFS2_NODETYPE_CLEANMARKER,
+ 8 /* 8 bytes in this node */
+ };
+ unsigned long nandptr;
+ struct Nand *mychip;
+ int ret = 0;
+
+ if (ofs & (nand->erasesize-1) || len & (nand->erasesize-1)) {
+ printf ("Offset and size must be sector aligned, erasesize = %d\n",
+ (int) nand->erasesize);
+ return -1;
+ }
+
+ nandptr = nand->IO_ADDR;
+
+ /* Select the NAND device */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,0);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_OFF();
+#endif
+ NAND_ENABLE_CE(nand); /* set pin low */
+
+ /* Check the WP bit */
+ NanD_Command(nand, NAND_CMD_STATUS);
+ if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
+ printf ("nand_write_ecc: Device is write protected!!!\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* Check the WP bit */
+ NanD_Command(nand, NAND_CMD_STATUS);
+ if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {
+ printf ("%s: Device is write protected!!!\n", __FUNCTION__);
+ ret = -1;
+ goto out;
+ }
+
+ /* FIXME: Do nand in the background. Use timers or schedule_task() */
+ while(len) {
+ /*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/
+ mychip = &nand->chips[ofs >> nand->chipshift];
+
+ /* always check for bad block first, genuine bad blocks
+ * should _never_ be erased.
+ */
+ if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) {
+ /* Select the NAND device */
+ NAND_ENABLE_CE(nand); /* set pin low */
+
+ NanD_Command(nand, NAND_CMD_ERASE1);
+ NanD_Address(nand, ADDR_PAGE, ofs);
+ NanD_Command(nand, NAND_CMD_ERASE2);
+
+ NanD_Command(nand, NAND_CMD_STATUS);
+
+#ifdef NAND_NO_RB
+ { u_char ret_val;
+ do {
+ ret_val = READ_NAND(nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ if (READ_NAND(nandptr) & 1) {
+ printf ("%s: Error erasing at 0x%lx\n",
+ __FUNCTION__, (long)ofs);
+ /* There was an error */
+ ret = -1;
+ goto out;
+ }
+ if (clean) {
+ int n; /* return value not used */
+ int p, l;
+
+ /* clean marker position and size depend
+ * on the page size, since 256 byte pages
+ * only have 8 bytes of oob data
+ */
+ if (nand->page256) {
+ p = NAND_JFFS2_OOB8_FSDAPOS;
+ l = NAND_JFFS2_OOB8_FSDALEN;
+ } else {
+ p = NAND_JFFS2_OOB16_FSDAPOS;
+ l = NAND_JFFS2_OOB16_FSDALEN;
+ }
+
+ ret = nand_write_oob(nand, ofs + p, l, (size_t *)&n,
+ (u_char *)&clean_marker);
+ /* quit here if write failed */
+ if (ret)
+ goto out;
+ }
+ }
+ ofs += nand->erasesize;
+ len -= nand->erasesize;
+ }
+
+out:
+ /* De-select the NAND device */
+ NAND_DISABLE_CE(nand); /* set pin high */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,1);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_ON();
+#endif
+
+ return ret;
+}
+
+
+static inline int nandcheck(unsigned long potential, unsigned long physadr)
+{
+ return 0;
+}
+
+unsigned long nand_probe(unsigned long physadr)
+{
+ struct nand_chip *nand = NULL;
+ int i = 0, ChipID = 1;
+
+#ifdef CONFIG_MTD_NAND_ECC_JFFS2
+ oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0;
+ oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1;
+ oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2;
+ oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3;
+ oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4;
+ oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5;
+ oob_config.eccvalid_pos = 4;
+#else
+ oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0;
+ oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1;
+ oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2;
+ oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3;
+ oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4;
+ oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5;
+ oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS;
+#endif
+ oob_config.badblock_pos = 5;
+
+ for (i=0; i<CFG_MAX_NAND_DEVICE; i++) {
+ if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) {
+ nand = &nand_dev_desc[i];
+ break;
+ }
+ }
+ if (!nand)
+ return (0);
+
+ memset((char *)nand, 0, sizeof(struct nand_chip));
+
+ nand->IO_ADDR = physadr;
+ nand->cache_page = -1; /* init the cache page */
+ NanD_ScanChips(nand);
+
+ if (nand->totlen == 0) {
+ /* no chips found, clean up and quit */
+ memset((char *)nand, 0, sizeof(struct nand_chip));
+ nand->ChipID = NAND_ChipID_UNKNOWN;
+ return (0);
+ }
+
+ nand->ChipID = ChipID;
+ if (curr_device == -1)
+ curr_device = i;
+
+ nand->data_buf = malloc (nand->oobblock + nand->oobsize);
+ if (!nand->data_buf) {
+ puts ("Cannot allocate memory for data structures.\n");
+ return (0);
+ }
+
+ return (nand->totlen);
+}
+
+#ifdef CONFIG_MTD_NAND_ECC
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const u_char nand_ecc_precalc_table[] = {
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+
+/*
+ * Creates non-inverted ECC code from line parity
+ */
+static void nand_trans_result(u_char reg2, u_char reg3,
+ u_char *ecc_code)
+{
+ u_char a, b, i, tmp1, tmp2;
+
+ /* Initialize variables */
+ a = b = 0x80;
+ tmp1 = tmp2 = 0;
+
+ /* Calculate first ECC byte */
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Calculate second ECC byte */
+ b = 0x80;
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Store two of the ECC bytes */
+ ecc_code[0] = tmp1;
+ ecc_code[1] = tmp2;
+}
+
+/*
+ * Calculate 3 byte ECC code for 256 byte block
+ */
+static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
+{
+ u_char idx, reg1, reg3;
+ int j;
+
+ /* Initialize variables */
+ reg1 = reg3 = 0;
+ ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+
+ /* Build up column parity */
+ for(j = 0; j < 256; j++) {
+
+ /* Get CP0 - CP5 from table */
+ idx = nand_ecc_precalc_table[dat[j]];
+ reg1 ^= idx;
+
+ /* All bit XOR = 1 ? */
+ if (idx & 0x40) {
+ reg3 ^= (u_char) j;
+ }
+ }
+
+ /* Create non-inverted ECC code from line parity */
+ nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
+
+ /* Calculate final ECC code */
+ ecc_code[0] = ~ecc_code[0];
+ ecc_code[1] = ~ecc_code[1];
+ ecc_code[2] = ((~reg1) << 2) | 0x03;
+}
+
+/*
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+ u_char a, b, c, d1, d2, d3, add, bit, i;
+
+ /* Do error detection */
+ d1 = calc_ecc[0] ^ read_ecc[0];
+ d2 = calc_ecc[1] ^ read_ecc[1];
+ d3 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((d1 | d2 | d3) == 0) {
+ /* No errors */
+ return 0;
+ } else {
+ a = (d1 ^ (d1 >> 1)) & 0x55;
+ b = (d2 ^ (d2 >> 1)) & 0x55;
+ c = (d3 ^ (d3 >> 1)) & 0x54;
+
+ /* Found and will correct single bit error in the data */
+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+ c = 0x80;
+ add = 0;
+ a = 0x80;
+ for (i=0; i<4; i++) {
+ if (d1 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ c = 0x80;
+ for (i=0; i<4; i++) {
+ if (d2 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ bit = 0;
+ b = 0x04;
+ c = 0x80;
+ for (i=0; i<3; i++) {
+ if (d3 & c)
+ bit |= b;
+ c >>= 2;
+ b >>= 1;
+ }
+ b = 0x01;
+ a = dat[add];
+ a ^= (b << bit);
+ dat[add] = a;
+ return 1;
+ }
+ else {
+ i = 0;
+ while (d1) {
+ if (d1 & 0x01)
+ ++i;
+ d1 >>= 1;
+ }
+ while (d2) {
+ if (d2 & 0x01)
+ ++i;
+ d2 >>= 1;
+ }
+ while (d3) {
+ if (d3 & 0x01)
+ ++i;
+ d3 >>= 1;
+ }
+ if (i == 1) {
+ /* ECC Code Error Correction */
+ read_ecc[0] = calc_ecc[0];
+ read_ecc[1] = calc_ecc[1];
+ read_ecc[2] = calc_ecc[2];
+ return 2;
+ }
+ else {
+ /* Uncorrectable Error */
+ return -1;
+ }
+ }
+ }
+
+ /* Should never happen */
+ return -1;
+}
+
+#endif
+
+#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
/* keeps pointer to currentlu processed partition */
static struct part_info *current_part;
-#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE)
+#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND)
+#include <nand.h>
/*
* Support for jffs2 on top of NAND-flash
*
*
*/
-/* this one defined in cmd_nand.c */
-int read_jffs2_nand(size_t start, size_t len,
- size_t * retlen, u_char * buf, int nanddev);
+/* info for NAND chips, defined in drivers/nand/nand.c */
+extern nand_info_t nand_info[];
#define NAND_PAGE_SIZE 512
#define NAND_PAGE_SHIFT 9
#endif
#define NAND_CACHE_SIZE (NAND_CACHE_PAGES*NAND_PAGE_SIZE)
+#ifdef CFG_NAND_LEGACY
static u8* nand_cache = NULL;
static u32 nand_cache_off = (u32)-1;
{
struct mtdids *id = current_part->dev->id;
u32 bytes_read = 0;
- size_t retlen;
+ ulong retlen;
int cpy_bytes;
while (bytes_read < size) {
return -1;
}
}
- if (read_jffs2_nand(nand_cache_off, NAND_CACHE_SIZE,
- &retlen, nand_cache, id->num) < 0 ||
+
+ retlen = NAND_CACHE_SIZE;
+ if (nand_read(&nand_info[id->num], nand_cache_off,
+ &retlen, nand_cache) != 0 ||
retlen != NAND_CACHE_SIZE) {
printf("read_nand_cached: error reading nand off %#x size %d bytes\n",
nand_cache_off, NAND_CACHE_SIZE);
{
free(buf);
}
+#endif /* CFG_NAND_LEGACY */
#endif /* #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) */
return get_fl_mem_nor(off);
#endif
-#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE)
+#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
if (id->type == MTD_DEV_TYPE_NAND)
return get_fl_mem_nand(off, size, ext_buf);
#endif
return get_node_mem_nor(off);
#endif
-#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE)
+#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
if (id->type == MTD_DEV_TYPE_NAND)
return get_node_mem_nand(off);
#endif
static inline void put_fl_mem(void *buf)
{
-#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE)
+#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
struct mtdids *id = current_part->dev->id;
if (id->type == MTD_DEV_TYPE_NAND)
#include <common.h>
-#if defined(CONFIG_NEW_NAND_CODE) && (CONFIG_COMMANDS & CFG_CMD_JFFS2)
+#if !defined(CFG_NAND_LEGACY) && (CONFIG_COMMANDS & CFG_CMD_JFFS2)
#include <malloc.h>
#include <linux/stat.h>
* NAND-FLASH stuff
*-----------------------------------------------------------------------
*/
+
+#define CFG_NAND_LEGACY
+
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
CFG_CMD_DOC | \
CFG_CMD_ELF | \
0 )
+
+/* CFG_CMD_DOC required legacy NAND support */
+#define CFG_NAND_LEGACY
+
#if 0
#define CONFIG_COMMANDS (CONFIG_CMD_DFL | CFG_CMD_DHCP | \
CFG_CMD_PCI | CFG_CMD_DOC | CFG_CMD_DATE)
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
#undef CONFIG_WATCHDOG /* watchdog disabled */
#define CONFIG_SDRAM_BANK0 1 /* init onboard SDRAM bank 0 */
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
#undef CONFIG_WATCHDOG /* watchdog disabled */
#define CONFIG_SDRAM_BANK0 1 /* init onboard SDRAM bank 0 */
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
#undef CONFIG_WATCHDOG /* watchdog disabled */
#define CONFIG_SDRAM_BANK0 1 /* init onboard SDRAM bank 0 */
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
+
#undef CONFIG_WATCHDOG /* watchdog disabled */
#define CONFIG_SDRAM_BANK0 1 /* init onboard SDRAM bank 0 */
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
#undef CONFIG_WATCHDOG /* watchdog disabled */
#define CONFIG_SDRAM_BANK0 1 /* init onboard SDRAM bank 0 */
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
/*
* Miscellaneous configurable options
*/
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
/*
* Miscellaneous configurable options
*/
*/
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
/*
* Verbose help from command monitor.
*/
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
#undef CONFIG_BZIP2 /* include support for bzip2 compressed images */
#undef CONFIG_WATCHDOG /* watchdog disabled */
* NAND-FLASH stuff
*-----------------------------------------------------------------------
*/
+#define CFG_NAND_LEGACY
+
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
#define CFG_HUSH_PARSER
#define CFG_PROMPT_HUSH_PS2 "> "
/**************************************************************
/****************************************************************/
/* NAND */
+#define CFG_NAND_LEGACY
#define CFG_NAND_BASE NAND_BASE
#define CONFIG_MTD_NAND_ECC_JFFS2
#define CONFIG_MTD_NAND_VERIFY_WRITE
/****************************************************************/
/* NAND */
+#define CFG_NAND_LEGACY
#define CFG_NAND_BASE NAND_BASE
#define CONFIG_MTD_NAND_ECC_JFFS2
#define CONFIG_MTD_NAND_VERIFY_WRITE
/*****************************************************************************/
+#define CFG_NAND_LEGACY
+
#if defined(CONFIG_NETVIA_VERSION) && CONFIG_NETVIA_VERSION >= 2
/* NAND */
*/
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
/*
* Miscellaneous configurable options
*/
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
/*
* Miscellaneous configurable options
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
#define CFG_HUSH_PARSER
#define CFG_PROMPT_HUSH_PS2 "> "
/**************************************************************
* NAND-FLASH stuff
*-----------------------------------------------------------------------
*/
+#define CFG_NAND_LEGACY
+
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
#define ADD_DOC_CMD 0
#else
#define ADD_DOC_CMD CFG_CMD_DOC
+/* DoC requires legacy NAND for now */
+#define CFG_NAND_LEGACY
#endif
/*
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
+
/*
* Disk-On-Chip configuration
*/
/*
* Disk-On-Chip configuration
*/
+#define CFG_NAND_LEGACY
#define CFG_DOC_SHORT_TIMEOUT
#define CFG_MAX_DOC_DEVICE 1 /* Max number of DOC devices */
* NAND-FLASH stuff
*-----------------------------------------------------------------------
*/
+/*
+ * nand device 1 on dave (PPChameleonEVB) needs more time,
+ * so we just introduce additional wait in nand_wait(),
+ * effectively for both devices.
+ */
+#define PPCHAMELON_NAND_TIMER_HACK
-/* Use the new NAND code. (BOARDLIBS = drivers/nand/libnand.a required) */
-#define CONFIG_NEW_NAND_CODE
#define CFG_NAND0_BASE 0xFF400000
#define CFG_NAND1_BASE 0xFF000000
#define CFG_NAND_BASE_LIST { CFG_NAND0_BASE, CFG_NAND1_BASE }
#define NAND_BIG_DELAY_US 25
#define CFG_MAX_NAND_DEVICE 2 /* Max number of NAND devices */
-#define SECTORSIZE 512
-#define NAND_NO_RB
-#define ADDR_COLUMN 1
-#define ADDR_PAGE 2
-#define ADDR_COLUMN_PAGE 3
-
-#define NAND_ChipID_UNKNOWN 0x00
-#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
#define CFG_NAND0_CE (0x80000000 >> 1) /* our CE is GPIO1 */
+#define CFG_NAND0_RDY (0x80000000 >> 4) /* our RDY is GPIO4 */
#define CFG_NAND0_CLE (0x80000000 >> 2) /* our CLE is GPIO2 */
#define CFG_NAND0_ALE (0x80000000 >> 3) /* our ALE is GPIO3 */
-#define CFG_NAND0_RDY (0x80000000 >> 4) /* our RDY is GPIO4 */
#define CFG_NAND1_CE (0x80000000 >> 14) /* our CE is GPIO14 */
+#define CFG_NAND1_RDY (0x80000000 >> 31) /* our RDY is GPIO31 */
#define CFG_NAND1_CLE (0x80000000 >> 15) /* our CLE is GPIO15 */
#define CFG_NAND1_ALE (0x80000000 >> 16) /* our ALE is GPIO16 */
-#define CFG_NAND1_RDY (0x80000000 >> 31) /* our RDY is GPIO31 */
-#ifdef CONFIG_NEW_NAND_CODE
#define MACRO_NAND_DISABLE_CE(nandptr) do \
{ \
switch((unsigned long)nandptr) \
break; \
} \
} while(0)
-#else
-#define NAND_DISABLE_CE(nand) do \
-{ \
- switch((unsigned long)(((struct nand_chip *)nand)->IO_ADDR)) \
- { \
- case CFG_NAND0_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) | CFG_NAND0_CE); \
- break; \
- case CFG_NAND1_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) | CFG_NAND1_CE); \
- break; \
- } \
-} while(0)
-#define NAND_ENABLE_CE(nand) do \
-{ \
- switch((unsigned long)(((struct nand_chip *)nand)->IO_ADDR)) \
- { \
- case CFG_NAND0_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CFG_NAND0_CE); \
- break; \
- case CFG_NAND1_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CFG_NAND1_CE); \
- break; \
- } \
-} while(0)
+#if 0
+#define SECTORSIZE 512
+#define NAND_NO_RB
-#define NAND_CTL_CLRALE(nandptr) do \
-{ \
- switch((unsigned long)nandptr) \
- { \
- case CFG_NAND0_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CFG_NAND0_ALE); \
- break; \
- case CFG_NAND1_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CFG_NAND1_ALE); \
- break; \
- } \
-} while(0)
+#define ADDR_COLUMN 1
+#define ADDR_PAGE 2
+#define ADDR_COLUMN_PAGE 3
-#define NAND_CTL_SETALE(nandptr) do \
-{ \
- switch((unsigned long)nandptr) \
- { \
- case CFG_NAND0_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) | CFG_NAND0_ALE); \
- break; \
- case CFG_NAND1_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) | CFG_NAND1_ALE); \
- break; \
- } \
-} while(0)
+#define NAND_ChipID_UNKNOWN 0x00
+#define NAND_MAX_FLOORS 1
-#define NAND_CTL_CLRCLE(nandptr) do \
-{ \
- switch((unsigned long)nandptr) \
- { \
- case CFG_NAND0_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CFG_NAND0_CLE); \
- break; \
- case CFG_NAND1_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) & ~CFG_NAND1_CLE); \
- break; \
- } \
-} while(0)
-#define NAND_CTL_SETCLE(nandptr) do { \
- switch((unsigned long)nandptr) { \
- case CFG_NAND0_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) | CFG_NAND0_CLE); \
- break; \
- case CFG_NAND1_BASE: \
- out32(GPIO0_OR, in32(GPIO0_OR) | CFG_NAND1_CLE); \
- break; \
- } \
-} while(0)
-#endif /* !CONFIG_NEW_NAND_CODE */
#ifdef NAND_NO_RB
/* constant delay (see also tR in the datasheet) */
#define WRITE_NAND_ADDRESS(d, adr) do{ *(volatile __u8 *)((unsigned long)adr) = (__u8)(d); } while(0)
#define WRITE_NAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr) = (__u8)d; } while(0)
#define READ_NAND(adr) ((volatile unsigned char)(*(volatile __u8 *)(unsigned long)adr))
-
+#endif
/*-----------------------------------------------------------------------
* PCI stuff
*-----------------------------------------------------------------------
/************************************************************
* Disk-On-Chip configuration
************************************************************/
+#define CFG_NAND_LEGACY
+
#define CFG_MAX_DOC_DEVICE 1 /* Max number of DOC devices */
#define CFG_DOC_SHORT_TIMEOUT
#define CFG_DOC_SUPPORT_2000
*/
/* NAND flash support */
+#define CFG_NAND_LEGACY
#define CONFIG_MTD_NAND_ECC_JFFS2
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
* NAND-FLASH stuff
*-----------------------------------------------------------------------
*/
+#define CFG_NAND_LEGACY
+
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
* NAND-FLASH stuff
*-----------------------------------------------------------------------
*/
+#define CFG_NAND_LEGACY
+
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
* 2nd ethernet port you have to "undef" the following define.
*/
#define CONFIG_BAMBOO_NAND 1 /* enable nand flash support */
+#define CFG_NAND_LEGACY
/*-----------------------------------------------------------------------
* Base addresses -- Note these are effective addresses where the
* NAND flash
*/
#define CFG_MAX_NAND_DEVICE 1
+#define NAND_MAX_CHIPS 1
#define CFG_NAND_BASE 0x04000000 + (2 << 23)
-#define CONFIG_NEW_NAND_CODE
/*
* JFFS2 partitions (mtdparts command line support)
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
+#define CFG_NAND_LEGACY
/*
* Miscellaneous configurable options
* linux/include/linux/mtd/nand.h
*
* Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
- * Steven J. Hill <sjhill@cotw.com>
- * Thomas Gleixner <gleixner@autronix.de>
+ * Steven J. Hill <sjhill@realitydiluted.com>
+ * Thomas Gleixner <tglx@linutronix.de>
*
- * $Id: nand.h,v 1.7 2003/07/24 23:30:46 a0384864 Exp $
+ * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* command delay times for different chips
* 04-28-2002 TG OOB config defines moved from nand.c to avoid duplicate
* defines in jffs2/wbuf.c
+ * 08-07-2002 TG forced bad block location to byte 5 of OOB, even if
+ * CONFIG_MTD_NAND_ECC_JFFS2 is not set
+ * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC
+ *
+ * 08-29-2002 tglx nand_chip structure: data_poi for selecting
+ * internal / fs-driver buffer
+ * support for 6byte/512byte hardware ECC
+ * read_ecc, write_ecc extended for different oob-layout
+ * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB,
+ * NAND_YAFFS_OOB
+ * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL
+ * Split manufacturer and device ID structures
+ *
+ * 02-08-2004 tglx added option field to nand structure for chip anomalities
+ * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id
+ * update of nand_chip structure description
*/
#ifndef __LINUX_MTD_NAND_H
#define __LINUX_MTD_NAND_H
-#ifdef CONFIG_NEW_NAND_CODE
-#include "nand_new.h"
-#else
+#include <linux/mtd/compat.h>
+#include <linux/mtd/mtd.h>
+
+struct mtd_info;
+/* Scan and identify a NAND device */
+extern int nand_scan (struct mtd_info *mtd, int max_chips);
+/* Free resources held by the NAND device */
+extern void nand_release (struct mtd_info *mtd);
+
+/* Read raw data from the device without ECC */
+extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen);
+
+
+
+/* This constant declares the max. oobsize / page, which
+ * is supported now. If you add a chip with bigger oobsize/page
+ * adjust this accordingly.
+ */
+#define NAND_MAX_OOBSIZE 64
+
+/*
+ * Constants for hardware specific CLE/ALE/NCE function
+*/
+/* Select the chip by setting nCE to low */
+#define NAND_CTL_SETNCE 1
+/* Deselect the chip by setting nCE to high */
+#define NAND_CTL_CLRNCE 2
+/* Select the command latch by setting CLE to high */
+#define NAND_CTL_SETCLE 3
+/* Deselect the command latch by setting CLE to low */
+#define NAND_CTL_CLRCLE 4
+/* Select the address latch by setting ALE to high */
+#define NAND_CTL_SETALE 5
+/* Deselect the address latch by setting ALE to low */
+#define NAND_CTL_CLRALE 6
+/* Set write protection by setting WP to high. Not used! */
+#define NAND_CTL_SETWP 7
+/* Clear write protection by setting WP to low. Not used! */
+#define NAND_CTL_CLRWP 8
+
/*
* Standard NAND flash commands
*/
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
+#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
+/* Extended commands for large page devices */
+#define NAND_CMD_READSTART 0x30
+#define NAND_CMD_CACHEDPROG 0x15
+
+/* Status bits */
+#define NAND_STATUS_FAIL 0x01
+#define NAND_STATUS_FAIL_N1 0x02
+#define NAND_STATUS_TRUE_READY 0x20
+#define NAND_STATUS_READY 0x40
+#define NAND_STATUS_WP 0x80
+
+/*
+ * Constants for ECC_MODES
+ */
+
+/* No ECC. Usage is not recommended ! */
+#define NAND_ECC_NONE 0
+/* Software ECC 3 byte ECC per 256 Byte data */
+#define NAND_ECC_SOFT 1
+/* Hardware ECC 3 byte ECC per 256 Byte data */
+#define NAND_ECC_HW3_256 2
+/* Hardware ECC 3 byte ECC per 512 Byte data */
+#define NAND_ECC_HW3_512 3
+/* Hardware ECC 3 byte ECC per 512 Byte data */
+#define NAND_ECC_HW6_512 4
+/* Hardware ECC 8 byte ECC per 512 Byte data */
+#define NAND_ECC_HW8_512 6
+/* Hardware ECC 12 byte ECC per 2048 Byte data */
+#define NAND_ECC_HW12_2048 7
+
/*
+ * Constants for Hardware ECC
+*/
+/* Reset Hardware ECC for read */
+#define NAND_ECC_READ 0
+/* Reset Hardware ECC for write */
+#define NAND_ECC_WRITE 1
+/* Enable Hardware ECC before syndrom is read back from flash */
+#define NAND_ECC_READSYN 2
+
+/* Option constants for bizarre disfunctionality and real
+* features
+*/
+/* Chip can not auto increment pages */
+#define NAND_NO_AUTOINCR 0x00000001
+/* Buswitdh is 16 bit */
+#define NAND_BUSWIDTH_16 0x00000002
+/* Device supports partial programming without padding */
+#define NAND_NO_PADDING 0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG 0x00000008
+/* Chip has copy back function */
+#define NAND_COPYBACK 0x00000010
+/* AND Chip which has 4 banks and a confusing page / block
+ * assignment. See Renesas datasheet for further information */
+#define NAND_IS_AND 0x00000020
+/* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+#define NAND_4PAGE_ARRAY 0x00000040
+
+/* Options valid for Samsung large page devices */
+#define NAND_SAMSUNG_LP_OPTIONS \
+ (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
+
+/* Macros to identify the above */
+#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
+#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
+#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
+#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
+
+/* Mask to zero out the chip options, which come from the id table */
+#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
+
+/* Non chip related options */
+/* Use a flash based bad block table. This option is passed to the
+ * default bad block table function. */
+#define NAND_USE_FLASH_BBT 0x00010000
+/* The hw ecc generator provides a syndrome instead a ecc value on read
+ * This can only work if we have the ecc bytes directly behind the
+ * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
+#define NAND_HWECC_SYNDROME 0x00020000
+
+
+/* Options set by nand scan */
+/* Nand scan has allocated oob_buf */
+#define NAND_OOBBUF_ALLOC 0x40000000
+/* Nand scan has allocated data_buf */
+#define NAND_DATABUF_ALLOC 0x80000000
+
+
+/*
+ * nand_state_t - chip states
* Enumeration for NAND flash chip state
*/
typedef enum {
FL_READING,
FL_WRITING,
FL_ERASING,
- FL_SYNCING
+ FL_SYNCING,
+ FL_CACHEDPRG,
} nand_state_t;
+/* Keep gcc happy */
+struct nand_chip;
-/*
- * NAND Private Flash Chip Data
- *
- * Structure overview:
- *
- * IO_ADDR - address to access the 8 I/O lines of the flash device
- *
- * hwcontrol - hardwarespecific function for accesing control-lines
- *
- * dev_ready - hardwarespecific function for accesing device ready/busy line
- *
- * chip_lock - spinlock used to protect access to this structure
- *
- * wq - wait queue to sleep on if a NAND operation is in progress
- *
- * state - give the current state of the NAND device
- *
- * page_shift - number of address bits in a page (column address bits)
- *
- * data_buf - data buffer passed to/from MTD user modules
- *
- * data_cache - data cache for redundant page access and shadow for
- * ECC failure
- *
- * ecc_code_buf - used only for holding calculated or read ECCs for
- * a page read or written when ECC is in use
- *
- * reserved - padding to make structure fall on word boundary if
- * when ECC is in use
+#if 0
+/**
+ * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
+ * @lock: protection lock
+ * @active: the mtd device which holds the controller currently
*/
-struct Nand {
- char floor, chip;
- unsigned long curadr;
- unsigned char curmode;
- /* Also some erase/write/pipeline info when we get that far */
+struct nand_hw_control {
+ spinlock_t lock;
+ struct nand_chip *active;
};
+#endif
+
+/**
+ * struct nand_chip - NAND Private Flash Chip Data
+ * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
+ * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device
+ * @read_byte: [REPLACEABLE] read one byte from the chip
+ * @write_byte: [REPLACEABLE] write one byte to the chip
+ * @read_word: [REPLACEABLE] read one word from the chip
+ * @write_word: [REPLACEABLE] write one word to the chip
+ * @write_buf: [REPLACEABLE] write data from the buffer to the chip
+ * @read_buf: [REPLACEABLE] read data from the chip into the buffer
+ * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data
+ * @select_chip: [REPLACEABLE] select chip nr
+ * @block_bad: [REPLACEABLE] check, if the block is bad
+ * @block_markbad: [REPLACEABLE] mark the block bad
+ * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines
+ * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
+ * If set to NULL no access to ready/busy is available and the ready/busy information
+ * is read from the chip status register
+ * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
+ * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
+ * @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware
+ * @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
+ * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
+ * be provided if a hardware ECC is available
+ * @erase_cmd: [INTERN] erase command write function, selectable due to AND support
+ * @scan_bbt: [REPLACEABLE] function to scan bad block table
+ * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines
+ * @eccsize: [INTERN] databytes used per ecc-calculation
+ * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
+ * @eccsteps: [INTERN] number of ecc calculation steps per page
+ * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
+ * @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip
+ * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
+ * @state: [INTERN] the current state of the NAND device
+ * @page_shift: [INTERN] number of address bits in a page (column address bits)
+ * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
+ * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
+ * @chip_shift: [INTERN] number of address bits in one chip
+ * @data_buf: [INTERN] internal buffer for one page + oob
+ * @oob_buf: [INTERN] oob buffer for one eraseblock
+ * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized
+ * @data_poi: [INTERN] pointer to a data buffer
+ * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
+ * special functionality. See the defines for further explanation
+ * @badblockpos: [INTERN] position of the bad block marker in the oob area
+ * @numchips: [INTERN] number of physical chips
+ * @chipsize: [INTERN] the size of one chip for multichip arrays
+ * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
+ * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
+ * @autooob: [REPLACEABLE] the default (auto)placement scheme
+ * @bbt: [INTERN] bad block table pointer
+ * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
+ * @bbt_md: [REPLACEABLE] bad block table mirror descriptor
+ * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
+ * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
+ * @priv: [OPTIONAL] pointer to private chip date
+ */
struct nand_chip {
+ void __iomem *IO_ADDR_R;
+ void __iomem *IO_ADDR_W;
+
+ u_char (*read_byte)(struct mtd_info *mtd);
+ void (*write_byte)(struct mtd_info *mtd, u_char byte);
+ u16 (*read_word)(struct mtd_info *mtd);
+ void (*write_word)(struct mtd_info *mtd, u16 word);
+
+ void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
+ void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
+ int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
+ void (*select_chip)(struct mtd_info *mtd, int chip);
+ int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+ int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+ void (*hwcontrol)(struct mtd_info *mtd, int cmd);
+ int (*dev_ready)(struct mtd_info *mtd);
+ void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
+ int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
+ int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
+ int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+ void (*enable_hwecc)(struct mtd_info *mtd, int mode);
+ void (*erase_cmd)(struct mtd_info *mtd, int page);
+ int (*scan_bbt)(struct mtd_info *mtd);
+ int eccmode;
+ int eccsize;
+ int eccbytes;
+ int eccsteps;
+ int chip_delay;
+#if 0
+ spinlock_t chip_lock;
+ wait_queue_head_t wq;
+ nand_state_t state;
+#endif
int page_shift;
+ int phys_erase_shift;
+ int bbt_erase_shift;
+ int chip_shift;
u_char *data_buf;
- u_char *data_cache;
- int cache_page;
- u_char ecc_code_buf[6];
- u_char reserved[2];
- char ChipID; /* Type of DiskOnChip */
- struct Nand *chips;
- int chipshift;
- char* chips_name;
- unsigned long erasesize;
- unsigned long mfr; /* Flash IDs - only one type of flash per device */
- unsigned long id;
- char* name;
- int numchips;
- char page256;
- char pageadrlen;
- unsigned long IO_ADDR; /* address to access the 8 I/O lines to the flash device */
- unsigned long totlen;
- uint oobblock; /* Size of OOB blocks (e.g. 512) */
- uint oobsize; /* Amount of OOB data per block (e.g. 16) */
- uint eccsize;
- int bus16;
+ u_char *oob_buf;
+ int oobdirty;
+ u_char *data_poi;
+ unsigned int options;
+ int badblockpos;
+ int numchips;
+ unsigned long chipsize;
+ int pagemask;
+ int pagebuf;
+ struct nand_oobinfo *autooob;
+ uint8_t *bbt;
+ struct nand_bbt_descr *bbt_td;
+ struct nand_bbt_descr *bbt_md;
+ struct nand_bbt_descr *badblock_pattern;
+ struct nand_hw_control *controller;
+ void *priv;
};
/*
*/
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
+#define NAND_MFR_FUJITSU 0x04
+#define NAND_MFR_NATIONAL 0x8f
+#define NAND_MFR_RENESAS 0x07
+#define NAND_MFR_STMICRO 0x20
-/*
- * NAND Flash Device ID Structure
- *
- * Structure overview:
- *
- * name - Complete name of device
- *
- * manufacture_id - manufacturer ID code of device.
- *
- * model_id - model ID code of device.
- *
- * chipshift - total number of address bits for the device which
- * is used to calculate address offsets and the total
- * number of bytes the device is capable of.
+/**
+ * struct nand_flash_dev - NAND Flash Device ID Structure
*
- * page256 - denotes if flash device has 256 byte pages or not.
- *
- * pageadrlen - number of bytes minus one needed to hold the
- * complete address into the flash array. Keep in
- * mind that when a read or write is done to a
- * specific address, the address is input serially
- * 8 bits at a time. This structure member is used
- * by the read/write routines as a loop index for
- * shifting the address out 8 bits at a time.
- *
- * erasesize - size of an erase block in the flash device.
+ * @name: Identify the device type
+ * @id: device ID code
+ * @pagesize: Pagesize in bytes. Either 256 or 512 or 0
+ * If the pagesize is 0, then the real pagesize
+ * and the eraseize are determined from the
+ * extended id bytes in the chip
+ * @erasesize: Size of an erase block in the flash device.
+ * @chipsize: Total chipsize in Mega Bytes
+ * @options: Bitfield to store chip relevant options
*/
struct nand_flash_dev {
- char * name;
- int manufacture_id;
- int model_id;
- int chipshift;
- char page256;
- char pageadrlen;
+ char *name;
+ int id;
+ unsigned long pagesize;
+ unsigned long chipsize;
unsigned long erasesize;
- int bus16;
+ unsigned long options;
};
+/**
+ * struct nand_manufacturers - NAND Flash Manufacturer ID Structure
+ * @name: Manufacturer name
+ * @id: manufacturer ID code of device.
+*/
+struct nand_manufacturers {
+ int id;
+ char * name;
+};
+
+extern struct nand_flash_dev nand_flash_ids[];
+extern struct nand_manufacturers nand_manuf_ids[];
+
+/**
+ * struct nand_bbt_descr - bad block table descriptor
+ * @options: options for this descriptor
+ * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
+ * when bbt is searched, then we store the found bbts pages here.
+ * Its an array and supports up to 8 chips now
+ * @offs: offset of the pattern in the oob area of the page
+ * @veroffs: offset of the bbt version counter in the oob are of the page
+ * @version: version read from the bbt page during scan
+ * @len: length of the pattern, if 0 no pattern check is performed
+ * @maxblocks: maximum number of blocks to search for a bbt. This number of
+ * blocks is reserved at the end of the device where the tables are
+ * written.
+ * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
+ * bad) block in the stored bbt
+ * @pattern: pattern to identify bad block table or factory marked good /
+ * bad blocks, can be NULL, if len = 0
+ *
+ * Descriptor for the bad block table marker and the descriptor for the
+ * pattern which identifies good and bad blocks. The assumption is made
+ * that the pattern and the version count are always located in the oob area
+ * of the first block.
+ */
+struct nand_bbt_descr {
+ int options;
+ int pages[NAND_MAX_CHIPS];
+ int offs;
+ int veroffs;
+ uint8_t version[NAND_MAX_CHIPS];
+ int len;
+ int maxblocks;
+ int reserved_block_code;
+ uint8_t *pattern;
+};
+
+/* Options for the bad block table descriptors */
+
+/* The number of bits used per block in the bbt on the device */
+#define NAND_BBT_NRBITS_MSK 0x0000000F
+#define NAND_BBT_1BIT 0x00000001
+#define NAND_BBT_2BIT 0x00000002
+#define NAND_BBT_4BIT 0x00000004
+#define NAND_BBT_8BIT 0x00000008
+/* The bad block table is in the last good block of the device */
+#define NAND_BBT_LASTBLOCK 0x00000010
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_ABSPAGE 0x00000020
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_SEARCH 0x00000040
+/* bbt is stored per chip on multichip devices */
+#define NAND_BBT_PERCHIP 0x00000080
+/* bbt has a version counter at offset veroffs */
+#define NAND_BBT_VERSION 0x00000100
+/* Create a bbt if none axists */
+#define NAND_BBT_CREATE 0x00000200
+/* Search good / bad pattern through all pages of a block */
+#define NAND_BBT_SCANALLPAGES 0x00000400
+/* Scan block empty during good / bad block scan */
+#define NAND_BBT_SCANEMPTY 0x00000800
+/* Write bbt if neccecary */
+#define NAND_BBT_WRITE 0x00001000
+/* Read and write back block contents when writing bbt */
+#define NAND_BBT_SAVECONTENT 0x00002000
+/* Search good / bad pattern on the first and the second page */
+#define NAND_BBT_SCAN2NDPAGE 0x00004000
+
+/* The maximum number of blocks to scan for a bbt */
+#define NAND_BBT_SCAN_MAXBLOCKS 4
+
+extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd);
+extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
+extern int nand_default_bbt (struct mtd_info *mtd);
+extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
+extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
+
/*
* Constants for oob configuration
*/
-#define NAND_NOOB_ECCPOS0 0
-#define NAND_NOOB_ECCPOS1 1
-#define NAND_NOOB_ECCPOS2 2
-#define NAND_NOOB_ECCPOS3 3
-#define NAND_NOOB_ECCPOS4 6
-#define NAND_NOOB_ECCPOS5 7
-#define NAND_NOOB_BADBPOS -1
-#define NAND_NOOB_ECCVPOS -1
-
-#define NAND_JFFS2_OOB_ECCPOS0 0
-#define NAND_JFFS2_OOB_ECCPOS1 1
-#define NAND_JFFS2_OOB_ECCPOS2 2
-#define NAND_JFFS2_OOB_ECCPOS3 3
-#define NAND_JFFS2_OOB_ECCPOS4 6
-#define NAND_JFFS2_OOB_ECCPOS5 7
-#define NAND_JFFS2_OOB_BADBPOS 5
-#define NAND_JFFS2_OOB_ECCVPOS 4
-
-#define NAND_JFFS2_OOB8_FSDAPOS 6
-#define NAND_JFFS2_OOB16_FSDAPOS 8
-#define NAND_JFFS2_OOB8_FSDALEN 2
-#define NAND_JFFS2_OOB16_FSDALEN 8
-
-unsigned long nand_probe(unsigned long physadr);
-#endif /* !CONFIG_NEW_NAND_CODE */
+#define NAND_SMALL_BADBLOCK_POS 5
+#define NAND_LARGE_BADBLOCK_POS 0
+
#endif /* __LINUX_MTD_NAND_H */
#ifndef __LINUX_MTD_NAND_IDS_H
#define __LINUX_MTD_NAND_IDS_H
+#ifndef CFG_NAND_LEGACY
+#error This module is for the legacy NAND support
+#endif
+
static struct nand_flash_dev nand_flash_ids[] = {
{"Toshiba TC5816BDC", NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000, 0},
{"Toshiba TC5832DC", NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000, 0},
--- /dev/null
+/*
+ * linux/include/linux/mtd/nand.h
+ *
+ * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
+ * Steven J. Hill <sjhill@cotw.com>
+ * Thomas Gleixner <gleixner@autronix.de>
+ *
+ * $Id: nand.h,v 1.7 2003/07/24 23:30:46 a0384864 Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Info:
+ * Contains standard defines and IDs for NAND flash devices
+ *
+ * Changelog:
+ * 01-31-2000 DMW Created
+ * 09-18-2000 SJH Moved structure out of the Disk-On-Chip drivers
+ * so it can be used by other NAND flash device
+ * drivers. I also changed the copyright since none
+ * of the original contents of this file are specific
+ * to DoC devices. David can whack me with a baseball
+ * bat later if I did something naughty.
+ * 10-11-2000 SJH Added private NAND flash structure for driver
+ * 10-24-2000 SJH Added prototype for 'nand_scan' function
+ * 10-29-2001 TG changed nand_chip structure to support
+ * hardwarespecific function for accessing control lines
+ * 02-21-2002 TG added support for different read/write adress and
+ * ready/busy line access function
+ * 02-26-2002 TG added chip_delay to nand_chip structure to optimize
+ * command delay times for different chips
+ * 04-28-2002 TG OOB config defines moved from nand.c to avoid duplicate
+ * defines in jffs2/wbuf.c
+ */
+#ifndef __LINUX_MTD_NAND_LEGACY_H
+#define __LINUX_MTD_NAND_LEGACY_H
+
+#ifndef CFG_NAND_LEGACY
+#error This module is for the legacy NAND support
+#endif
+
+/*
+ * Standard NAND flash commands
+ */
+#define NAND_CMD_READ0 0
+#define NAND_CMD_READ1 1
+#define NAND_CMD_PAGEPROG 0x10
+#define NAND_CMD_READOOB 0x50
+#define NAND_CMD_ERASE1 0x60
+#define NAND_CMD_STATUS 0x70
+#define NAND_CMD_SEQIN 0x80
+#define NAND_CMD_READID 0x90
+#define NAND_CMD_ERASE2 0xd0
+#define NAND_CMD_RESET 0xff
+
+/*
+ * Enumeration for NAND flash chip state
+ */
+typedef enum {
+ FL_READY,
+ FL_READING,
+ FL_WRITING,
+ FL_ERASING,
+ FL_SYNCING
+} nand_state_t;
+
+
+/*
+ * NAND Private Flash Chip Data
+ *
+ * Structure overview:
+ *
+ * IO_ADDR - address to access the 8 I/O lines of the flash device
+ *
+ * hwcontrol - hardwarespecific function for accesing control-lines
+ *
+ * dev_ready - hardwarespecific function for accesing device ready/busy line
+ *
+ * chip_lock - spinlock used to protect access to this structure
+ *
+ * wq - wait queue to sleep on if a NAND operation is in progress
+ *
+ * state - give the current state of the NAND device
+ *
+ * page_shift - number of address bits in a page (column address bits)
+ *
+ * data_buf - data buffer passed to/from MTD user modules
+ *
+ * data_cache - data cache for redundant page access and shadow for
+ * ECC failure
+ *
+ * ecc_code_buf - used only for holding calculated or read ECCs for
+ * a page read or written when ECC is in use
+ *
+ * reserved - padding to make structure fall on word boundary if
+ * when ECC is in use
+ */
+struct Nand {
+ char floor, chip;
+ unsigned long curadr;
+ unsigned char curmode;
+ /* Also some erase/write/pipeline info when we get that far */
+};
+
+struct nand_chip {
+ int page_shift;
+ u_char *data_buf;
+ u_char *data_cache;
+ int cache_page;
+ u_char ecc_code_buf[6];
+ u_char reserved[2];
+ char ChipID; /* Type of DiskOnChip */
+ struct Nand *chips;
+ int chipshift;
+ char* chips_name;
+ unsigned long erasesize;
+ unsigned long mfr; /* Flash IDs - only one type of flash per device */
+ unsigned long id;
+ char* name;
+ int numchips;
+ char page256;
+ char pageadrlen;
+ unsigned long IO_ADDR; /* address to access the 8 I/O lines to the flash device */
+ unsigned long totlen;
+ uint oobblock; /* Size of OOB blocks (e.g. 512) */
+ uint oobsize; /* Amount of OOB data per block (e.g. 16) */
+ uint eccsize;
+ int bus16;
+};
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_TOSHIBA 0x98
+#define NAND_MFR_SAMSUNG 0xec
+
+/*
+ * NAND Flash Device ID Structure
+ *
+ * Structure overview:
+ *
+ * name - Complete name of device
+ *
+ * manufacture_id - manufacturer ID code of device.
+ *
+ * model_id - model ID code of device.
+ *
+ * chipshift - total number of address bits for the device which
+ * is used to calculate address offsets and the total
+ * number of bytes the device is capable of.
+ *
+ * page256 - denotes if flash device has 256 byte pages or not.
+ *
+ * pageadrlen - number of bytes minus one needed to hold the
+ * complete address into the flash array. Keep in
+ * mind that when a read or write is done to a
+ * specific address, the address is input serially
+ * 8 bits at a time. This structure member is used
+ * by the read/write routines as a loop index for
+ * shifting the address out 8 bits at a time.
+ *
+ * erasesize - size of an erase block in the flash device.
+ */
+struct nand_flash_dev {
+ char * name;
+ int manufacture_id;
+ int model_id;
+ int chipshift;
+ char page256;
+ char pageadrlen;
+ unsigned long erasesize;
+ int bus16;
+};
+
+/*
+* Constants for oob configuration
+*/
+#define NAND_NOOB_ECCPOS0 0
+#define NAND_NOOB_ECCPOS1 1
+#define NAND_NOOB_ECCPOS2 2
+#define NAND_NOOB_ECCPOS3 3
+#define NAND_NOOB_ECCPOS4 6
+#define NAND_NOOB_ECCPOS5 7
+#define NAND_NOOB_BADBPOS -1
+#define NAND_NOOB_ECCVPOS -1
+
+#define NAND_JFFS2_OOB_ECCPOS0 0
+#define NAND_JFFS2_OOB_ECCPOS1 1
+#define NAND_JFFS2_OOB_ECCPOS2 2
+#define NAND_JFFS2_OOB_ECCPOS3 3
+#define NAND_JFFS2_OOB_ECCPOS4 6
+#define NAND_JFFS2_OOB_ECCPOS5 7
+#define NAND_JFFS2_OOB_BADBPOS 5
+#define NAND_JFFS2_OOB_ECCVPOS 4
+
+#define NAND_JFFS2_OOB8_FSDAPOS 6
+#define NAND_JFFS2_OOB16_FSDAPOS 8
+#define NAND_JFFS2_OOB8_FSDALEN 2
+#define NAND_JFFS2_OOB16_FSDALEN 8
+
+unsigned long nand_probe(unsigned long physadr);
+#endif /* __LINUX_MTD_NAND_LEGACY_H */
+++ /dev/null
-/*
- * linux/include/linux/mtd/nand.h
- *
- * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
- * Steven J. Hill <sjhill@realitydiluted.com>
- * Thomas Gleixner <tglx@linutronix.de>
- *
- * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Info:
- * Contains standard defines and IDs for NAND flash devices
- *
- * Changelog:
- * 01-31-2000 DMW Created
- * 09-18-2000 SJH Moved structure out of the Disk-On-Chip drivers
- * so it can be used by other NAND flash device
- * drivers. I also changed the copyright since none
- * of the original contents of this file are specific
- * to DoC devices. David can whack me with a baseball
- * bat later if I did something naughty.
- * 10-11-2000 SJH Added private NAND flash structure for driver
- * 10-24-2000 SJH Added prototype for 'nand_scan' function
- * 10-29-2001 TG changed nand_chip structure to support
- * hardwarespecific function for accessing control lines
- * 02-21-2002 TG added support for different read/write adress and
- * ready/busy line access function
- * 02-26-2002 TG added chip_delay to nand_chip structure to optimize
- * command delay times for different chips
- * 04-28-2002 TG OOB config defines moved from nand.c to avoid duplicate
- * defines in jffs2/wbuf.c
- * 08-07-2002 TG forced bad block location to byte 5 of OOB, even if
- * CONFIG_MTD_NAND_ECC_JFFS2 is not set
- * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC
- *
- * 08-29-2002 tglx nand_chip structure: data_poi for selecting
- * internal / fs-driver buffer
- * support for 6byte/512byte hardware ECC
- * read_ecc, write_ecc extended for different oob-layout
- * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB,
- * NAND_YAFFS_OOB
- * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL
- * Split manufacturer and device ID structures
- *
- * 02-08-2004 tglx added option field to nand structure for chip anomalities
- * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id
- * update of nand_chip structure description
- */
-#ifndef __LINUX_MTD_NAND_NEW_H
-#define __LINUX_MTD_NAND_NEW_H
-
-#include <linux/mtd/compat.h>
-#include <linux/mtd/mtd.h>
-
-struct mtd_info;
-/* Scan and identify a NAND device */
-extern int nand_scan (struct mtd_info *mtd, int max_chips);
-/* Free resources held by the NAND device */
-extern void nand_release (struct mtd_info *mtd);
-
-/* Read raw data from the device without ECC */
-extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen);
-
-
-
-/* This constant declares the max. oobsize / page, which
- * is supported now. If you add a chip with bigger oobsize/page
- * adjust this accordingly.
- */
-#define NAND_MAX_OOBSIZE 64
-
-/*
- * Constants for hardware specific CLE/ALE/NCE function
-*/
-/* Select the chip by setting nCE to low */
-#define NAND_CTL_SETNCE 1
-/* Deselect the chip by setting nCE to high */
-#define NAND_CTL_CLRNCE 2
-/* Select the command latch by setting CLE to high */
-#define NAND_CTL_SETCLE 3
-/* Deselect the command latch by setting CLE to low */
-#define NAND_CTL_CLRCLE 4
-/* Select the address latch by setting ALE to high */
-#define NAND_CTL_SETALE 5
-/* Deselect the address latch by setting ALE to low */
-#define NAND_CTL_CLRALE 6
-/* Set write protection by setting WP to high. Not used! */
-#define NAND_CTL_SETWP 7
-/* Clear write protection by setting WP to low. Not used! */
-#define NAND_CTL_CLRWP 8
-
-/*
- * Standard NAND flash commands
- */
-#define NAND_CMD_READ0 0
-#define NAND_CMD_READ1 1
-#define NAND_CMD_PAGEPROG 0x10
-#define NAND_CMD_READOOB 0x50
-#define NAND_CMD_ERASE1 0x60
-#define NAND_CMD_STATUS 0x70
-#define NAND_CMD_STATUS_MULTI 0x71
-#define NAND_CMD_SEQIN 0x80
-#define NAND_CMD_READID 0x90
-#define NAND_CMD_ERASE2 0xd0
-#define NAND_CMD_RESET 0xff
-
-/* Extended commands for large page devices */
-#define NAND_CMD_READSTART 0x30
-#define NAND_CMD_CACHEDPROG 0x15
-
-/* Status bits */
-#define NAND_STATUS_FAIL 0x01
-#define NAND_STATUS_FAIL_N1 0x02
-#define NAND_STATUS_TRUE_READY 0x20
-#define NAND_STATUS_READY 0x40
-#define NAND_STATUS_WP 0x80
-
-/*
- * Constants for ECC_MODES
- */
-
-/* No ECC. Usage is not recommended ! */
-#define NAND_ECC_NONE 0
-/* Software ECC 3 byte ECC per 256 Byte data */
-#define NAND_ECC_SOFT 1
-/* Hardware ECC 3 byte ECC per 256 Byte data */
-#define NAND_ECC_HW3_256 2
-/* Hardware ECC 3 byte ECC per 512 Byte data */
-#define NAND_ECC_HW3_512 3
-/* Hardware ECC 3 byte ECC per 512 Byte data */
-#define NAND_ECC_HW6_512 4
-/* Hardware ECC 8 byte ECC per 512 Byte data */
-#define NAND_ECC_HW8_512 6
-/* Hardware ECC 12 byte ECC per 2048 Byte data */
-#define NAND_ECC_HW12_2048 7
-
-/*
- * Constants for Hardware ECC
-*/
-/* Reset Hardware ECC for read */
-#define NAND_ECC_READ 0
-/* Reset Hardware ECC for write */
-#define NAND_ECC_WRITE 1
-/* Enable Hardware ECC before syndrom is read back from flash */
-#define NAND_ECC_READSYN 2
-
-/* Option constants for bizarre disfunctionality and real
-* features
-*/
-/* Chip can not auto increment pages */
-#define NAND_NO_AUTOINCR 0x00000001
-/* Buswitdh is 16 bit */
-#define NAND_BUSWIDTH_16 0x00000002
-/* Device supports partial programming without padding */
-#define NAND_NO_PADDING 0x00000004
-/* Chip has cache program function */
-#define NAND_CACHEPRG 0x00000008
-/* Chip has copy back function */
-#define NAND_COPYBACK 0x00000010
-/* AND Chip which has 4 banks and a confusing page / block
- * assignment. See Renesas datasheet for further information */
-#define NAND_IS_AND 0x00000020
-/* Chip has a array of 4 pages which can be read without
- * additional ready /busy waits */
-#define NAND_4PAGE_ARRAY 0x00000040
-
-/* Options valid for Samsung large page devices */
-#define NAND_SAMSUNG_LP_OPTIONS \
- (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
-
-/* Macros to identify the above */
-#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
-#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
-#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
-#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
-
-/* Mask to zero out the chip options, which come from the id table */
-#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
-
-/* Non chip related options */
-/* Use a flash based bad block table. This option is passed to the
- * default bad block table function. */
-#define NAND_USE_FLASH_BBT 0x00010000
-/* The hw ecc generator provides a syndrome instead a ecc value on read
- * This can only work if we have the ecc bytes directly behind the
- * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
-#define NAND_HWECC_SYNDROME 0x00020000
-
-
-/* Options set by nand scan */
-/* Nand scan has allocated oob_buf */
-#define NAND_OOBBUF_ALLOC 0x40000000
-/* Nand scan has allocated data_buf */
-#define NAND_DATABUF_ALLOC 0x80000000
-
-
-/*
- * nand_state_t - chip states
- * Enumeration for NAND flash chip state
- */
-typedef enum {
- FL_READY,
- FL_READING,
- FL_WRITING,
- FL_ERASING,
- FL_SYNCING,
- FL_CACHEDPRG,
-} nand_state_t;
-
-/* Keep gcc happy */
-struct nand_chip;
-
-#if 0
-/**
- * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
- * @lock: protection lock
- * @active: the mtd device which holds the controller currently
- */
-struct nand_hw_control {
- spinlock_t lock;
- struct nand_chip *active;
-};
-#endif
-
-/**
- * struct nand_chip - NAND Private Flash Chip Data
- * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
- * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device
- * @read_byte: [REPLACEABLE] read one byte from the chip
- * @write_byte: [REPLACEABLE] write one byte to the chip
- * @read_word: [REPLACEABLE] read one word from the chip
- * @write_word: [REPLACEABLE] write one word to the chip
- * @write_buf: [REPLACEABLE] write data from the buffer to the chip
- * @read_buf: [REPLACEABLE] read data from the chip into the buffer
- * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data
- * @select_chip: [REPLACEABLE] select chip nr
- * @block_bad: [REPLACEABLE] check, if the block is bad
- * @block_markbad: [REPLACEABLE] mark the block bad
- * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines
- * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
- * If set to NULL no access to ready/busy is available and the ready/busy information
- * is read from the chip status register
- * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
- * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
- * @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware
- * @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
- * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
- * be provided if a hardware ECC is available
- * @erase_cmd: [INTERN] erase command write function, selectable due to AND support
- * @scan_bbt: [REPLACEABLE] function to scan bad block table
- * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines
- * @eccsize: [INTERN] databytes used per ecc-calculation
- * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step
- * @eccsteps: [INTERN] number of ecc calculation steps per page
- * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
- * @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip
- * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
- * @state: [INTERN] the current state of the NAND device
- * @page_shift: [INTERN] number of address bits in a page (column address bits)
- * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
- * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
- * @chip_shift: [INTERN] number of address bits in one chip
- * @data_buf: [INTERN] internal buffer for one page + oob
- * @oob_buf: [INTERN] oob buffer for one eraseblock
- * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized
- * @data_poi: [INTERN] pointer to a data buffer
- * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
- * special functionality. See the defines for further explanation
- * @badblockpos: [INTERN] position of the bad block marker in the oob area
- * @numchips: [INTERN] number of physical chips
- * @chipsize: [INTERN] the size of one chip for multichip arrays
- * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
- * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
- * @autooob: [REPLACEABLE] the default (auto)placement scheme
- * @bbt: [INTERN] bad block table pointer
- * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
- * @bbt_md: [REPLACEABLE] bad block table mirror descriptor
- * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
- * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
- * @priv: [OPTIONAL] pointer to private chip date
- */
-
-struct nand_chip {
- void __iomem *IO_ADDR_R;
- void __iomem *IO_ADDR_W;
-
- u_char (*read_byte)(struct mtd_info *mtd);
- void (*write_byte)(struct mtd_info *mtd, u_char byte);
- u16 (*read_word)(struct mtd_info *mtd);
- void (*write_word)(struct mtd_info *mtd, u16 word);
-
- void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
- void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
- int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
- void (*select_chip)(struct mtd_info *mtd, int chip);
- int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
- int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
- void (*hwcontrol)(struct mtd_info *mtd, int cmd);
- int (*dev_ready)(struct mtd_info *mtd);
- void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
- int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
- int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
- int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
- void (*enable_hwecc)(struct mtd_info *mtd, int mode);
- void (*erase_cmd)(struct mtd_info *mtd, int page);
- int (*scan_bbt)(struct mtd_info *mtd);
- int eccmode;
- int eccsize;
- int eccbytes;
- int eccsteps;
- int chip_delay;
-#if 0
- spinlock_t chip_lock;
- wait_queue_head_t wq;
- nand_state_t state;
-#endif
- int page_shift;
- int phys_erase_shift;
- int bbt_erase_shift;
- int chip_shift;
- u_char *data_buf;
- u_char *oob_buf;
- int oobdirty;
- u_char *data_poi;
- unsigned int options;
- int badblockpos;
- int numchips;
- unsigned long chipsize;
- int pagemask;
- int pagebuf;
- struct nand_oobinfo *autooob;
- uint8_t *bbt;
- struct nand_bbt_descr *bbt_td;
- struct nand_bbt_descr *bbt_md;
- struct nand_bbt_descr *badblock_pattern;
- struct nand_hw_control *controller;
- void *priv;
-};
-
-/*
- * NAND Flash Manufacturer ID Codes
- */
-#define NAND_MFR_TOSHIBA 0x98
-#define NAND_MFR_SAMSUNG 0xec
-#define NAND_MFR_FUJITSU 0x04
-#define NAND_MFR_NATIONAL 0x8f
-#define NAND_MFR_RENESAS 0x07
-#define NAND_MFR_STMICRO 0x20
-
-/**
- * struct nand_flash_dev - NAND Flash Device ID Structure
- *
- * @name: Identify the device type
- * @id: device ID code
- * @pagesize: Pagesize in bytes. Either 256 or 512 or 0
- * If the pagesize is 0, then the real pagesize
- * and the eraseize are determined from the
- * extended id bytes in the chip
- * @erasesize: Size of an erase block in the flash device.
- * @chipsize: Total chipsize in Mega Bytes
- * @options: Bitfield to store chip relevant options
- */
-struct nand_flash_dev {
- char *name;
- int id;
- unsigned long pagesize;
- unsigned long chipsize;
- unsigned long erasesize;
- unsigned long options;
-};
-
-/**
- * struct nand_manufacturers - NAND Flash Manufacturer ID Structure
- * @name: Manufacturer name
- * @id: manufacturer ID code of device.
-*/
-struct nand_manufacturers {
- int id;
- char * name;
-};
-
-extern struct nand_flash_dev nand_flash_ids[];
-extern struct nand_manufacturers nand_manuf_ids[];
-
-/**
- * struct nand_bbt_descr - bad block table descriptor
- * @options: options for this descriptor
- * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
- * when bbt is searched, then we store the found bbts pages here.
- * Its an array and supports up to 8 chips now
- * @offs: offset of the pattern in the oob area of the page
- * @veroffs: offset of the bbt version counter in the oob are of the page
- * @version: version read from the bbt page during scan
- * @len: length of the pattern, if 0 no pattern check is performed
- * @maxblocks: maximum number of blocks to search for a bbt. This number of
- * blocks is reserved at the end of the device where the tables are
- * written.
- * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
- * bad) block in the stored bbt
- * @pattern: pattern to identify bad block table or factory marked good /
- * bad blocks, can be NULL, if len = 0
- *
- * Descriptor for the bad block table marker and the descriptor for the
- * pattern which identifies good and bad blocks. The assumption is made
- * that the pattern and the version count are always located in the oob area
- * of the first block.
- */
-struct nand_bbt_descr {
- int options;
- int pages[NAND_MAX_CHIPS];
- int offs;
- int veroffs;
- uint8_t version[NAND_MAX_CHIPS];
- int len;
- int maxblocks;
- int reserved_block_code;
- uint8_t *pattern;
-};
-
-/* Options for the bad block table descriptors */
-
-/* The number of bits used per block in the bbt on the device */
-#define NAND_BBT_NRBITS_MSK 0x0000000F
-#define NAND_BBT_1BIT 0x00000001
-#define NAND_BBT_2BIT 0x00000002
-#define NAND_BBT_4BIT 0x00000004
-#define NAND_BBT_8BIT 0x00000008
-/* The bad block table is in the last good block of the device */
-#define NAND_BBT_LASTBLOCK 0x00000010
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_ABSPAGE 0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH 0x00000040
-/* bbt is stored per chip on multichip devices */
-#define NAND_BBT_PERCHIP 0x00000080
-/* bbt has a version counter at offset veroffs */
-#define NAND_BBT_VERSION 0x00000100
-/* Create a bbt if none axists */
-#define NAND_BBT_CREATE 0x00000200
-/* Search good / bad pattern through all pages of a block */
-#define NAND_BBT_SCANALLPAGES 0x00000400
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY 0x00000800
-/* Write bbt if neccecary */
-#define NAND_BBT_WRITE 0x00001000
-/* Read and write back block contents when writing bbt */
-#define NAND_BBT_SAVECONTENT 0x00002000
-/* Search good / bad pattern on the first and the second page */
-#define NAND_BBT_SCAN2NDPAGE 0x00004000
-
-/* The maximum number of blocks to scan for a bbt */
-#define NAND_BBT_SCAN_MAXBLOCKS 4
-
-extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd);
-extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
-extern int nand_default_bbt (struct mtd_info *mtd);
-extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
-extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
-
-/*
-* Constants for oob configuration
-*/
-#define NAND_SMALL_BADBLOCK_POS 5
-#define NAND_LARGE_BADBLOCK_POS 0
-
-#endif /* __LINUX_MTD_NAND_NEW_H */