summaryrefslogtreecommitdiff
path: root/common/cmd_onenand.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/cmd_onenand.c')
-rw-r--r--common/cmd_onenand.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
new file mode 100644
index 0000000..dcda099
--- /dev/null
+++ b/common/cmd_onenand.c
@@ -0,0 +1,155 @@
+/*
+ * U-Boot command for OneNAND support
+ *
+ * Copyright (C) 2005-2007 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>
+
+#ifdef CONFIG_CMD_ONENAND
+
+#include <linux/mtd/compat.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+#include <asm/io.h>
+
+extern struct mtd_info onenand_mtd;
+extern struct onenand_chip onenand_chip;
+
+int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int ret = 0;
+
+ switch (argc) {
+ case 0:
+ case 1:
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+
+ case 2:
+ if (strncmp(argv[1], "open", 4) == 0) {
+ onenand_init();
+ return 0;
+ }
+ onenand_print_device_info(onenand_chip.device_id, 1);
+ return 0;
+
+ default:
+ /* At least 4 args */
+ if (strncmp(argv[1], "erase", 5) == 0) {
+ struct erase_info instr;
+ ulong start, end;
+ ulong block;
+
+ start = simple_strtoul(argv[2], NULL, 10);
+ end = simple_strtoul(argv[3], NULL, 10);
+ start -= (unsigned long)onenand_chip.base;
+ end -= (unsigned long)onenand_chip.base;
+
+ if (!end || end < 0)
+ end = start;
+
+ printf("Erase block from %d to %d\n", start, end);
+
+ for (block = start; block <= end; block++) {
+ instr.addr = block << onenand_chip.erase_shift;
+ instr.len = 1 << onenand_chip.erase_shift;
+ ret = onenand_erase(&onenand_mtd, &instr);
+ if (ret) {
+ printf("erase failed %d\n", block);
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+ if (strncmp(argv[1], "read", 4) == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong ofs = simple_strtoul(argv[3], NULL, 16);
+ size_t len = simple_strtoul(argv[4], NULL, 16);
+ size_t retlen = 0;
+ int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1;
+
+ ofs -= (unsigned long)onenand_chip.base;
+
+ if (oob)
+ onenand_read_oob(&onenand_mtd, ofs, len,
+ &retlen, (u_char *) addr);
+ else
+ onenand_read(&onenand_mtd, ofs, len, &retlen,
+ (u_char *) addr);
+ printf("Done\n");
+
+ return 0;
+ }
+
+ if (strncmp(argv[1], "write", 5) == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong ofs = simple_strtoul(argv[3], NULL, 16);
+ size_t len = simple_strtoul(argv[4], NULL, 16);
+ size_t retlen = 0;
+
+ ofs -= (unsigned long)onenand_chip.base;
+
+ onenand_write(&onenand_mtd, ofs, len, &retlen,
+ (u_char *) addr);
+ printf("Done\n");
+
+ return 0;
+ }
+
+ if (strncmp(argv[1], "block", 5) == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong block = simple_strtoul(argv[3], NULL, 10);
+ ulong page = simple_strtoul(argv[4], NULL, 10);
+ size_t len = simple_strtol(argv[5], NULL, 10);
+ size_t retlen = 0;
+ ulong ofs;
+ int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1;
+
+ ofs = block << onenand_chip.erase_shift;
+ if (page)
+ ofs += page << onenand_chip.page_shift;
+
+ if (!len) {
+ if (oob)
+ len = 64;
+ else
+ len = 512;
+ }
+
+ if (oob)
+ onenand_read_oob(&onenand_mtd, ofs, len,
+ &retlen, (u_char *) addr);
+ else
+ onenand_read(&onenand_mtd, ofs, len, &retlen,
+ (u_char *) addr);
+ return 0;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ onenand, 6, 1, do_onenand,
+ "onenand - OneNAND sub-system\n",
+ "info - show available OneNAND devices\n"
+ "onenand read[.oob] addr ofs len - read data at ofs with len to addr\n"
+ "onenand write addr ofs len - write data at ofs with len from addr\n"
+ "onenand erase saddr eaddr - erase block start addr to end addr\n"
+ "onenand block[.oob] addr block [page] [len] - "
+ "read data with (block [, page]) to addr"
+);
+
+#endif /* CONFIG_CMD_ONENAND */