summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Ungar <david.ungar@timesys.com>2010-10-11 14:24:08 -0400
committerDavid Ungar <david.ungar@timesys.com>2010-10-11 14:39:23 -0400
commita718de3f42a6280fefd8b60b3e4733e015b0f637 (patch)
tree1b0c5b36cd7fb408e8119d56c542f86903cc56d5
parent411a2e5823bf4280d70d5b9e9ea683e27b09f7b2 (diff)
Additional NAND support
-rw-r--r--board/omap3/logic/logic.c88
-rw-r--r--common/cmd_nand.c42
-rw-r--r--cpu/arm_cortexa8/omap3/board.c19
-rw-r--r--drivers/mtd/mtdcore.c4
-rw-r--r--drivers/mtd/nand/nand_base.c93
-rw-r--r--drivers/mtd/nand/nand_util.c78
-rw-r--r--drivers/mtd/nand/omap_gpmc.c383
-rw-r--r--include/asm-arm/arch-omap3/omap_gpmc.h19
-rw-r--r--include/asm-arm/arch-omap3/sys_proto.h10
-rw-r--r--include/configs/omap3_logic.h50
-rw-r--r--include/linux/mtd/mtd.h3
-rw-r--r--include/linux/mtd/nand.h12
-rw-r--r--include/nand.h2
-rw-r--r--lib_arm/board.c9
14 files changed, 718 insertions, 94 deletions
diff --git a/board/omap3/logic/logic.c b/board/omap3/logic/logic.c
index e0bcbc4bf3..77d5e21bbb 100644
--- a/board/omap3/logic/logic.c
+++ b/board/omap3/logic/logic.c
@@ -38,6 +38,8 @@
#include <asm/arch/gpio.h>
#include <asm/mach-types.h>
#include "logic.h"
+#include "product_id.h"
+#include <nand.h>
/*
* Routine: logic_identify
@@ -47,7 +49,7 @@
*/
unsigned int logic_identify(void)
{
- unsigned int val;
+ unsigned int val = 0;
int i;
MUX_LOGIC_HSUSB0_D5_GPIO_MUX();
@@ -64,19 +66,66 @@ unsigned int logic_identify(void)
omap_set_gpio_direction(189, 1);
val = omap_get_gpio_datain(189);
omap_free_gpio(189);
- }
- printf("Board: ");
- if (val) {
- printf("Torpedo\n");
- val = MACH_TYPE_OMAP3_TORPEDO;
- } else {
- printf("LV SOM\n");
- val = MACH_TYPE_OMAP3530_LV_SOM;
+ printf("Board: ");
+ if (val) {
+ printf("Torpedo\n");
+ val = MACH_TYPE_OMAP3_TORPEDO;
+ } else {
+ printf("LV SOM\n");
+ val = MACH_TYPE_OMAP3530_LV_SOM;
+ }
}
return val;
}
+
+#define LOGIC_NAND_GPMC_CONFIG1 0x00001800
+#define LOGIC_NAND_GPMC_CONFIG2 0x00090900
+#define LOGIC_NAND_GPMC_CONFIG3 0x00090902
+#define LOGIC_NAND_GPMC_CONFIG4 0x07020702
+#define LOGIC_NAND_GPMC_CONFIG5 0x00080909
+#define LOGIC_NAND_GPMC_CONFIG6 0x000002CF
+#define LOGIC_NAND_GPMC_CONFIG7 0x00000C70
+
+static void setup_nand_settings(void)
+{
+ /* Configure GPMC registers */
+ writel(0x00000000, &gpmc_cfg->cs[0].config7);
+ sdelay(1000);
+ writel(LOGIC_NAND_GPMC_CONFIG1, &gpmc_cfg->cs[0].config1);
+ writel(LOGIC_NAND_GPMC_CONFIG2, &gpmc_cfg->cs[0].config2);
+ writel(LOGIC_NAND_GPMC_CONFIG3, &gpmc_cfg->cs[0].config3);
+ writel(LOGIC_NAND_GPMC_CONFIG4, &gpmc_cfg->cs[0].config4);
+ writel(LOGIC_NAND_GPMC_CONFIG5, &gpmc_cfg->cs[0].config5);
+ writel(LOGIC_NAND_GPMC_CONFIG6, &gpmc_cfg->cs[0].config6);
+ writel(LOGIC_NAND_GPMC_CONFIG7, &gpmc_cfg->cs[0].config7);
+ sdelay(2000);
+}
+
+#define LOGIC_CF_GPMC_CONFIG1 0x00001210
+#define LOGIC_CF_GPMC_CONFIG2 0x00131000
+#define LOGIC_CF_GPMC_CONFIG3 0x001f1f01
+#define LOGIC_CF_GPMC_CONFIG4 0x10030e03
+#define LOGIC_CF_GPMC_CONFIG5 0x010f1411
+#define LOGIC_CF_GPMC_CONFIG6 0x80030600
+#define LOGIC_CF_GPMC_CONFIG7 0x00000f58
+
+static void setup_cf_gpmc_setup(void)
+{
+ /* Configure GPMC registers */
+ writel(0x00000000, &gpmc_cfg->cs[3].config7);
+ sdelay(1000);
+ writel(LOGIC_CF_GPMC_CONFIG1, &gpmc_cfg->cs[3].config1);
+ writel(LOGIC_CF_GPMC_CONFIG2, &gpmc_cfg->cs[3].config2);
+ writel(LOGIC_CF_GPMC_CONFIG3, &gpmc_cfg->cs[3].config3);
+ writel(LOGIC_CF_GPMC_CONFIG4, &gpmc_cfg->cs[3].config4);
+ writel(LOGIC_CF_GPMC_CONFIG5, &gpmc_cfg->cs[3].config5);
+ writel(LOGIC_CF_GPMC_CONFIG6, &gpmc_cfg->cs[3].config6);
+ writel(LOGIC_CF_GPMC_CONFIG7, &gpmc_cfg->cs[3].config7);
+ sdelay(2000);
+}
+
/*
* Routine: board_init
* Description: Early hardware init.
@@ -86,6 +135,15 @@ int board_init(void)
DECLARE_GLOBAL_DATA_PTR;
gpmc_init(); /* in SRAM or SDRAM, finish GPMC */
+
+ /* Update NAND settings */
+ setup_nand_settings();
+
+#if 0
+ /* Update CF settings */
+ setup_cf_gpmc_setup();
+#endif
+
/* board id for Linux (placeholder until can ID board) */
gd->bd->bi_arch_number = MACH_TYPE_OMAP3530_LV_SOM;
/* boot param addr */
@@ -94,7 +152,6 @@ int board_init(void)
return 0;
}
-
static void setup_net_chip(void);
static void setup_isp1760_chip(void);
static void fix_flash_sync(void);
@@ -196,6 +253,11 @@ int board_late_init(void)
// Fetch the ethaddr of the WiFi
board_get_nth_enetaddr(enetaddr, 1, 1);
#endif
+
+#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
+ // Unlock the whole chip
+ nand_unlock(&nand_info[0], 0x0, nand_info[0].size);
+#endif
return 0;
}
@@ -212,11 +274,11 @@ void set_muxconf_regs(void)
// GPMC settings for LV SOM Ethernet chip
#define LOGIC_NET_GPMC_CONFIG1 0x00001000
-#define LOGIC_NET_GPMC_CONFIG2 0x00080802
+#define LOGIC_NET_GPMC_CONFIG2 0x00080701
#define LOGIC_NET_GPMC_CONFIG3 0x00000000
-#define LOGIC_NET_GPMC_CONFIG4 0x08020802
+#define LOGIC_NET_GPMC_CONFIG4 0x08010702
#define LOGIC_NET_GPMC_CONFIG5 0x00080a0a
-#define LOGIC_NET_GPMC_CONFIG6 0x00000000
+#define LOGIC_NET_GPMC_CONFIG6 0x03000280
#define LOGIC_NET_GPMC_CONFIG7 0x00000f48
/*
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index d71fc49077..c3629f49d1 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -182,7 +182,11 @@ static void do_nand_status(nand_info_t *nand)
int last_status = -1;
struct nand_chip *nand_chip = nand->priv;
- /* check the WP bit */
+
+ /* Check the WP bit. To do so requires resetting the device to
+ force the status back to its reset value (so WP becomes whether
+ the WP pin is set). */
+ nand_chip->cmdfunc(nand, NAND_CMD_RESET, -1, -1);
nand_chip->cmdfunc(nand, NAND_CMD_STATUS, -1, -1);
printf("device is %swrite protected\n",
(nand_chip->read_byte(nand) & 0x80 ?
@@ -283,7 +287,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
strcmp(cmd, "biterr") != 0 &&
- strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
+ strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 &&
+ strcmp(cmd, "debug") != 0 && strcmp(cmd, "features") != 0)
goto usage;
/* the following commands operate on the current device */
@@ -399,8 +404,12 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
opts.blockalign = 1;
opts.quiet = quiet;
opts.writeoob = 1;
+#if 1
+ /* Use current ecc layout */
+#else
opts.autoplace = 1;
opts.forceyaffs = 1;
+#endif
nand_write_opts(nand, &opts);
} else if (!strcmp(s, ".oob")) {
/* out-of-band data */
@@ -456,6 +465,26 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
return 1;
}
+#ifdef CONFIG_MTD_DEBUG
+ if (strcmp(cmd, "debug") == 0) {
+ if (argc == 3) {
+ ulong val = simple_strtoul(argv[2], NULL, 16);
+ mtd_debug_verbose = val;
+ } else
+ printf("%d\n", mtd_debug_verbose);
+ return 1;
+ }
+#endif
+
+ if (strcmp(cmd, "features") == 0) {
+ uint8_t features[5];
+ addr = simple_strtoul(argv[2], NULL, 16);
+ nand_get_features(nand, addr, features);
+ printf("%02x %02x %02x %02x %02x\n", features[0],
+ features[1], features[2], features[3], features[4]);
+ return 1;
+ }
+
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
if (strcmp(cmd, "lock") == 0) {
int tight = 0;
@@ -483,6 +512,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
return 1;
+ printf ("nand_unlock: start: %08x, length: %#x\n",
+ (int)off, (int)size);
if (!nand_unlock(nand, off, size)) {
puts("NAND flash successfully unlocked\n");
} else {
@@ -515,13 +546,18 @@ U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,
"nand dump[.oob] off - dump page\n"
"nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
- "nand biterr off - make a bit error at offset (UNSAFE)"
+ "nand biterr off - make a bit error at offset (UNSAFE)\n"
+ "features addr - dump the features addr"
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
"\n"
"nand lock [tight] [status]\n"
" bring nand to lock state or display locked pages\n"
"nand unlock [offset] [size] - unlock section"
#endif
+#ifdef CONFIG_MTD_DEBUG
+ "\n"
+ "nand debug [level] - display or set MTD debug level"
+#endif
);
static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
diff --git a/cpu/arm_cortexa8/omap3/board.c b/cpu/arm_cortexa8/omap3/board.c
index 1c29e2143e..b8db9783b8 100644
--- a/cpu/arm_cortexa8/omap3/board.c
+++ b/cpu/arm_cortexa8/omap3/board.c
@@ -331,18 +331,27 @@ static int do_switch_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
nand = mtd->priv;
if (argc == 1) {
- if (nand->ecc.mode == NAND_ECC_SOFT)
+ switch(nand->ecc.mode) {
+ case NAND_ECC_SOFT:
printf("Software ECC\n");
- else
+ break;
+ case NAND_ECC_HW:
printf("Hardware ECC\n");
+ break;
+ case NAND_ECC_CHIP:
+ printf("Internal to NAND Hardware ECC\n");
+ break;
+ }
return 0;
}
if (argc != 2)
goto usage;
if (strncmp(argv[1], "hw", 2) == 0)
- omap_nand_switch_ecc(1);
+ omap_nand_switch_ecc(OMAP_ECC_HW);
else if (strncmp(argv[1], "sw", 2) == 0)
- omap_nand_switch_ecc(0);
+ omap_nand_switch_ecc(OMAP_ECC_SOFT);
+ else if (strncmp(argv[1], "chip", 4) == 0)
+ omap_nand_switch_ecc(OMAP_ECC_CHIP);
else
goto usage;
@@ -356,7 +365,7 @@ usage:
U_BOOT_CMD(
nandecc, 2, 1, do_switch_ecc,
"nandecc - switch OMAP3 NAND ECC calculation algorithm",
- "[hw/sw] - Switch between NAND hardware (hw) or software (sw) ecc algorithm"
+ "[hw/sw/chip] - Switch between NAND hardware (hw), software (sw), or chip (chip) ecc algorithm"
);
#endif /* CONFIG_NAND_OMAP_GPMC */
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 6eb52ed50c..7bc62e6f86 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -11,6 +11,10 @@
#include <linux/mtd/compat.h>
#include <ubi_uboot.h>
+#ifdef CONFIG_MTD_DEBUG
+int mtd_debug_verbose = CONFIG_MTD_DEBUG_VERBOSE;
+#endif
+
struct mtd_info *mtd_table[MAX_MTD_DEVICES];
int add_mtd_device(struct mtd_info *mtd)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 360b070849..1f3a638748 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -454,11 +454,26 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
static int nand_check_wp(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
- /* Check the WP bit */
+
+ /* Check the WP bit. To do so requires resetting the device to
+ force the status back to its reset value (so WP becomes whether
+ the WP pin is set). */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
}
+static void nand_set_feature(struct mtd_info *mtd, int feature_address, uint8_t *params)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ chip->cmd_ctrl(mtd, NAND_CMD_SETFEATURE, NAND_CTRL_CLE);
+ chip->cmd_ctrl(mtd, feature_address, NAND_CTRL_ALE);
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_CTRL_CHANGE | NAND_NCE);
+ udelay(100);
+ chip->write_buf(mtd, params, 4);
+}
+
/**
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
* @mtd: MTD device structure
@@ -1217,6 +1232,26 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
sndcmd = 0;
}
+ /* If in chip ECC mode, need to read the status
+ to see if an ECC error occurred. */
+ if (chip->ecc.mode == NAND_ECC_CHIP) {
+ int status;
+ chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
+ NAND_CTRL_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd,
+ NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ status = chip->read_byte(mtd);
+ chip->cmd_ctrl(mtd, NAND_CMD_READ0,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ if (status & 0x1)
+ mtd->ecc_stats.failed++;
+ else if (status & 0x10)
+ mtd->ecc_stats.corrected++;
+ }
+
/* Now read the page into the buffer */
if (unlikely(ops->mode == MTD_OOB_RAW))
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
@@ -1420,6 +1455,8 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
+ if ((~status) & NAND_STATUS_WP)
+ return -EPERM;
return status & NAND_STATUS_FAIL ? -EIO : 0;
}
@@ -1479,6 +1516,8 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
+ if ((~status) & NAND_STATUS_WP)
+ return -EPERM;
return status & NAND_STATUS_FAIL ? -EIO : 0;
}
@@ -1768,6 +1807,11 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
* See if operation failed and additional status checks are
* available
*/
+ if ((~status) & NAND_STATUS_WP) {
+ printf("%s: failed to write to write-protected page\n", __FUNCTION__);
+ return -EPERM;
+ }
+
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
status = chip->errstat(mtd, chip, FL_WRITING, status,
page);
@@ -1777,6 +1821,10 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
} else {
chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
+ if ((~status) & NAND_STATUS_WP) {
+ printf("%s: failed to write to write-protected page\n", __FUNCTION__);
+ return -EPERM;
+ }
}
#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
@@ -2005,7 +2053,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
/* Do not allow write past end of page */
if ((ops->ooboffs + ops->ooblen) > len) {
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: "
- "Attempt to write past end of page\n");
+ "Attempt to write past end of page (%d+%d>%d)\n", ops->ooboffs, ops->ooblen, len);
return -EINVAL;
}
@@ -2249,7 +2297,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
chip->erase_cmd(mtd, page & chip->pagemask);
status = chip->waitfunc(mtd, chip);
-
+
/*
* See if operation failed and additional status checks are
* available
@@ -2258,6 +2306,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
status = chip->errstat(mtd, chip, FL_ERASING,
status, page);
+ /* If block is write-protected, skip to next */
+ if ((~status) & NAND_STATUS_WP) {
+ printk(KERN_WARNING "nand_erase: attempt to erase a "
+ "write-protected block at page 0x%08x\n", page);
+ instr->state = MTD_ERASE_FAILED;
+ goto erase_exit;
+ }
+
/* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) {
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "
@@ -2502,6 +2558,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
return ERR_PTR(-ENODEV);
}
+ chip->maf_id = tmp_manf;
+ chip->dev_id = tmp_id;
+
/* Lookup the flash id */
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (dev_id == nand_flash_ids[i].id) {
@@ -2777,6 +2836,26 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
+ if (chip->has_chip_ecc) {
+ /* Put chip into no-ECC mode */
+ uint8_t params[4] = {0x00, 0x00, 0x00, 0x00};
+ nand_set_feature(mtd, 0x90, params);
+ }
+ break;
+
+ case NAND_ECC_CHIP:
+ chip->ecc.read_page = nand_read_page_raw;
+ chip->ecc.write_page = nand_write_page_raw;
+ chip->ecc.read_oob = nand_read_oob_std;
+ chip->ecc.write_oob = nand_write_oob_std;
+ chip->ecc.size = mtd->writesize;
+ chip->ecc.bytes = 0;
+
+ if (chip->has_chip_ecc) {
+ /* Put chip into ECC mode */
+ uint8_t params[4] = {0x08, 0x00, 0x00, 0x00};
+ nand_set_feature(mtd, 0x90, params);
+ }
break;
case NAND_ECC_NONE:
@@ -2788,6 +2867,13 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.write_oob = nand_write_oob_std;
chip->ecc.size = mtd->writesize;
chip->ecc.bytes = 0;
+
+ if (chip->has_chip_ecc) {
+ /* Put chip into ECC mode */
+ uint8_t params[4] = {0x00, 0x00, 0x00, 0x00};
+ nand_set_feature(mtd, 0x90, params);
+ }
+
break;
default:
@@ -2805,6 +2891,7 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.layout->oobavail +=
chip->ecc.layout->oobfree[i].length;
mtd->oobavail = chip->ecc.layout->oobavail;
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: oobavail %d\n", __FUNCTION__, mtd->oobavail);
/*
* Set the number of read / write steps for one page depending on ECC
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index c866c1210c..7db9b66985 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -339,6 +339,7 @@ int nand_lock(struct mtd_info *mtd, int tight)
int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
{
int ret = 0;
+ int flags = 0;
int chipnr;
int page;
struct nand_chip *chip = mtd->priv;
@@ -360,9 +361,19 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
page = (int)(offset >> chip->page_shift);
chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask);
- ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT
- | NAND_LOCK_STATUS_LOCK
- | NAND_LOCK_STATUS_UNLOCK);
+ ret = chip->read_byte(mtd);
+
+ ret &= (NAND_LOCK_STATUS_TIGHT | NAND_LOCK_STATUS_LOCK | NAND_LOCK_STATUS_UNLOCK);
+
+ if (ret & NAND_LOCK_STATUS_TIGHT)
+ flags |= NAND_LOCK_STATUS_TIGHT;
+
+ if (ret & NAND_LOCK_STATUS_UNLOCK)
+ flags |= NAND_LOCK_STATUS_UNLOCK;
+ else
+ flags |= NAND_LOCK_STATUS_LOCK;
+
+ ret = flags;
out:
/* de-select the NAND device */
@@ -370,6 +381,32 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
return ret;
}
+int nand_get_features(struct mtd_info *mtd, uint8_t faddr, uint8_t *features)
+{
+ struct nand_chip *chip = mtd->priv;
+ int i;
+
+ chip->select_chip(mtd, 0);
+
+ /* Send the status command */
+ chip->cmd_ctrl(mtd, NAND_CMD_GET_FEATURES, NAND_CTRL_CHANGE | NAND_CTRL_CLE);
+
+ /* Send the feature address */
+ chip->cmd_ctrl(mtd, faddr, NAND_CTRL_CHANGE | NAND_CTRL_ALE);
+ /* Switch to data access */
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_CTRL_CHANGE | NAND_NCE);
+
+ ndelay(100);
+
+ for (i=0; i<5; ++i)
+ features[i] = chip->read_byte(mtd);
+
+#if 0
+ printf("%s: %02x %02x %02x %02x %02x\n", __FUNCTION__, features[0],
+ features[1], features[2], features[3], features[4]);
+#endif
+ return 0;
+}
/**
* nand_unlock: - Unlock area of NAND pages
* only one consecutive area can be unlocked at one time!
@@ -388,13 +425,19 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
int status;
int page;
struct nand_chip *chip = mtd->priv;
+#if 0
printf ("nand_unlock: start: %08x, length: %d!\n",
(int)start, (int)length);
-
+#endif
/* select the NAND device */
chipnr = (int)(start >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
+ /* Check the WP bit. To do so requires resetting the device to
+ force the status back to its reset value (so WP becomes whether
+ the WP pin is set). */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
/* check the WP bit */
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) {
@@ -732,7 +775,11 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
.ooblen = meminfo->ecclayout->oobavail,
.oobretlen = 0,
.ooboffs = 0,
+#if 1
+ .datbuf = data_buf,
+#else
.datbuf = NULL,
+#endif
.oobbuf = oob_buf,
};
@@ -744,19 +791,20 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
goto restoreoob;
}
imglen -= meminfo->oobsize;
- }
+ } else {
- /* write out the page data */
- result = meminfo->write(meminfo,
- mtdoffset,
- meminfo->writesize,
- &written,
- (unsigned char *) &data_buf);
+ /* write out the page data */
+ result = meminfo->write(meminfo,
+ mtdoffset,
+ meminfo->writesize,
+ &written,
+ (unsigned char *) &data_buf);
- if (result != 0) {
- printf("writing NAND page at offset 0x%lx failed\n",
- mtdoffset);
- goto restoreoob;
+ if (result != 0) {
+ printf("writing NAND page at offset 0x%lx failed\n",
+ mtdoffset);
+ goto restoreoob;
+ }
}
imglen -= readlen;
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 5624b06677..9590ed920f 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -26,11 +26,13 @@
#include <asm/errno.h>
#include <asm/arch/mem.h>
#include <asm/arch/omap_gpmc.h>
+#include <asm/arch/sys_proto.h>
#include <linux/mtd/nand_ecc.h>
#include <nand.h>
static uint8_t cs;
static struct nand_ecclayout hw_nand_oob = GPMC_NAND_HW_ECC_LAYOUT;
+static struct nand_ecclayout chip_nand_oob = GPMC_NAND_CHIP_ECC_LAYOUT;
/*
* omap_nand_hwcontrol - Set the address pointers corretly for the
@@ -158,6 +160,25 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
return 0;
}
+static int omap_correct_chip_hwecc(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct nand_chip *chip;
+
+ chip = mtd->priv;
+
+ printf("%s: ecc_status %02x\n", __func__, chip->ecc_status);
+ /* We stored the read status in info->ecc_status in the read.
+ If bit 0 is set, then there was an uncorrectable ECC error.
+ If bit 3 is set, then there was a correctable error (up to
+ four bits of correction). */
+ if (chip->ecc_status & 0x01)
+ return -1;
+ if (chip->ecc_status & 0x08)
+ return 4;
+ return 0;
+}
+
/*
* omap_calculate_ecc - Generate non-inverted ECC bytes.
*
@@ -194,6 +215,13 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
+static int omap_calculate_chip_hwecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:\n", __func__);
+ return 0;
+}
+
/*
* omap_enable_ecc - This function enables the hardware ecc functionality
* @mtd: MTD device structure
@@ -226,14 +254,335 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
}
}
+static void omap_enable_chip_hwecc(struct mtd_info *mtd, int mode)
+{
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:\n", __func__);
+}
+
+/*
+ * omap_nand_chip_has_ecc - return true if chip has internal ECC
+ */
+int omap_nand_chip_has_ecc(void)
+{
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ int i;
+ uint8_t ident[5];
+
+ if (nand_curr_device < 0 ||
+ nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[nand_curr_device].name) {
+ printf("Error: Can't switch ecc, no devices available\n");
+ return 0;
+ }
+
+ mtd = &nand_info[nand_curr_device];
+ chip = mtd->priv;
+
+#if 1
+ chip->select_chip(mtd, 0);
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+
+ /* Wait for the chip to get the ID ready */
+ ndelay(100);
+
+ for (i=0; i<2; ++i)
+ ident[i] = chip->read_byte(mtd);
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d %02x %02x\n", __FUNCTION__, __LINE__, ident[0], ident[1]);
+ if (ident[0] == NAND_MFR_MICRON) {
+ for (i=2; i<5; ++i)
+ ident[i] = chip->read_byte(mtd);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d %02x %02x %02x\n", __FUNCTION__, __LINE__, ident[2], ident[3], ident[4]);
+ if (ident[4] & 0x3)
+ chip->has_chip_ecc = 1;
+ }
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: has_chip_ecc %d\n", __FUNCTION__, chip->has_chip_ecc);
+#else
+ if (nand->maf_id == NAND_MFR_MICRON) {
+ switch(nand->dev_id) {
+ case 0x2c:
+ case 0xdc:
+ case 0xcc:
+ case 0xac:
+ case 0xbc:
+ case 0xa3:
+ case 0xb3:
+ case 0xd3:
+ case 0xc3:
+ nand->has_chip_ecc = 1;
+ return 1;
+ default:
+ break;
+ }
+ }
+#endif
+ return chip->has_chip_ecc;
+}
+
+/*
+ * omap_nand_set_features - set the features in the chip
+ * @faddr - features address
+ * @features - array of byts to set as features
+ */
+static void micron_set_features(struct mtd_info *mtd, uint8_t faddr, uint8_t *features)
+{
+ struct nand_chip *chip;
+
+ chip = mtd->priv;
+
+ chip->select_chip(mtd, 0);
+
+ /* Send the status command */
+ omap_nand_hwcontrol(mtd, NAND_CMD_SET_FEATURES, NAND_CTRL_CHANGE | NAND_CTRL_CLE);
+ /* Send the feature address */
+ omap_nand_hwcontrol(mtd, faddr, NAND_CTRL_CHANGE | NAND_CTRL_ALE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE, NAND_CTRL_CHANGE | NAND_NCE);
+
+ ndelay(100);
+ if (chip->options & NAND_BUSWIDTH_16) {
+ uint16_t ftrs16[4];
+ int i;
+ for (i=0; i<4; ++i)
+ ftrs16[i] = features[i];
+ chip->write_buf(mtd, (uint8_t *)ftrs16, sizeof(ftrs16));
+ } else
+ chip->write_buf(mtd, features, 4);
+
+ udelay(2);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: faddr %02x [%02x %02x %02x %02x]\n", __FUNCTION__, faddr, features[0], features[1], features[2], features[3]);
+}
+
+static void micron_set_chip_ecc(struct mtd_info *mtd, int enable)
+{
+ uint8_t params[4];
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3,"%s:%d enable %d\n", __FUNCTION__, __LINE__, enable);
+
+ memset(params, 0x00, sizeof(params));
+ if (enable)
+ params[0] = 0x08;
+ micron_set_features(mtd, 0x90, params);
+
+#if 0
+ micron_get_features(mtd, 0x90, params);
+#endif
+ MTDDEBUG(MTD_DEBUG_LEVEL3,"%s: %02x %02x %02x %02x\n", __FUNCTION__, params[0], params[1], params[2], params[3]);
+}
+
+/**
+ * nand_read_oob_std - [REPLACABLE] the most common OOB data read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ * @sndcmd: flag whether to issue read command or not
+ */
+static int omap_read_oob_chipecc(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ struct nand_chip *nand;
+
+ nand = mtd->priv;
+
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: page = %d, len = %i\n",
+ __func__, page, mtd->oobsize);
+
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ sndcmd = 0;
+ }
+
+ /* Send the status command */
+ omap_nand_hwcontrol(mtd, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ chip->ecc_status = chip->read_byte(mtd);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: ecc_status %02x\n", __func__, chip->ecc_status);
+ if (chip->ecc_status & (0x8|0x1)) {
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d page %d ecc_status %02x\n", __FUNCTION__, __LINE__, page, chip->ecc_status);
+ if (chip->ecc_status & 0x1)
+ mtd->ecc_stats.failed++;
+ else if (chip->ecc_status & 0x80)
+ mtd->ecc_stats.corrected += 4;
+ }
+
+ /* Send the read prefix */
+ omap_nand_hwcontrol(mtd, NAND_CMD_READ0,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ return sndcmd;
+}
+
+/**
+ * omap_nand_command_lp - Send command to NAND large page device
+ * @mtd: MTD device structure
+ * @command: the command to be sent
+ * @column: the column address for this command, -1 if none
+ * @page_addr: the page address for this command, -1 if none
+ *
+ * Send command to NAND device. This is the version for the new large page
+ * devices We dont have the separate regions as we have in the small page
+ * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
+ */
+static void omap_nand_command_lp(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ register struct nand_chip *chip = mtd->priv;
+
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+
+ /* Command latch cycle */
+ omap_nand_hwcontrol(mtd, command & 0xff,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+ if (column != -1 || page_addr != -1) {
+ int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16)
+ column >>= 1;
+ omap_nand_hwcontrol(mtd, column, ctrl);
+ ctrl &= ~NAND_CTRL_CHANGE;
+ omap_nand_hwcontrol(mtd, column >> 8, ctrl);
+ }
+ if (page_addr != -1) {
+ omap_nand_hwcontrol(mtd, page_addr, ctrl);
+ omap_nand_hwcontrol(mtd, page_addr >> 8,
+ NAND_NCE | NAND_ALE);
+ /* One more address cycle for devices > 128MiB */
+ if (chip->chipsize > (128 << 20))
+ omap_nand_hwcontrol(mtd, page_addr >> 16,
+ NAND_NCE | NAND_ALE);
+ }
+ }
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+
+ /*
+ * program and erase have their own busy handlers
+ * status, sequential in, and deplete1 need no delay
+ */
+ switch (command) {
+
+ case NAND_CMD_CACHEDPROG:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_RNDIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_DEPLETE1:
+ return;
+
+ /*
+ * read error status commands require only a short delay
+ */
+ case NAND_CMD_STATUS_ERROR:
+ case NAND_CMD_STATUS_ERROR0:
+ case NAND_CMD_STATUS_ERROR1:
+ case NAND_CMD_STATUS_ERROR2:
+ case NAND_CMD_STATUS_ERROR3:
+ udelay(chip->chip_delay);
+ return;
+
+ case NAND_CMD_RESET:
+ if (chip->dev_ready)
+ break;
+ udelay(chip->chip_delay);
+ omap_nand_hwcontrol(mtd, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
+ return;
+
+ case NAND_CMD_RNDOUT:
+ /* No ready / busy check necessary */
+ omap_nand_hwcontrol(mtd, NAND_CMD_RNDOUTSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ return;
+
+ case NAND_CMD_READ0:
+
+ /* Send the read start */
+ omap_nand_hwcontrol(mtd, NAND_CMD_READSTART,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ /* This applies to read commands */
+ default:
+ /*
+ * If we don't have access to the busy pin, we apply the given
+ * command delay
+ */
+ if (!chip->dev_ready) {
+ udelay(chip->chip_delay);
+ goto ready_exit;
+ }
+ }
+
+ /* Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine. */
+ ndelay(100);
+
+ nand_wait_ready(mtd);
+
+ready_exit:
+ /* If the chip has internal ECC, then we need to read the status
+ to determin if there's an ECC error - capture it for handling by
+ omap_nand_correct_chip_hwecc() later */
+ if (command == NAND_CMD_READ0) {
+ if (chip->has_chip_ecc) {
+
+ /* Send the status command */
+ omap_nand_hwcontrol(mtd, NAND_CMD_STATUS,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+ chip->ecc_status = chip->read_byte(mtd);
+ MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: ecc_status %02x\n", __func__, chip->ecc_status);
+#if 0
+ if (chip->ecc_status & (0x8|0x1))
+ printk("%s:%d page %d column %d ecc_status %02x\n", __FUNCTION__, __LINE__, page_addr, column, chip->ecc_status);
+#endif
+
+ /* Send the read prefix */
+ omap_nand_hwcontrol(mtd, NAND_CMD_READ0,
+ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+ /* Switch to data access */
+ omap_nand_hwcontrol(mtd, NAND_CMD_NONE,
+ NAND_NCE | NAND_CTRL_CHANGE);
+
+ }
+ }
+
+}
+
/*
* omap_nand_switch_ecc - switch the ECC operation b/w h/w ecc and s/w ecc.
* The default is to come up on s/w ecc
*
- * @hardware - 1 -switch to h/w ecc, 0 - s/w ecc
+ * @hardware - 1 -switch to h/w ecc, 0 - s/w ecc, 2 - chip ecc,
*
*/
-void omap_nand_switch_ecc(int32_t hardware)
+void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode)
{
struct nand_chip *nand;
struct mtd_info *mtd;
@@ -260,7 +609,7 @@ void omap_nand_switch_ecc(int32_t hardware)
nand->ecc.calculate = NULL;
/* Setup the ecc configurations again */
- if (hardware) {
+ if (mode == OMAP_ECC_HW) {
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.layout = &hw_nand_oob;
nand->ecc.size = 512;
@@ -269,12 +618,38 @@ void omap_nand_switch_ecc(int32_t hardware)
nand->ecc.correct = omap_correct_data;
nand->ecc.calculate = omap_calculate_ecc;
omap_hwecc_init(nand);
+ if (nand->has_chip_ecc)
+ micron_set_chip_ecc(mtd, 0);
printf("NAND: HW ECC selected\n");
- } else {
+ } else if (mode == OMAP_ECC_SOFT) {
nand->ecc.mode = NAND_ECC_SOFT;
/* Use mtd default settings */
nand->ecc.layout = NULL;
printf("NAND: SW ECC selected\n");
+ if (nand->has_chip_ecc)
+ micron_set_chip_ecc(mtd, 0);
+ } else if (mode == OMAP_ECC_CHIP) {
+ if (!nand->has_chip_ecc) {
+ printf("NAND: Chip does not have internal ECC!\n");
+ return;
+ }
+ nand->ecc.bytes = 0;
+ nand->ecc.size = 2048;
+ nand->ecc.calculate = omap_calculate_chip_hwecc;
+ nand->ecc.hwctl = omap_enable_chip_hwecc;
+ nand->ecc.correct = omap_correct_chip_hwecc;
+ nand->ecc.read_oob = omap_read_oob_chipecc;
+ nand->ecc.mode = NAND_ECC_CHIP; /* internal to chip */
+ nand->ecc.layout = &chip_nand_oob;
+ if (nand->options & NAND_BUSWIDTH_16)
+ nand->cmdfunc = omap_nand_command_lp;
+ else
+ printf("%s: Huh? not 16-bit wide\n", __FUNCTION__);
+ micron_set_chip_ecc(mtd, 1);
+ printf("NAND: Internal to NAND ECC selected\n");
+ } else {
+ printf("NAND: unknown ECC mode %d\n", mode);
+ return;
}
/* Update NAND handling after ECC mode switch */
diff --git a/include/asm-arm/arch-omap3/omap_gpmc.h b/include/asm-arm/arch-omap3/omap_gpmc.h
index bd22bce837..c86448baa8 100644
--- a/include/asm-arm/arch-omap3/omap_gpmc.h
+++ b/include/asm-arm/arch-omap3/omap_gpmc.h
@@ -58,6 +58,25 @@
}
#endif
+/* Micron MT29F4G16ABBDA internal-to-NAND ECC layout */
+#define GPMC_NAND_CHIP_ECC_LAYOUT {\
+ .eccbytes = 32,\
+ .eccpos = {8, 9, 10, 11, 12, 13, 14, 15, \
+ 24, 25, 26, 27, 28, 19, 30, 31, \
+ 40, 41, 42, 43, 44, 45, 46, 47, \
+ 56, 57, 58, 59, 60, 61, 62, 63}, \
+ .oobfree = {\
+ {.offset = 4,\
+ .length = 4 },\
+ {.offset = 20,\
+ .length = 4 },\
+ {.offset = 36,\
+ .length = 4 },\
+ {.offset = 52,\
+ .length = 4 },\
+ } \
+};
+
/* Small Page x8 NAND device Layout */
#ifdef GPMC_NAND_ECC_SP_x8_LAYOUT
#define GPMC_NAND_HW_ECC_LAYOUT {\
diff --git a/include/asm-arm/arch-omap3/sys_proto.h b/include/asm-arm/arch-omap3/sys_proto.h
index 7361d08961..a7a6523a42 100644
--- a/include/asm-arm/arch-omap3/sys_proto.h
+++ b/include/asm-arm/arch-omap3/sys_proto.h
@@ -60,7 +60,15 @@ void sr32(void *, u32, u32, u32);
u32 wait_on_value(u32, u32, void *, u32);
void sdelay(unsigned long);
void make_cs1_contiguous(void);
-void omap_nand_switch_ecc(int);
+
+enum omap_nand_ecc_mode {
+ OMAP_ECC_SOFT = 1,
+ OMAP_ECC_HW,
+ OMAP_ECC_CHIP,
+};
+
+void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode);
+int omap_nand_chip_has_ecc(void);
void power_init_r(void);
void dieid_num_r(void);
diff --git a/include/configs/omap3_logic.h b/include/configs/omap3_logic.h
index 1599eeea28..6dcec746d1 100644
--- a/include/configs/omap3_logic.h
+++ b/include/configs/omap3_logic.h
@@ -114,6 +114,7 @@
#define CONFIG_CMD_I2C /* I2C serial bus support */
#define CONFIG_CMD_MMC /* MMC support */
#define CONFIG_CMD_NAND /* NAND support */
+#define CONFIG_CMD_NAND_LOCK_UNLOCK
#undef CONFIG_CMD_FLASH /* flinfo, erase, protect */
#undef CONFIG_CMD_FPGA /* FPGA configuration Support */
@@ -164,7 +165,6 @@
/* Environment information */
#define CONFIG_BOOTDELAY 10
-#if 1
#define CONFIG_EXTRA_ENV_SETTINGS \
"display=15\0" \
"loadaddr=0x81000000\0" \
@@ -177,55 +177,13 @@
"nfsboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=/dev/nfs rw nfsroot=${serverip}:${rootpath}${nfsoptions} ip=dhcp ${otherbootargs};tftpboot ${loadaddr} ${kernelimage};bootm ${loadaddr}\0" \
"ramboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=/dev/ram rw ramdisk_size=${ramdisksize} ${otherbootargs};tftpboot ${loadaddr} ${kernelimage};tftpboot ${rootfsaddr} rootfs.ext2.gz.uboot;bootm ${loadaddr} ${rootfsaddr}\0" \
"xipboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=/dev/ram rw ramdisk_size=${ramdisksize} ${otherbootargs};bootm ${loadaddr} ${rootfsaddr}\0" \
- "rootdevice=/dev/mtdblock4\0" \
+ "rootdevice=/dev/mtdblock3\0" \
"rootfstype=yaffs\0" \
"mtdboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=${rootdevice} rootfstype=${rootfstype} rw ${otherbootargs};bootm ${loadaddr}\0" \
"sdmtdboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=${rootdevice} rootfstype=${rootfstype} rw ${otherbootargs};mmcinit;fatload mmc0 ${loadaddr} ${kernelimage}; bootm ${loadaddr}\0"
#define CONFIG_BOOTCOMMAND "run xipboot"
-#else
-
-// Beagle ENV_SETTINGS
-#define CONFIG_EXTRA_ENV_SETTINGS \
- "loadaddr=0x82000000\0" \
- "console=ttyS2,115200n8\0" \
- "videomode=1024x768@60,vxres=1024,vyres=768\0" \
- "videospec=omapfb:vram:2M,vram:4M\0" \
- "mmcargs=setenv bootargs console=${console} " \
- "video=${videospec},mode:${videomode} " \
- "root=/dev/mmcblk0p2 rw " \
- "rootfstype=ext3 rootwait\0" \
- "nandargs=setenv bootargs console=${console} " \
- "video=${videospec},mode:${videomode} " \
- "root=/dev/mtdblock4 rw " \
- "rootfstype=jffs2\0" \
- "loadbootscript=fatload mmc 0 ${loadaddr} boot.scr\0" \
- "bootscript=echo Running bootscript from mmc ...; " \
- "source ${loadaddr}\0" \
- "loaduimage=fatload mmc 0 ${loadaddr} uImage\0" \
- "mmcboot=echo Booting from mmc ...; " \
- "run mmcargs; " \
- "bootm ${loadaddr}\0" \
- "nandboot=echo Booting from nand ...; " \
- "run nandargs; " \
- "nand read ${loadaddr} 280000 400000; " \
- "bootm ${loadaddr}\0" \
-
-// Beagle BOOTCOMMAND
-#define CONFIG_BOOTCOMMAND \
- "if mmc init; then " \
- "if run loadbootscript; then " \
- "run bootscript; " \
- "else " \
- "if run loaduimage; then " \
- "run mmcboot; " \
- "else run nandboot; " \
- "fi; " \
- "fi; " \
- "else run nandboot; fi"
-#endif
-
#define CONFIG_PREBOOT \
"echo ======================NOTICE============================;" \
"echo This is the first time that you boot up this board. You are;" \
@@ -330,10 +288,8 @@
#define CONFIG_ENV_OFFSET boot_flash_off
#define CONFIG_ENV_ADDR SMNAND_ENV_OFFSET
-#if 0
#define CONFIG_MTD_DEBUG 1
-#define CONFIG_MTD_DEBUG_VERBOSE 2 // Loud MTD debug messages
-#endif
+#define CONFIG_MTD_DEBUG_VERBOSE -1 // No MTD debug messages
/*-----------------------------------------------------------------------
* CFI FLASH driver setup
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 16556c4798..11c76dc008 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -297,9 +297,10 @@ static inline void mtd_erase_callback(struct erase_info *instr)
#define MTD_DEBUG_LEVEL3 (3) /* Noisy */
#ifdef CONFIG_MTD_DEBUG
+extern int mtd_debug_verbose;
#define MTDDEBUG(n, args...) \
do { \
- if (n <= CONFIG_MTD_DEBUG_VERBOSE) \
+ if (n <= mtd_debug_verbose) \
printk(KERN_INFO args); \
} while(0)
#else /* CONFIG_MTD_DEBUG */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 3e0044b94f..c23c1fd4cc 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -85,6 +85,8 @@ extern void nand_wait_ready(struct mtd_info *mtd);
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
+#define NAND_CMD_SETFEATURE 0xee
+#define NAND_CMD_GETFEATURE 0xef
#define NAND_CMD_RESET 0xff
/* Extended commands for large page devices */
@@ -92,6 +94,11 @@ extern void nand_wait_ready(struct mtd_info *mtd);
#define NAND_CMD_RNDOUTSTART 0xE0
#define NAND_CMD_CACHEDPROG 0x15
+/* Extended commands for ONFI devices */
+#define NAND_CMD_READ_PARAM 0xec
+#define NAND_CMD_GET_FEATURES 0xee
+#define NAND_CMD_SET_FEATURES 0xef
+
/* Extended commands for AG-AND device */
/*
* Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
@@ -128,6 +135,7 @@ typedef enum {
NAND_ECC_SOFT,
NAND_ECC_HW,
NAND_ECC_HW_SYNDROME,
+ NAND_ECC_CHIP,
} nand_ecc_modes_t;
/*
@@ -369,6 +377,10 @@ struct nand_chip {
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
+ uint8_t maf_id, dev_id; /* manufacturer/device identifier */
+ uint8_t has_chip_ecc; /* !0 if chip has internal ECC engine */
+ uint8_t ecc_status; /* status of read w/ECC */
+
uint8_t (*read_byte)(struct mtd_info *mtd);
u16 (*read_word)(struct mtd_info *mtd);
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
diff --git a/include/nand.h b/include/nand.h
index 2a81597a65..03bbce9d5f 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -123,6 +123,8 @@ int nand_lock( nand_info_t *meminfo, int tight );
int nand_unlock( nand_info_t *meminfo, ulong start, ulong length );
int nand_get_lock_status(nand_info_t *meminfo, loff_t offset);
+int nand_get_features( nand_info_t *meminfo, uint8_t faddr, uint8_t *features);
+
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
void board_nand_select_device(struct nand_chip *nand, int chip);
#endif
diff --git a/lib_arm/board.c b/lib_arm/board.c
index f984f6d60d..e9ccb9bec2 100644
--- a/lib_arm/board.c
+++ b/lib_arm/board.c
@@ -47,6 +47,7 @@
#include <net.h>
#include <serial.h>
#include <nand.h>
+#include <asm/arch/sys_proto.h>
#include <onenand_uboot.h>
#include <mmc.h>
@@ -363,9 +364,13 @@ void start_armboot (void)
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
-#endif
#if defined(CONFIG_OMAP3_LOGIC)
- omap_nand_switch_ecc(1); /* switch to HW ECC mode */
+ if (omap_nand_chip_has_ecc()) {
+ omap_nand_switch_ecc(OMAP_ECC_CHIP); /* Use the chip's ECC */
+ } else {
+ omap_nand_switch_ecc(OMAP_ECC_HW); /* switch to HW ECC mode */
+ }
+#endif
#endif
#if defined(CONFIG_CMD_ONENAND)