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 <[EMAIL PROTECTED]>
---
 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



_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to