cmd/mtd.c is a generic command to access all low level
MTD devices, like SPI-NOR, Parallel NOR and NAND.

This is implemented based on u-boot driver model, so any
new driver added for using this command must follow dm principles.

Signed-off-by: Jagan Teki <ja...@openedev.com>
---
 cmd/Kconfig              |   6 +
 cmd/Makefile             |   1 +
 cmd/mtd.c                | 285 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/Makefile     |   2 +-
 drivers/mtd/mtd-uclass.c |  17 +++
 include/mtd.h            |   9 ++
 6 files changed, 319 insertions(+), 1 deletion(-)
 create mode 100644 cmd/mtd.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 86554ea..9386692 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -706,6 +706,12 @@ config CMD_FS_GENERIC
          fs types.
 endmenu
 
+config CMD_MTD
+       bool "Generic command for accessing MTD devices"
+       help
+         Command to support MTD devices accessing.
+         MTD devices like SPI-NOR, Parallel NOR and NAND.
+
 config CMD_UBI
        tristate "Enable UBI - Unsorted block images commands"
        select CRC32
diff --git a/cmd/Makefile b/cmd/Makefile
index 81b98ee..d50a405 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_CMD_MISC) += misc.o
 obj-$(CONFIG_CMD_MMC) += mmc.o
 obj-$(CONFIG_CMD_MMC_SPI) += mmc_spi.o
 obj-$(CONFIG_MP) += mp.o
+obj-$(CONFIG_CMD_MTD) += mtd.o
 obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
 obj-$(CONFIG_CMD_NAND) += nand.o
 obj-$(CONFIG_CMD_NET) += net.o
