Add partition based OneNAND commands
PATCH 2/3 Add partition based OneNAND commands
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(-)
common/cmd_onenand.c +259 -0
@@ -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 );
Signature · 1 line
1.5.4.3
PATCH 2/3 Add partition based OneNAND commands
Quoted 6 lines · Rohit Hagargundgi
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.
How much of this is onenand-specific?
-Scott