[U-Boot] [PATCH 2/3] Add partition based OneNAND commands

Rohit Hagargundgi h.rohit at samsung.com
Thu Dec 11 15:28:35 CET 2008


Add commands which operate on partitions. They are:

 1. onenand partwrite	: Write image / data to partition skipping bad blocks.
 2. onenand partread	: Read image / data from partition skipping bad blocks.
 3. onenand lastslcpart	: Configure Flex-OneNAND boundary to
			  make 'partition' as last SLC partition.

Signed-off-by: Rohit Hagargundgi <h.rohit at samsung.com>
---
 common/cmd_onenand.c |  259 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 259 insertions(+), 0 deletions(-)

diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
index 2caae45..e4e933c 100644
--- a/common/cmd_onenand.c
+++ b/common/cmd_onenand.c
@@ -21,6 +21,191 @@
 extern struct mtd_info onenand_mtd;
 extern struct onenand_chip onenand_chip;
 
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+
+#include <jffs2/jffs2.h>
+
+/* parition handling routines */
+int mtdparts_init(void);
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+		      u8 *part_num, struct part_info **part);
+
+/* get_erasesize - Return erasesize of block in which ofs lies
+ * @param mtd		MTD info structure
+ * @param ofs		offset on flash
+ *
+ * Return erasesize of block in which ofs lies
+ */
+static int get_erasesize(struct mtd_info *mtd, loff_t ofs)
+{
+	struct onenand_chip *this = mtd->priv;
+	unsigned slc = 0;
+
+	onenand_get_block(this, ofs, &slc);
+	if (slc)
+		return 1 << (this->erase_shift - 1);
+	else
+		return 1 << this->erase_shift;
+}
+
+/**
+ * do_part_write - Write image to partition skipping bad blocks
+ * @param addr		offset in memory where image is stored
+ * @param part		partition information structure
+ * @param len		size of image in bytes
+ *
+ * Write data to a partition while skipping bad blocks.
+ * The blocks are erased before writing.
+ * If erase or write fails, the block is marked bad
+ * and writing continues with next block.
+ */
+static int do_part_write(ulong addr, struct part_info *part, size_t len)
+{
+	struct mtd_info *mtd = &onenand_mtd;
+	unsigned ofs;
+	size_t retlen = 0;
+	int thiswrite = 0, thislen;
+	int erasesize, ret;
+	struct erase_info instr = {
+		.callback	= NULL,
+	};
+
+	printf("Write from 0x%x to 0x%x, len 0x%x\n", (unsigned)addr, part->offset, len);
+	if (len > part->size) {
+		printf("Attempt to write image bigger than partition.Failed\n");
+		return -1;
+	}
+
+	/* Round off len to nearest writesize */
+	if (len & (mtd->writesize - 1))
+		len += mtd->writesize - (len & (mtd->writesize - 1));
+
+	ofs = part->offset;
+
+	while (len && (ofs < (part->offset + part->size))) {
+		erasesize = get_erasesize(mtd, ofs);
+
+		ret = mtd->block_isbad(mtd, ofs);
+		if (ret) {
+			printf("Bad block at 0x%x\n", ofs);
+			goto skipbadblock;
+		}
+
+		thiswrite = 0;
+
+		instr.addr = ofs;
+		instr.len = erasesize;
+		ret = mtd->erase(mtd, &instr);
+		if (ret) {
+			printf("Erase failed at 0x%x.\n", ofs);
+			goto markblockbad;
+		}
+
+		thislen = min(len, erasesize);
+		while (thiswrite < thislen) {
+			ret = mtd->write(mtd, ofs, mtd->writesize, &retlen, (u_char *) addr);
+			if (ret || (retlen != mtd->writesize)) {
+				printf("Write failed at 0x%x\n", ofs);
+				goto erasediscard;
+			}
+
+			thiswrite += mtd->writesize;
+			ofs += mtd->writesize;
+			addr += mtd->writesize;
+			len -= mtd->writesize;
+		}
+		continue;
+
+erasediscard:
+		/* Write to this block failed.
+		 * Erase and mark it bad.
+		 */
+		ret = mtd->erase(mtd, &instr);
+		if (ret)
+			printf("Erase failed at 0x%x.\n", instr.addr);
+
+markblockbad:
+		/* Erase to this block failed.
+		 * Mark it bad.
+		 */
+		ret = mtd->block_markbad(mtd, instr.addr);
+		if (!ret)
+			printf("Marked block as bad\n");
+		else
+			printf("Unable to mark block as bad. Failed\n");
+		ofs -= thiswrite;
+		addr -= thiswrite;
+		len += thiswrite;
+
+skipbadblock:
+		/* Bad block at ofs. Skip this block. */
+		ofs += erasesize;
+	}
+
+	if (len) {
+		printf("Image is bigger than usable size in partition. Write failed\n");
+		return -1;
+	}
+
+	printf("Done\n");
+	return 0;
+}
+
+/**
+ * do_part_read - Read image from partition skipping bad blocks
+ * @param addr		offset in memory where image will be copied
+ * @param part		partition information structure
+ * @param len		size of image in bytes
+ *
+ * Read data from a partition while skipping bad blocks.
+ */
+static int do_part_read(ulong addr, struct part_info *part, size_t len)
+{
+	struct mtd_info *mtd = &onenand_mtd;
+	ulong ofs;
+	size_t retlen = 0;
+	int erasesize, ret, toread;
+
+	if (len > part->size) {
+		printf("Attempt to read image bigger than partition.Failed\n");
+		return -1;
+	}
+
+	ofs = part->offset;
+
+	while (len && (ofs < (part->offset + part->size))) {
+		erasesize = get_erasesize(mtd, ofs);
+
+		ret = mtd->block_isbad(mtd, ofs);
+		if (ret)
+			goto readout;
+
+		toread = min(len, erasesize);
+		ret = mtd->read(mtd, ofs, toread, &retlen, (u_char *) addr);
+		if (ret || (retlen != toread)) {
+			printf("Error while reading offset %lu, len %d\n", ofs, toread);
+			return -1;
+		}
+
+		ofs += toread;
+		addr += toread;
+		len -= toread;
+		continue;
+readout:
+		/* Bad block at ofs. Skip this block. */
+		ofs += erasesize;
+	}
+
+	if (len) {
+		printf("Reached end of partition while reading image. Read failed\n");
+		return -1;
+	}
+
+	printf("Done\n");
+	return 0;
+}
+#endif
+
 /**
  * do_set_boundary - [Flex-OneNAND] Set boundary of Flex-OneNAND
  * @param mtd		mtd information structure
@@ -191,6 +376,71 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 			return 0;
 		}
 
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+		if ((strcmp(argv[1], "partread") == 0)
+		     || (strcmp(argv[1], "partwrite") == 0)) {
+			ulong addr = simple_strtoul(argv[3], NULL, 16);
+			size_t len = simple_strtoul(argv[4], NULL, 16);
+			struct mtd_device *device;
+			struct part_info *part;
+			u8 pnum;
+
+			if (mtdparts_init())
+				return -1;
+
+			if (find_dev_and_part(argv[2], &device, &pnum, &part) == 0) {
+				return  (strcmp(argv[1], "partwrite") == 0) ?
+					do_part_write(addr, part, len) :
+					do_part_read(addr, part, len);
+			}
+		}
+		if (strncmp(argv[1], "lastslcpart", 11) == 0) {
+			/*
+			 * this command sets the Flex-OneNAND boundary such that
+			 * all partitions upto and including 'part'(argument)
+			 * turn into SLC area. The remaining area turns into MLC.
+			 */
+			struct mtd_device *device;
+			struct part_info *part;
+			u8 pnum;
+			unsigned offset, bdry;
+			int density, blksperdie;
+			int lock = 0;
+
+			density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+			density &= ONENAND_DEVICE_DENSITY_MASK;
+
+			blksperdie = ((16 << density) << 20) >> this->erase_shift;
+			blksperdie >>= (this->device_id & ONENAND_DEVICE_IS_DDP) ? 1 : 0;
+
+			if (argc == 4 && strncmp(argv[3], "LOCK", 4) == 0)
+				lock = 1;
+
+			if (mtdparts_init())
+				return -1;
+
+			if (find_dev_and_part(argv[2], &device, &pnum, &part))
+				return -1;
+
+			offset = part->offset + part->size - 1;
+
+			bdry = onenand_get_block(this, offset, NULL);
+			if (bdry < blksperdie) {
+				do_set_boundary(mtd, 0, bdry, lock);
+				if (this->dies == 2)
+					/*
+					 * Setting a boundary value of 0
+					 * may cause MLC partitions to
+					 * become unaligned. So set it to 1.
+					 */
+					do_set_boundary(mtd, 1, 1, lock);
+			} else {
+				do_set_boundary(mtd, 0, blksperdie - 1, lock);
+				do_set_boundary(mtd, 1, bdry - blksperdie, lock);
+			}
+			return 0;
+		}
+#endif
 		if (strncmp(argv[1], "setboundary", 11) == 0) {
 			unsigned die = simple_strtoul(argv[2], NULL, 0);
 			unsigned bdry = simple_strtoul(argv[3], NULL, 0);
@@ -220,4 +470,13 @@ U_BOOT_CMD(
 		"read data with (block [, page]) to addr\n"
 	"onenand setboundary DIE BOUNDARY [LOCK] - "
 	"Change SLC boundary of Flex-OneNAND\n"
+#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+	"onenand partread <part-name> <addr> <len>\n"
+	"    - read image from  partition with length len to addr\n"
+	"onenand partwrite <part-name> <addr> <len>\n"
+	"    - write image to  partition with length len from addr\n"
+	"onenand lastslcpart <part-name> [LOCK] - \n"
+	"    - Set Flex-OneNAND boundary such that (partition) is the\n"
+	"      last partition in SLC region\n"
+#endif
 );
-- 
1.5.4.3





More information about the U-Boot mailing list