summaryrefslogtreecommitdiffstats
path: root/common/env_nand.c
diff options
context:
space:
mode:
authorBen Gardiner <bengardiner@nanometrics.ca>2010-07-05 13:27:07 -0400
committerScott Wood <scottwood@freescale.com>2010-07-12 13:56:46 -0500
commitc9f7351b5bb70d292f6b0baaf0e21366e0b0b163 (patch)
tree19b4353d9a4c5428b486e19f803c1855107cd76f /common/env_nand.c
parent67ceefa79b86d9d72b7487005a6a8a61cd6a1d66 (diff)
downloadblackbird-obmc-uboot-c9f7351b5bb70d292f6b0baaf0e21366e0b0b163.tar.gz
blackbird-obmc-uboot-c9f7351b5bb70d292f6b0baaf0e21366e0b0b163.zip
NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
This is a re-submission of the patch by Harald Welte <laforge@openmoko.org> with minor modifications for rebase and changes as suggested by Scott Wood <scottwood@freescale.com> [1] [2]. This patch enables the environment partition to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition. With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block. This patch introduces the 'nand env.oob' command, which can be called from the u-boot command line. 'nand env.oob get' reads the address of the environment partition from the OOB data, 'nand env.oob set {offset,partition-name}' allows the setting of the marker by specifying a numeric offset or a partition name. [1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43916 [2] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/79195 Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca> Acked-by: Harald Welte <laforge@gnumonks.org>
Diffstat (limited to 'common/env_nand.c')
-rw-r--r--common/env_nand.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/common/env_nand.c b/common/env_nand.c
index 50bc111a3b..47d9848acb 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -38,6 +38,7 @@
#include <linux/stddef.h>
#include <malloc.h>
#include <nand.h>
+#include <asm/errno.h>
#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
#define CMD_SAVEENV
@@ -284,6 +285,40 @@ int readenv (size_t offset, u_char * buf)
return 0;
}
+#ifdef CONFIG_ENV_OFFSET_OOB
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
+{
+ struct mtd_oob_ops ops;
+ uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+ int ret;
+
+ ops.datbuf = NULL;
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooboffs = 0;
+ ops.ooblen = ENV_OFFSET_SIZE;
+ ops.oobbuf = (void *) oob_buf;
+
+ ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
+
+ if (!ret) {
+ if (oob_buf[0] == ENV_OOB_MARKER) {
+ *result = oob_buf[1] * nand->erasesize;
+ } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
+ *result = oob_buf[1];
+ } else {
+ printf("No dynamic environment marker in OOB block 0"
+ "\n");
+ ret = -ENOENT;
+ goto fail;
+ }
+ } else {
+ printf("error reading OOB block 0\n");
+ }
+fail:
+ return ret;
+}
+#endif
+
#ifdef CONFIG_ENV_OFFSET_REDUND
void env_relocate_spec (void)
{
@@ -353,6 +388,17 @@ void env_relocate_spec (void)
#if !defined(ENV_IS_EMBEDDED)
int ret;
+#if defined(CONFIG_ENV_OFFSET_OOB)
+ ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
+ /* If unable to read environment offset from NAND OOB then fall through
+ * to the normal environment reading code below
+ */
+ if (!ret)
+ printf("Found Environment offset in OOB..\n");
+ else
+ return use_default();
+#endif
+
ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
if (ret)
return use_default();
OpenPOWER on IntegriCloud