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