common/cmd_nand.c: globalized arg_off_size
include/util.h: new header to convenience functions, such as arg_off_size
common/cmd_dynenv.c (do_dynenv): use arg_off_size to sanity-check offset and to
  allow use of partition name
common/cmd_dynenv.c (do_dynenv): indicate in no uncertain terms when an update
  would not work due to Flash bits already cleared
common/cmd_dynenv.c (do_dynenv): update CFG_ENV_OFFSET after successful "dynenv
  set", so that we can write the new environment without having to reboot

- Werner Almesberger <werner@openmoko.org>

Index: u-boot/common/cmd_nand.c
===================================================================
--- u-boot.orig/common/cmd_nand.c
+++ u-boot/common/cmd_nand.c
@@ -100,7 +100,7 @@ static inline int str2long(char *p, ulon
 	return (*p != '\0' && *endptr == '\0') ? 1 : 0;
 }
 
-static int
+int
 arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, ulong *size)
 {
 	int idx = nand_curr_device;
Index: u-boot/include/util.h
===================================================================
--- /dev/null
+++ u-boot/include/util.h
@@ -0,0 +1,33 @@
+/*
+ * util.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <werner@openmoko.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include "nand.h"
+
+
+/* common/cmd_nand.c */
+int arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off,
+  ulong *size);
+
+#endif /* UTIL_H */
Index: u-boot/common/cmd_dynenv.c
===================================================================
--- u-boot.orig/common/cmd_dynenv.c
+++ u-boot/common/cmd_dynenv.c
@@ -23,6 +23,7 @@
 #include <malloc.h>
 #include <environment.h>
 #include <nand.h>
+#include <util.h>
 #include <asm/errno.h>
 
 #if defined(CFG_ENV_OFFSET_OOB)
@@ -39,8 +40,8 @@ int do_dynenv(cmd_tbl_t *cmdtp, int flag
 	if (!buf)
 		return -ENOMEM;
 
+	ret = mtd->read_oob(mtd, 8, size, (size_t *) &size, (u_char *) buf);
 	if (!strcmp(cmd, "get")) {
-		ret = mtd->read_oob(mtd, 8, size, (size_t *) &size, (u_char *) buf);
 
 		if (buf[0] == 'E' && buf[1] == 'N' &&
 		    buf[2] == 'V' && buf[3] == '0')
@@ -49,7 +50,8 @@ int do_dynenv(cmd_tbl_t *cmdtp, int flag
 			printf("No dynamic environment marker in OOB block 0\n");
 
 	} else if (!strcmp(cmd, "set")) {
-		unsigned long addr;
+		unsigned long addr, dummy;
+
 		if (argc < 3)
 			goto usage;
 
@@ -57,7 +59,23 @@ int do_dynenv(cmd_tbl_t *cmdtp, int flag
 		buf[1] = 'N';
 		buf[2] = 'V';
 		buf[3] = '0';
-		addr = simple_strtoul(argv[2], NULL, 16);
+
+		if (arg_off_size(argc-2, argv+2, mtd, &addr, &dummy) < 0) {
+			printf("Offset or partition name expected\n");
+			goto fail;
+		}
+		if (!ret) {
+			uint8_t tmp[4];
+			int i;
+
+			memcpy(&tmp, &addr, 4);
+			for (i = 0; i != 4; i++)
+				if (tmp[i] & ~buf[i+4]) {
+					printf("ERROR: erase OOB block to "
+					  "write this value\n");
+					goto fail;
+				}
+		}
 		memcpy(buf+4, &addr, 4);
 
 		printf("%02x %02x %02x %02x - %02x %02x %02x %02x\n",
@@ -65,6 +83,8 @@ int do_dynenv(cmd_tbl_t *cmdtp, int flag
 			buf[4], buf[5], buf[6], buf[7]);
 
 		ret = mtd->write_oob(mtd, 8, size, (size_t *) &size, (u_char *) buf);
+		if (!ret)
+			CFG_ENV_OFFSET = addr;
 	} else
 		goto usage;
 
@@ -72,8 +92,9 @@ int do_dynenv(cmd_tbl_t *cmdtp, int flag
 	return ret;
 
 usage:
-	free(buf);
 	printf("Usage:\n%s\n", cmdtp->usage);
+fail:
+	free(buf);
 	return 1;
 }
 
