[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