
Now OneNAND handles block operation only. With this patch OneNAND handles all read/write size.
Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c index 9090940..2b8f01b 100644 --- a/common/cmd_onenand.c +++ b/common/cmd_onenand.c @@ -36,7 +36,7 @@ static inline int str2long(char *p, ulong *num) return (*p != '\0' && *endptr == '\0') ? 1 : 0; }
-static int arg_off_size(int argc, char *argv[], ulong *off, size_t *size) +static int arg_off_size(int argc, char *argv[], ulong *off, ssize_t *size) { if (argc >= 1) { if (!(str2long(argv[0], off))) { @@ -69,61 +69,65 @@ static int arg_off_size(int argc, char *argv[], ulong *off, size_t *size) return 0; }
-static int onenand_block_read(loff_t from, size_t len, - size_t *retlen, u_char *buf, int oob) +static int onenand_block_read(loff_t from, ssize_t len, + ssize_t *retlen, u_char *buf, int oob) { struct onenand_chip *this = mtd->priv; - int blocks = (int) len >> this->erase_shift; int blocksize = (1 << this->erase_shift); loff_t ofs = from; struct mtd_oob_ops ops = { .retlen = 0, }; + ssize_t thislen; int ret;
- if (oob) - ops.ooblen = blocksize; - else - ops.len = blocksize; + while (len > 0) { + thislen = min_t(ssize_t, len, blocksize); + thislen = ALIGN(thislen, mtd->writesize);
- while (blocks) { ret = mtd->block_isbad(mtd, ofs); if (ret) { printk("Bad blocks %d at 0x%x\n", (u32)(ofs >> this->erase_shift), (u32)ofs); - ofs += blocksize; + ofs += thislen; continue; }
- if (oob) + if (oob) { ops.oobbuf = buf; - else + ops.ooblen = thislen; + } else { ops.datbuf = buf; + ops.len = thislen; + }
ops.retlen = 0; ret = mtd->read_oob(mtd, ofs, &ops); if (ret) { printk("Read failed 0x%x, %d\n", (u32)ofs, ret); - ofs += blocksize; + ofs += thislen; continue; } - ofs += blocksize; - buf += blocksize; - blocks--; + ofs += thislen; + buf += thislen; + len -= thislen; *retlen += ops.retlen; }
return 0; }
-static int onenand_block_write(loff_t to, size_t len, - size_t *retlen, const u_char * buf) +static int onenand_block_write(loff_t to, ssize_t len, + ssize_t *retlen, const u_char * buf) { struct onenand_chip *this = mtd->priv; - int blocks = len >> this->erase_shift; int blocksize = (1 << this->erase_shift); + struct mtd_oob_ops ops = { + .retlen = 0, + .oobbuf = NULL, + }; loff_t ofs; - size_t _retlen = 0; + ssize_t thislen; int ret;
if (to == next_ofs) { @@ -135,27 +139,34 @@ static int onenand_block_write(loff_t to, size_t len, } ofs = to;
- while (blocks) { + while (len > 0) { + thislen = min_t(ssize_t, len, blocksize); + thislen = ALIGN(thislen, mtd->writesize); + ret = mtd->block_isbad(mtd, ofs); if (ret) { printk("Bad blocks %d at 0x%x\n", (u32)(ofs >> this->erase_shift), (u32)ofs); - skip_ofs += blocksize; + skip_ofs += thislen; goto next; }
- ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf); + + ops.datbuf = (u_char *) buf; + ops.len = thislen; + ops.retlen = 0; + ret = mtd->write_oob(mtd, ofs, &ops); if (ret) { printk("Write failed 0x%x, %d", (u32)ofs, ret); - skip_ofs += blocksize; + skip_ofs += thislen; goto next; }
- buf += blocksize; - blocks--; - *retlen += _retlen; + buf += thislen; + len -= thislen; + *retlen += ops.retlen; next: - ofs += blocksize; + ofs += thislen; }
return 0; @@ -234,7 +245,7 @@ static int onenand_block_test(u32 start, u32 size) end_block = mtd->size >> this->erase_shift;
blocks = start_block; - ofs = start; + ofs = start_block << this->erase_shift; while (blocks < end_block) { printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs);
@@ -265,9 +276,10 @@ static int onenand_block_test(u32 start, u32 size) goto next; }
- if (memcmp(buf, verify_buf, blocksize)) + if (memcmp(buf, verify_buf, blocksize)) { printk("\nRead/Write test failed at 0x%x\n", (u32)ofs); - + break; + } next: ofs += blocksize; blocks++; @@ -322,6 +334,7 @@ static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob) p += 16; } puts("OOB:\n"); + p = oobbuf; i = mtd->oobsize >> 3; while (i--) { printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", @@ -339,7 +352,7 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) struct onenand_chip *this; int blocksize; ulong addr, ofs; - size_t len, retlen = 0; + ssize_t len, retlen = 0; int ret = 0; char *cmd, *s;
@@ -385,7 +398,8 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) int erase;
erase = strcmp(cmd, "erase") == 0; /* 1 = erase, 0 = test */ - printf("\nOneNAND %s: ", erase ? "erase" : "test"); + printf("\nOneNAND %s %s: ", erase ? "erase" : "test", + force ? "force" : "");
/* skip first two or three arguments, look for offset and size */ if (arg_off_size(argc - o, argv + o, &ofs, &len) != 0)