From: Rohit Hagargundgi <h.rohit@samsung.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 2/3] Add partition based OneNAND commands
Date: Thu, 11 Dec 2008 19:58:35 +0530 [thread overview]
Message-ID: <49412393.40100@samsung.com> (raw)
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@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
next reply other threads:[~2008-12-11 14:28 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-12-11 14:28 Rohit Hagargundgi [this message]
2009-01-15 21:14 ` [U-Boot] [PATCH 2/3] Add partition based OneNAND commands Scott Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49412393.40100@samsung.com \
--to=h.rohit@samsung.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.