OneNAND support (take #2)

[PATCH 3/3] OneNAND support (take #2)

OneNAND support at U-Boot

Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
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 */