diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 6783645356..7bd37de78d 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -574,7 +574,15 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &rwsize, - (u_char *)addr); + (u_char *)addr, 0); +#ifdef CONFIG_CMD_NAND_YAFFS + } else if (!strcmp(s, ".yaffs")) { + if (read) { + printf("Unknown nand command suffix '%s'.\n", s); + return 1; + } + ret = nand_write_skip_bad(nand, off, &rwsize, (u_char *)addr, 1); +#endif } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { @@ -680,6 +688,11 @@ U_BOOT_CMD( "nand write - addr off|partition size\n" " read/write 'size' bytes starting at offset 'off'\n" " to/from memory address 'addr', skipping bad blocks.\n" +#ifdef CONFIG_CMD_NAND_YAFFS + "nand write.yaffs - addr off|partition size\n" + " write 'size' bytes starting at offset 'off' with yaffs format\n" + " from memory address 'addr', skipping bad blocks.\n" +#endif "nand erase[.spread] [clean] [off [size]] - erase 'size' bytes " "from offset 'off'\n" " With '.spread', erase enough for given file size, otherwise,\n" diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 22c7411694..8b4f738815 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -447,17 +447,34 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length) * @param nand NAND device * @param offset offset in flash * @param length buffer length - * @param buf buffer to read from + * @param buffer buffer to read from + * @param withoob whether write with yaffs format * @return 0 in case of success */ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - u_char *buffer) + u_char *buffer, int withoob) { - int rval; + int rval = 0, blocksize; size_t left_to_write = *length; u_char *p_buffer = buffer; int need_skip; +#ifdef CONFIG_CMD_NAND_YAFFS + if (withoob) { + int pages; + pages = nand->erasesize / nand->writesize; + blocksize = (pages * nand->oobsize) + nand->erasesize; + if (*length % (nand->writesize + nand->oobsize)) { + printf ("Attempt to write incomplete page" + " in yaffs mode\n"); + return -EINVAL; + } + } else +#endif + { + blocksize = nand->erasesize; + } + /* * nand_write() handles unaligned, partial page writes. * @@ -506,12 +523,44 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, continue; } - if (left_to_write < (nand->erasesize - block_offset)) + if (left_to_write < (blocksize - block_offset)) write_size = left_to_write; else - write_size = nand->erasesize - block_offset; + write_size = blocksize - block_offset; + +#ifdef CONFIG_CMD_NAND_YAFFS + if (withoob) { + int page, pages; + size_t pagesize = nand->writesize; + size_t pagesize_oob = pagesize + nand->oobsize; + struct mtd_oob_ops ops; + + ops.len = pagesize; + ops.ooblen = nand->oobsize; + ops.mode = MTD_OOB_AUTO; + ops.ooboffs = 0; + + pages = write_size / pagesize_oob; + for (page = 0; page < pages; page++) { + ops.datbuf = p_buffer; + ops.oobbuf = ops.datbuf + pagesize; + + rval = nand->write_oob(nand, offset, &ops); + if (!rval) + break; + + offset += pagesize; + p_buffer += pagesize_oob; + } + } + else +#endif + { + rval = nand_write (nand, offset, &write_size, p_buffer); + offset += write_size; + p_buffer += write_size; + } - rval = nand_write (nand, offset, &write_size, p_buffer); if (rval != 0) { printf ("NAND write to offset %llx failed %d\n", offset, rval); @@ -520,8 +569,6 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, } left_to_write -= write_size; - offset += write_size; - p_buffer += write_size; } return 0; diff --git a/include/nand.h b/include/nand.h index a4524113d0..7459bd0330 100644 --- a/include/nand.h +++ b/include/nand.h @@ -115,7 +115,7 @@ typedef struct nand_erase_options nand_erase_options_t; int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, u_char *buffer); int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - u_char *buffer); + u_char *buffer, int withoob); int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); #define NAND_LOCK_STATUS_TIGHT 0x01