[U-Boot] [PATCH] Bad Block Capable environment for OneNAND

apgmoorthy moorthy.apg at samsung.com
Mon Apr 13 15:04:52 CEST 2009


Hi,
       With OneNAND ipl reading CONFIG_SYS_MONITOR_LEN , Environment Area should start after CONFIG_SYS_MONITOR_LEN.
Environment is made Bad Block cpapable too. These are done in the patch.
And fix 'onenand test' command to skip Bootloader and Environment Blocks.

With Regards
  Moorthy

Makes Environment to start after CONFIG_SYS_MONITOR_LEN
Environment is made to be Bad Block aware/capable.
Fix 'onenand test' command to skip Bootloader and Environment Blocks.

 Signed-off-by: Rohit Hagargundgi <h.rohit at samsung.com>
 Signed-off-by: Gangheyamoorthy   <moorthy.apg at samsung.com>
---
 common/cmd_onenand.c      |   12 ++++--
 common/env_onenand.c      |   96 +++++++++++++++++++++++++++++++++------------
 include/configs/apollon.h |    2 +-
 include/onenand_uboot.h   |    4 ++
 4 files changed, 84 insertions(+), 30 deletions(-)

diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
index 5832ff8..c366935 100644
--- a/common/cmd_onenand.c
+++ b/common/cmd_onenand.c
@@ -206,6 +206,7 @@ static int onenand_block_test(u32 start, u32 size)
 	u_char *buf;
 	u_char *verify_buf;
 	int ret;
+	int badblocklen = 0;
 
 	buf = malloc(blocksize);
 	if (!buf) {
@@ -219,13 +220,16 @@ static int onenand_block_test(u32 start, u32 size)
 		return -1;
 	}
 
+	/* Protect boot-loader and environment variables from badblock testing */
+	while (start < CONFIG_SYS_MONITOR_LEN + CONFIG_ENV_SIZE + badblocklen) {
+		if (mtd->block_isbad(&onenand_mtd, start))
+			badblocklen += blocksize;
+		start += blocksize;
+	}
+
 	start_block = start >> this->erase_shift;
 	end_block = (start + size) >> this->erase_shift;
 
-	/* Protect boot-loader from badblock testing */
-	if (start_block < 2)
-		start_block = 2;
-
 	if (end_block > (mtd->size >> this->erase_shift))
 		end_block = mtd->size >> this->erase_shift;
 
diff --git a/common/env_onenand.c b/common/env_onenand.c
index dbccc79..76e3aa8 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -39,6 +39,16 @@ extern uchar default_environment[];
 
 #define ONENAND_ENV_SIZE(mtd)	(mtd.writesize - ENV_HEADER_SIZE)
 
+/*
+ * User can give many blocks to environment variable partition
+ * through CONFIG_ENV_SIZE macro.
+ * The variables are written to first block in the partition. If this block
+ * goes bad, the successive block is used to store environment variables.
+ *
+ */
+
+#define ONENAND_ENV_END   (CONFIG_SYS_MONITOR_LEN + CONFIG_ENV_SIZE)
+
 char *env_name_spec = "OneNAND";
 
 #ifdef ENV_IS_EMBEDDED
