diff options
Diffstat (limited to 'qemu/roms/u-boot/common/cmd_onenand.c')
-rw-r--r-- | qemu/roms/u-boot/common/cmd_onenand.c | 602 |
1 files changed, 0 insertions, 602 deletions
diff --git a/qemu/roms/u-boot/common/cmd_onenand.c b/qemu/roms/u-boot/common/cmd_onenand.c deleted file mode 100644 index 06cc14056..000000000 --- a/qemu/roms/u-boot/common/cmd_onenand.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * U-Boot command for OneNAND support - * - * Copyright (C) 2005-2008 Samsung Electronics - * Kyungmin Park <kyungmin.park@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <common.h> -#include <command.h> -#include <malloc.h> - -#include <linux/compat.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/onenand.h> - -#include <asm/io.h> - -static struct mtd_info *mtd; - -static loff_t next_ofs; -static loff_t skip_ofs; - -static inline int str2long(char *p, ulong *num) -{ - char *endptr; - - *num = simple_strtoul(p, &endptr, 16); - return (*p != '\0' && *endptr == '\0') ? 1 : 0; -} - -static int arg_off_size(int argc, char * const argv[], ulong *off, size_t *size) -{ - if (argc >= 1) { - if (!(str2long(argv[0], off))) { - printf("'%s' is not a number\n", argv[0]); - return -1; - } - } else { - *off = 0; - } - - if (argc >= 2) { - if (!(str2long(argv[1], (ulong *)size))) { - printf("'%s' is not a number\n", argv[1]); - return -1; - } - } else { - *size = mtd->size - *off; - } - - if ((*off + *size) > mtd->size) { - printf("total chip size (0x%llx) exceeded!\n", mtd->size); - return -1; - } - - if (*size == mtd->size) - puts("whole chip\n"); - else - printf("offset 0x%lx, size 0x%x\n", *off, *size); - - return 0; -} - -static int onenand_block_read(loff_t from, size_t len, - size_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, - }; - int ret; - - if (oob) - ops.ooblen = blocksize; - else - ops.len = blocksize; - - 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; - continue; - } - - if (oob) - ops.oobbuf = buf; - else - ops.datbuf = buf; - - ops.retlen = 0; - ret = mtd_read_oob(mtd, ofs, &ops); - if (ret) { - printk("Read failed 0x%x, %d\n", (u32)ofs, ret); - ofs += blocksize; - continue; - } - ofs += blocksize; - buf += blocksize; - blocks--; - *retlen += ops.retlen; - } - - return 0; -} - -static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf, - size_t *retlen) -{ - struct mtd_oob_ops ops = { - .len = mtd->writesize, - .ooblen = mtd->oobsize, - .mode = MTD_OPS_AUTO_OOB, - }; - int page, ret = 0; - for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) { - ops.datbuf = (u_char *)buf; - buf += mtd->writesize; - ops.oobbuf = (u_char *)buf; - buf += mtd->oobsize; - ret = mtd_write_oob(mtd, to, &ops); - if (ret) - break; - to += mtd->writesize; - } - - *retlen = (ret) ? 0 : mtd->erasesize; - return ret; -} - -static int onenand_block_write(loff_t to, size_t len, - size_t *retlen, const u_char * buf, int withoob) -{ - struct onenand_chip *this = mtd->priv; - int blocks = len >> this->erase_shift; - int blocksize = (1 << this->erase_shift); - loff_t ofs; - size_t _retlen = 0; - int ret; - - if (to == next_ofs) { - next_ofs = to + len; - to += skip_ofs; - } else { - next_ofs = to + len; - skip_ofs = 0; - } - ofs = to; - - 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); - skip_ofs += blocksize; - goto next; - } - - if (!withoob) - ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf); - else - ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen); - if (ret) { - printk("Write failed 0x%x, %d", (u32)ofs, ret); - skip_ofs += blocksize; - goto next; - } - - buf += blocksize; - blocks--; - *retlen += _retlen; -next: - ofs += blocksize; - } - - return 0; -} - -static int onenand_block_erase(u32 start, u32 size, int force) -{ - struct onenand_chip *this = mtd->priv; - struct erase_info instr = { - .callback = NULL, - }; - loff_t ofs; - int ret; - int blocksize = 1 << this->erase_shift; - - for (ofs = start; ofs < (start + size); ofs += blocksize) { - ret = mtd_block_isbad(mtd, ofs); - if (ret && !force) { - printf("Skip erase bad block %d at 0x%x\n", - (u32)(ofs >> this->erase_shift), (u32)ofs); - continue; - } - - instr.addr = ofs; - instr.len = blocksize; - instr.priv = force; - instr.mtd = mtd; - ret = mtd_erase(mtd, &instr); - if (ret) { - printf("erase failed block %d at 0x%x\n", - (u32)(ofs >> this->erase_shift), (u32)ofs); - continue; - } - } - - return 0; -} - -static int onenand_block_test(u32 start, u32 size) -{ - struct onenand_chip *this = mtd->priv; - struct erase_info instr = { - .callback = NULL, - .priv = 0, - }; - - int blocks; - loff_t ofs; - int blocksize = 1 << this->erase_shift; - int start_block, end_block; - size_t retlen; - u_char *buf; - u_char *verify_buf; - int ret; - - buf = malloc(blocksize); - if (!buf) { - printf("Not enough malloc space available!\n"); - return -1; - } - - verify_buf = malloc(blocksize); - if (!verify_buf) { - printf("Not enough malloc space available!\n"); - return -1; - } - - start_block = start >> this->erase_shift; - end_block = (start + size) >> this->erase_shift; - - /* Protect boot-loader from badblock testing */ - if (start_block < 2) - start_block = 2; - - if (end_block > (mtd->size >> this->erase_shift)) - end_block = mtd->size >> this->erase_shift; - - blocks = start_block; - ofs = start; - while (blocks < end_block) { - printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs); - - ret = mtd_block_isbad(mtd, ofs); - if (ret) { - printf("Skip erase bad block %d at 0x%x\n", - (u32)(ofs >> this->erase_shift), (u32)ofs); - goto next; - } - - instr.addr = ofs; - instr.len = blocksize; - ret = mtd_erase(mtd, &instr); - if (ret) { - printk("Erase failed 0x%x, %d\n", (u32)ofs, ret); - goto next; - } - - ret = mtd_write(mtd, ofs, blocksize, &retlen, buf); - if (ret) { - printk("Write failed 0x%x, %d\n", (u32)ofs, ret); - goto next; - } - - ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf); - if (ret) { - printk("Read failed 0x%x, %d\n", (u32)ofs, ret); - goto next; - } - - if (memcmp(buf, verify_buf, blocksize)) - printk("\nRead/Write test failed at 0x%x\n", (u32)ofs); - -next: - ofs += blocksize; - blocks++; - } - printf("...Done\n"); - - free(buf); - free(verify_buf); - - return 0; -} - -static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob) -{ - int i; - u_char *datbuf, *oobbuf, *p; - struct mtd_oob_ops ops; - loff_t addr; - - datbuf = malloc(mtd->writesize + mtd->oobsize); - oobbuf = malloc(mtd->oobsize); - if (!datbuf || !oobbuf) { - puts("No memory for page buffer\n"); - return 1; - } - off &= ~(mtd->writesize - 1); - addr = (loff_t) off; - memset(&ops, 0, sizeof(ops)); - ops.datbuf = datbuf; - ops.oobbuf = oobbuf; - ops.len = mtd->writesize; - ops.ooblen = mtd->oobsize; - ops.retlen = 0; - i = mtd_read_oob(mtd, addr, &ops); - if (i < 0) { - printf("Error (%d) reading page %08lx\n", i, off); - free(datbuf); - free(oobbuf); - return 1; - } - printf("Page %08lx dump:\n", off); - i = mtd->writesize >> 4; - p = datbuf; - - while (i--) { - if (!only_oob) - printf("\t%02x %02x %02x %02x %02x %02x %02x %02x" - " %02x %02x %02x %02x %02x %02x %02x %02x\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], - p[8], p[9], p[10], p[11], p[12], p[13], p[14], - p[15]); - p += 16; - } - puts("OOB:\n"); - i = mtd->oobsize >> 3; - p = oobbuf; - - while (i--) { - printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - p += 8; - } - free(datbuf); - free(oobbuf); - - return 0; -} - -static int do_onenand_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - printf("%s\n", mtd->name); - return 0; -} - -static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - ulong ofs; - - mtd = &onenand_mtd; - /* Currently only one OneNAND device is supported */ - printf("\nDevice %d bad blocks:\n", 0); - for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) { - if (mtd_block_isbad(mtd, ofs)) - printf(" %08x\n", (u32)ofs); - } - - return 0; -} - -static int do_onenand_read(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - char *s; - int oob = 0; - ulong addr, ofs; - size_t len; - int ret = 0; - size_t retlen = 0; - - if (argc < 3) - return CMD_RET_USAGE; - - s = strchr(argv[0], '.'); - if ((s != NULL) && (!strcmp(s, ".oob"))) - oob = 1; - - addr = (ulong)simple_strtoul(argv[1], NULL, 16); - - printf("\nOneNAND read: "); - if (arg_off_size(argc - 2, argv + 2, &ofs, &len) != 0) - return 1; - - ret = onenand_block_read(ofs, len, &retlen, (u8 *)addr, oob); - - printf(" %d bytes read: %s\n", retlen, ret ? "ERROR" : "OK"); - - return ret == 0 ? 0 : 1; -} - -static int do_onenand_write(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - ulong addr, ofs; - size_t len; - int ret = 0, withoob = 0; - size_t retlen = 0; - - if (argc < 3) - return CMD_RET_USAGE; - - if (strncmp(argv[0] + 6, "yaffs", 5) == 0) - withoob = 1; - - addr = (ulong)simple_strtoul(argv[1], NULL, 16); - - printf("\nOneNAND write: "); - if (arg_off_size(argc - 2, argv + 2, &ofs, &len) != 0) - return 1; - - ret = onenand_block_write(ofs, len, &retlen, (u8 *)addr, withoob); - - printf(" %d bytes written: %s\n", retlen, ret ? "ERROR" : "OK"); - - return ret == 0 ? 0 : 1; -} - -static int do_onenand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - ulong ofs; - int ret = 0; - size_t len; - int force; - - /* - * Syntax is: - * 0 1 2 3 4 - * onenand erase [force] [off size] - */ - argc--; - argv++; - if (argc) - { - if (!strcmp("force", argv[0])) - { - force = 1; - argc--; - argv++; - } - } - printf("\nOneNAND erase: "); - - /* skip first two or three arguments, look for offset and size */ - if (arg_off_size(argc, argv, &ofs, &len) != 0) - return 1; - - ret = onenand_block_erase(ofs, len, force); - - printf("%s\n", ret ? "ERROR" : "OK"); - - return ret == 0 ? 0 : 1; -} - -static int do_onenand_test(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - ulong ofs; - int ret = 0; - size_t len; - - /* - * Syntax is: - * 0 1 2 3 4 - * onenand test [force] [off size] - */ - - printf("\nOneNAND test: "); - - /* skip first two or three arguments, look for offset and size */ - if (arg_off_size(argc - 1, argv + 1, &ofs, &len) != 0) - return 1; - - ret = onenand_block_test(ofs, len); - - printf("%s\n", ret ? "ERROR" : "OK"); - - return ret == 0 ? 0 : 1; -} - -static int do_onenand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - ulong ofs; - int ret = 0; - char *s; - - if (argc < 2) - return CMD_RET_USAGE; - - s = strchr(argv[0], '.'); - ofs = (int)simple_strtoul(argv[1], NULL, 16); - - if (s != NULL && strcmp(s, ".oob") == 0) - ret = onenand_dump(mtd, ofs, 1); - else - ret = onenand_dump(mtd, ofs, 0); - - return ret == 0 ? 1 : 0; -} - -static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - int ret = 0; - ulong addr; - - argc -= 2; - argv += 2; - - if (argc <= 0) - return CMD_RET_USAGE; - - while (argc > 0) { - addr = simple_strtoul(*argv, NULL, 16); - - if (mtd_block_markbad(mtd, addr)) { - printf("block 0x%08lx NOT marked " - "as bad! ERROR %d\n", - addr, ret); - ret = 1; - } else { - printf("block 0x%08lx successfully " - "marked as bad\n", - addr); - } - --argc; - ++argv; - } - return ret; -} - -static cmd_tbl_t cmd_onenand_sub[] = { - U_BOOT_CMD_MKENT(info, 1, 0, do_onenand_info, "", ""), - U_BOOT_CMD_MKENT(bad, 1, 0, do_onenand_bad, "", ""), - U_BOOT_CMD_MKENT(read, 4, 0, do_onenand_read, "", ""), - U_BOOT_CMD_MKENT(write, 4, 0, do_onenand_write, "", ""), - U_BOOT_CMD_MKENT(write.yaffs, 4, 0, do_onenand_write, "", ""), - U_BOOT_CMD_MKENT(erase, 3, 0, do_onenand_erase, "", ""), - U_BOOT_CMD_MKENT(test, 3, 0, do_onenand_test, "", ""), - U_BOOT_CMD_MKENT(dump, 2, 0, do_onenand_dump, "", ""), - U_BOOT_CMD_MKENT(markbad, CONFIG_SYS_MAXARGS, 0, do_onenand_markbad, "", ""), -}; - -#ifdef CONFIG_NEEDS_MANUAL_RELOC -void onenand_reloc(void) { - fixup_cmdtable(cmd_onenand_sub, ARRAY_SIZE(cmd_onenand_sub)); -} -#endif - -static int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) -{ - cmd_tbl_t *c; - - if (argc < 2) - return CMD_RET_USAGE; - - mtd = &onenand_mtd; - - /* Strip off leading 'onenand' command argument */ - argc--; - argv++; - - c = find_cmd_tbl(argv[0], &cmd_onenand_sub[0], ARRAY_SIZE(cmd_onenand_sub)); - - if (c) - return c->cmd(cmdtp, flag, argc, argv); - else - return CMD_RET_USAGE; -} - -U_BOOT_CMD( - onenand, CONFIG_SYS_MAXARGS, 1, do_onenand, - "OneNAND sub-system", - "info - show available OneNAND devices\n" - "onenand bad - show bad blocks\n" - "onenand read[.oob] addr off size\n" - "onenand write[.yaffs] addr off size\n" - " read/write 'size' bytes starting at offset 'off'\n" - " to/from memory address 'addr', skipping bad blocks.\n" - "onenand erase [force] [off size] - erase 'size' bytes from\n" - "onenand test [off size] - test 'size' bytes from\n" - " offset 'off' (entire device if not specified)\n" - "onenand dump[.oob] off - dump page\n" - "onenand markbad off [...] - mark bad block(s) at offset (UNSAFE)" -); |