summaryrefslogtreecommitdiffstats
path: root/common/cmd_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/cmd_nand.c')
-rw-r--r--common/cmd_nand.c109
1 files changed, 108 insertions, 1 deletions
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index ea80555ef8..84b6272950 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -4,6 +4,10 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
+ * Ported 'dynenv' to 'nand env.oob' command
+ * (C) 2010 Nanometrics, Inc.
+ * 'dynenv' -- Dynamic environment offset in NAND OOB
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
* Added 16-bit nand support
* (C) 2004 Texas Instruments
*/
@@ -193,6 +197,90 @@ static void do_nand_status(nand_info_t *nand)
}
#endif
+#ifdef CONFIG_ENV_OFFSET_OOB
+unsigned long nand_env_oob_offset;
+
+int do_nand_env_oob(cmd_tbl_t *cmdtp, nand_info_t *nand,
+ int argc, char * const argv[])
+{
+ int ret;
+ uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+
+ char *cmd = argv[1];
+
+ if (!strcmp(cmd, "get")) {
+ ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+ if (ret)
+ return 1;
+
+ printf("0x%08lx\n", nand_env_oob_offset);
+ } else if (!strcmp(cmd, "set")) {
+ ulong addr;
+ size_t dummy_size;
+ struct mtd_oob_ops ops;
+
+ if (argc < 3)
+ goto usage;
+
+ if (arg_off_size(argc - 2, argv + 2, nand, &addr,
+ &dummy_size) < 0) {
+ printf("Offset or partition name expected\n");
+ return 1;
+ }
+
+ if (nand->oobavail < ENV_OFFSET_SIZE) {
+ printf("Insufficient available OOB bytes:\n"
+ "%d OOB bytes available but %d required for "
+ "env.oob support\n",
+ nand->oobavail, ENV_OFFSET_SIZE);
+ return 1;
+ }
+
+ if ((addr & (nand->erasesize - 1)) != 0) {
+ printf("Environment offset must be block-aligned\n");
+ return 1;
+ }
+
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooboffs = 0;
+ ops.ooblen = ENV_OFFSET_SIZE;
+ ops.oobbuf = (void *) oob_buf;
+
+ oob_buf[0] = ENV_OOB_MARKER;
+ oob_buf[1] = addr / nand->erasesize;
+
+ ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops);
+ if (ret) {
+ printf("Error writing OOB block 0\n");
+ return ret;
+ }
+
+ ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+ if (ret) {
+ printf("Error reading env offset in OOB\n");
+ return ret;
+ }
+
+ if (addr != nand_env_oob_offset) {
+ printf("Verification of env offset in OOB failed: "
+ "0x%08lx expected but got 0x%08lx\n",
+ addr, nand_env_oob_offset);
+ return 1;
+ }
+ } else {
+ goto usage;
+ }
+
+ return ret;
+
+usage:
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+#endif
+
static void nand_print_info(int idx)
{
nand_info_t *nand = &nand_info[idx];
@@ -272,9 +360,21 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const 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
+#ifdef CONFIG_ENV_OFFSET_OOB
+ && strcmp(cmd, "env.oob") != 0
+#endif
+ )
goto usage;
+#ifdef CONFIG_ENV_OFFSET_OOB
+ /* this command operates only on the first nand device */
+ if (strcmp(cmd, "env.oob") == 0) {
+ return do_nand_env_oob(cmdtp, &nand_info[0],
+ argc - 1, argv + 1);
+ }
+#endif
+
/* the following commands operate on the current device */
if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
!nand_info[nand_curr_device].name) {
@@ -502,6 +602,13 @@ U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,
" bring nand to lock state or display locked pages\n"
"nand unlock [offset] [size] - unlock section"
#endif
+#ifdef CONFIG_ENV_OFFSET_OOB
+ "\n"
+ "nand env.oob - environment offset in OOB of block 0 of"
+ " first device.\n"
+ "nand env.oob set off|partition - set enviromnent offset\n"
+ "nand env.oob get - get environment offset"
+#endif
);
static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,