@@ -58,23 +68,31 @@ uchar env_get_char_spec(int index)
 
 void env_relocate_spec(void)
 {
-	unsigned long env_addr;
-	int use_default = 0;
+	unsigned long env_addr = CONFIG_SYS_MONITOR_LEN;
+	int use_default = 1;
 	size_t retlen;
+	int blocksize = onenand_mtd.erasesize;
 
-	env_addr = CONFIG_ENV_ADDR;
+	/* Find environment block. */
+	while (onenand_mtd.writesize && (env_addr < ONENAND_ENV_END)) {
+		if (onenand_block_isbad(&onenand_mtd, env_addr)) {
+			printf("Skip bad block at 0x%x\n", (u32)env_addr);
+			env_addr += blocksize;
+			continue;
+		}
 
-	/* Check OneNAND exist */
-	if (onenand_mtd.writesize)
 		/* Ignore read fail */
 		onenand_read(&onenand_mtd, env_addr, onenand_mtd.writesize,
 			     &retlen, (u_char *) env_ptr);
-	else
-		onenand_mtd.writesize = MAX_ONENAND_PAGESIZE;
 
-	if (crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd)) !=
-	    env_ptr->crc)
-		use_default = 1;
+		if (crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd)) ==
+		    env_ptr->crc) {
+			printf("OneNAND: Read environment from 0x%x\n", (u32)env_addr);
+			use_default = 0;
+			break;
+		}
+		env_addr += blocksize;
+	}
 
 	if (use_default) {
 		memcpy(env_ptr->data, default_environment,
@@ -89,31 +107,59 @@ void env_relocate_spec(void)
 
 int saveenv(void)
 {
-	unsigned long env_addr = CONFIG_ENV_ADDR;
+	unsigned long env_addr = 0, badblocklen = 0;
 	struct erase_info instr = {
-		.callback	= NULL,
+		 .callback	= NULL,
 	};
 	size_t retlen;
+	int blocksize = onenand_mtd.erasesize;
 
-	instr.len = CONFIG_ENV_SIZE;
-	instr.addr = env_addr;
-	instr.mtd = &onenand_mtd;
-	if (onenand_erase(&onenand_mtd, &instr)) {
-		printf("OneNAND: erase failed at 0x%08lx\n", env_addr);
+	/* Skip bootloader area. */
+	while (env_addr < CONFIG_SYS_MONITOR_LEN + badblocklen) {
+		if (onenand_block_isbad(&onenand_mtd, env_addr))
+			badblocklen += blocksize;
+		env_addr += blocksize;
+	}
+
+	/* Skip any bad blocks */
+	while (onenand_block_isbad(&onenand_mtd, env_addr)) {
+		printf("Skip bad block at 0x%x\n", (u32)env_addr);
+		env_addr += blocksize;
+	}
+
+	 /* update crc */
+	 env_ptr->crc =
+	     crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd));
+
+retry:
+	if (env_addr >= ONENAND_ENV_END) {
+		printf("OneNAND: Saving environment failed\n");
 		return 1;
 	}
 
-	/* update crc */
-	env_ptr->crc =
-	    crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd));
+	instr.len = blocksize;
+	instr.addr = env_addr;
+	instr.mtd = &onenand_mtd;
 
-	if (onenand_write(&onenand_mtd, env_addr, onenand_mtd.writesize, &retlen,
-	     (u_char *) env_ptr)) {
-		printf("OneNAND: write failed at 0x%08x\n", instr.addr);
-		return 2;
+	/* Erase the environment block */
+	while (onenand_erase(&onenand_mtd, &instr)) {
+		onenand_block_markbad(&onenand_mtd, env_addr);
+		env_addr += blocksize;
+		instr.addr += blocksize;
 	}
 
-	return 0;
+	/* Write the environment variables*/
+	if (onenand_write(&onenand_mtd, env_addr, onenand_mtd.writesize,
+	    &retlen, (u_char *) env_ptr)) {
+		/* Mark block bad and try the next one */
+		onenand_block_markbad(&onenand_mtd, env_addr);
+		env_addr += blocksize;
+		goto retry;
+	}
+
+	printf("OneNAND: Saved environment to 0x%x\n", (u32)env_addr);
+
+	 return 0;
 }

 int env_init(void)
diff --git a/include/configs/apollon.h b/include/configs/apollon.h
index 2e8198f..cf41e01 100644
--- a/include/configs/apollon.h
+++ b/include/configs/apollon.h
@@ -75,7 +75,7 @@
 /*
  * Size of malloc() pool
  */
-#define	CONFIG_ENV_SIZE SZ_128K	/* Total Size of Environment Sector */
+#define	CONFIG_ENV_SIZE SZ_256K	/* Total Size of Environment Sector */
 #define	CONFIG_SYS_MALLOC_LEN	(CONFIG_ENV_SIZE + SZ_1M)
 /* bytes reserved for initial data */
 #define	CONFIG_SYS_GBL_DATA_SIZE	128
diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h
index 49da9d0..dbac25b 100644
--- a/include/onenand_uboot.h
+++ b/include/onenand_uboot.h
@@ -38,6 +38,10 @@ extern int onenand_erase(struct mtd_info *mtd, struct erase_info *instr);
 
 extern char *onenand_print_device_info(int device, int version);
 
+extern int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs);
+
+extern int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs);
+
 /* S3C64xx */
 extern void s3c64xx_onenand_init(struct mtd_info *);
 extern void s3c64xx_set_width_regs(struct onenand_chip *);



More information about the U-Boot mailing list