diff --git a/cmd/mtd.c b/cmd/mtd.c
new file mode 100644
index 0000000..0dc529d
--- /dev/null
+++ b/cmd/mtd.c
@@ -0,0 +1,285 @@
+/*
+ * Command for accessing MTD device.
+ *
+ * Copyright (C) 2016 Jagan Teki <ja...@openedev.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mtd.h>
+
+#include <asm/io.h>
+#include <jffs2/jffs2.h>
+
+static struct udevice *mtd_cur_dev;
+
+static int cmd_mtd_set_devnum(unsigned int devnum)
+{
+       struct udevice *dev;
+       int ret;
+
+       ret = uclass_get_device_by_seq(UCLASS_MTD, devnum, &dev);
+       if (ret) {
+               debug("%s: No MTD device %d\n", __func__, devnum);
+               return ret;
+       }
+       mtd_cur_dev = dev;
+
+       return 0;
+}
+
+static int mtd_get_cur_dev(struct udevice **devp)
+{
+       if (!mtd_cur_dev) {
+               puts("No MTD device selected\n");
+               return -ENODEV;
+       }
+       *devp = mtd_cur_dev;
+
+       return 0;
+}
+
+static int do_mtd_write_read(int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct mtd_info *mtd;
+       loff_t offset, addr, len, maxsize;
+       u_char *buf;
+       char *endp;
+       int idx = 0;
+       int ret;
+
+       if (argc < 3)
+               return -1;
+
+       ret = mtd_get_cur_dev(&dev);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       addr = simple_strtoul(argv[1], &endp, 16);
+       if (*argv[1] == 0 || *endp != 0)
+               return -1;
+
+       mtd = mtd_get_info(dev);
+       if (mtd_arg_off_size(argc - 2, &argv[2], &idx, &offset, &len,
+                            &maxsize, MTD_DEV_TYPE_NOR, mtd->size))
+               return -1;
+
+       buf = map_physmem(addr, len, MAP_WRBACK);
+       if (!buf) {
+               puts("failed to map physical memory\n");
+               return 1;
+       }
+
+       if (strcmp(argv[0], "write") == 0)
+               ret = dm_mtd_write(dev, offset, len, (size_t *)&len, buf);
+       else if (strcmp(argv[0], "read") == 0)
+               ret = dm_mtd_read(dev, offset, len, (size_t *)&len, buf);
+
+       printf("MTD: %zu bytes @ %#llx %s: ", (size_t)len, offset,
+              (strcmp(argv[0], "read") == 0) ? "Read" : "Written");
+       if (ret)
+               printf("ERROR %d\n", ret);
+       else
+               printf("OK\n");
+
+       unmap_physmem(buf, len);
+
+       return ret == 0 ? 0 : 1;
+}
+
+static int mtd_parse_len_arg(struct mtd_info *mtd, char *arg, loff_t *len)
+{
+       char *ep;
+       char round_up_len; /* indicates if the "+length" form used */
+       ulong len_arg;
+
+       round_up_len = 0;
+       if (*arg == '+') {
+               round_up_len = 1;
+               ++arg;
+       }
+
+       len_arg = simple_strtoul(arg, &ep, 16);
+       if (ep == arg || *ep != '\0')
+               return -1;
+
+       if (round_up_len && mtd->erasesize > 0)
+               *len = ROUND(len_arg, mtd->erasesize);
+       else
+               *len = len_arg;
+
+       return 1;
+}
+
+static int do_mtd_erase(int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct mtd_info *mtd;
+       struct erase_info instr;
+       loff_t addr, len, maxsize;
+       int idx = 0;
+       int ret;
+
+       if (argc < 3)
+               return -1;
+
+       ret = mtd_get_cur_dev(&dev);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       mtd = mtd_get_info(dev);
+       if (mtd_arg_off(argv[1], &idx, &addr, &len, &maxsize,
+                       MTD_DEV_TYPE_NOR, mtd->size))
+               return -1;
+
+       ret = mtd_parse_len_arg(mtd, argv[2], &len);
+       if (ret != 1)
+               return -1;
+
+       instr.mtd = mtd;
+       instr.addr = addr;
+       instr.len = len;
+       instr.callback = 0;
+       ret = dm_mtd_erase(dev, &instr);
+       printf("MTD: %zu bytes @ %#llx Erased: %s\n", (size_t)len, addr,
+              ret ? "ERROR" : "OK");
+
+       return ret == 0 ? 0 : 1;
+}
+
+static int do_mtd_probe(int argc, char * const argv[])
+{
+       struct udevice *dev, *devp;
+       int devnum;
+       int ret;
+
+       devnum = simple_strtoul(argv[1], NULL, 10);
+
+       debug("Setting MTD device to %d\n", devnum);
+       ret = cmd_mtd_set_devnum(devnum);
+       if (ret) {
+               printf("failing to set MTD device %d\n", devnum);
+               return CMD_RET_FAILURE;
+       }
+
+       ret = mtd_get_cur_dev(&dev);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       ret = dm_mtd_probe(dev, &devp);
+       if (ret) {
+               printf("failed to probe MTD device %d\n", devnum);
+               return CMD_RET_FAILURE;
+       }
+
+       return 0;
+}
+
+static int do_mtd_info(void)
+{
+       struct udevice *dev;
+       struct mtd_info *mtd;
+       int ret;
+
+       ret = mtd_get_cur_dev(&dev);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       mtd = mtd_get_info(dev);
+       printf("MTD Device %d: %s\n", dev->req_seq, mtd->name);
+       printf(" Page size:\t%d B\n Erase size:\t", mtd->writebufsize);
+       print_size(mtd->erasesize, "\n Size:\t\t");
+       print_size(mtd->size, "");
+       printf("\n");
+
+       return 0;
+}
+
+static int do_mtd_list(void)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+       int ret;
+
+       ret = uclass_get(UCLASS_MTD, &uc);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       uclass_foreach_dev(dev, uc) {
+               printf("MTD %d:\t%s", dev->req_seq, dev->name);
+                       if (device_active(dev))
+                               printf("  (active %d)", dev->seq);
+               printf("\n");
+       }
+
+       return 0;
+}
+
+static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       const char *cmd;
+       int ret = 0;
+
+       cmd = argv[1];
+       if (strcmp(cmd, "list") == 0) {
+               if (argc > 2)
+                       goto usage;
+
+               ret = do_mtd_list();
+               goto done;
+       }
+
+       if (strcmp(cmd, "info") == 0) {
+               if (argc > 2)
+                       goto usage;
+
+               ret = do_mtd_info();
+               goto done;
+       }
+
+       if (argc < 3)
+               goto usage;
+
+       --argc;
+       ++argv;
+
+       if (strcmp(cmd, "probe") == 0) {
+               ret = do_mtd_probe(argc, argv);
+               goto done;
+       }
+
+       if (strcmp(cmd, "erase") == 0) {
+               ret = do_mtd_erase(argc, argv);
+               goto done;
+       }
+
+       if (strcmp(cmd, "write") == 0 || strcmp(cmd, "read") == 0) {
+               ret = do_mtd_write_read(argc, argv);
+               goto done;
+       }
+
+done:
+       if (ret != -1)
+               return ret;
+
+usage:
+       return CMD_RET_USAGE;
+}
+
+static char mtd_help_text[] =
+       "list                   - show list of MTD devices\n"
+       "mtd info                       - show current MTD device info\n"
+       "mtd probe devnum               - probe the 'devnum' MTD device\n"
+       "mtd erase offset len           - erase 'len' bytes from 'offset'\n"
+       "mtd write addr to len          - write 'len' bytes to 'to' from 
'addr'\n"
+       "mtd read addr from len         - read 'len' bytes from 'from' to 
'addr'";
+
+U_BOOT_CMD(
+       mtd, 5, 1, do_mtd,
+       "MTD Sub-system",
+       mtd_help_text
+);
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index bd680a7..6b54b79 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -8,7 +8,7 @@
 ifneq (,$(findstring 
y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
 obj-y += mtdcore.o mtd_uboot.o
 endif
-obj-$(CONFIG_MTD) += mtd-uclass.o
+obj-$(CONFIG_MTD) += mtd-uclass.o mtd_uboot.o
 obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
 obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
 obj-$(CONFIG_ALTERA_QSPI) += altera_qspi.o
diff --git a/drivers/mtd/mtd-uclass.c b/drivers/mtd/mtd-uclass.c
index 8eb6e8f..3e63de4 100644
--- a/drivers/mtd/mtd-uclass.c
+++ b/drivers/mtd/mtd-uclass.c
@@ -83,6 +83,23 @@ int dm_add_mtd_device(struct udevice *dev)
        return 0;
 }
 
+int dm_mtd_probe(struct udevice *dev, struct udevice **devp)
+{
+       *devp = NULL;
+       int ret;
+
+       ret = device_probe(dev);
+       debug("%s:  device_probe: ret=%d\n", __func__, ret);
+       if (ret)
+               goto err;
+
+       *devp = dev;
+       return 0;
+err:
+       device_unbind(dev);
+       return ret;
+}
+
 /*
  * Implement a MTD uclass which should include most flash drivers.
  * The uclass private is pointed to mtd_info.
diff --git a/include/mtd.h b/include/mtd.h
index 93b5eaf..49b8272 100644
--- a/include/mtd.h
+++ b/include/mtd.h
@@ -74,4 +74,13 @@ int dm_mtd_erase(struct udevice *dev, struct erase_info 
*instr);
  */
 int dm_add_mtd_device(struct udevice *dev);
 
+/**
+ * dm_mtd_probe() - Probe MTD device
+ *
+ * @dev:       MTD device
+ * @devp:      MTD device pointer
+ * @return 0 if OK, -ve on error
+ */
+int dm_mtd_probe(struct udevice *dev, struct udevice **devp);
+
 #endif /* _MTD_H_ */
-- 
2.7.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to