[U-Boot] [PATCH v10 21/27] cmd: add spinor cmd support

Jagan Teki
2017-12-28T06:12:27Z

Now, spi-nor framework is up so access spi-nor device
from command prompt via 'spinor'

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
cmd/Kconfig | 5 +
cmd/Makefile | 1 +
cmd/spinor.c | 281 ++++++++++++++++++++++++++++++++++++++++++++
drivers/mtd/Makefile | 7 +-
include/linux/mtd/spi-nor.h | 1 +
5 files changed, 293 insertions(+), 2 deletions(-)
create mode 100644 cmd/spinor.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index c033223..130c226 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -870,6 +870,11 @@ config CMD_SDRAM
SDRAM has an EEPROM with information that can be read using the
I2C bus. This is only available on some boards.

+config CMD_SPINOR
+ bool "spinor"
+ help
+ SPI NOR Flash support
+
config CMD_SF
bool "sf"
help
diff --git a/cmd/Makefile b/cmd/Makefile
index 00e3869..81ab932 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -108,6 +108,7 @@ obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o
obj-$(CONFIG_SANDBOX) += host.o
obj-$(CONFIG_CMD_SATA) += sata.o
obj-$(CONFIG_CMD_NVME) += nvme.o
+obj-$(CONFIG_CMD_SPINOR) += spinor.o
obj-$(CONFIG_CMD_SF) += sf.o
obj-$(CONFIG_CMD_SCSI) += scsi.o disk.o
obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o
diff --git a/cmd/spinor.c b/cmd/spinor.c
new file mode 100644
index 0000000..b781151
--- /dev/null
+++ b/cmd/spinor.c
@@ -0,0 +1,281 @@
+/*
+ * Command for accessing SPI-NOR device.
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mtd.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+#include <asm/io.h>
+#include <jffs2/jffs2.h>
+
+static int curr_device = 0;
+
+static int do_spinor_list(void)
+{
+ print_spi_nor_devices('\n');
+ return CMD_RET_SUCCESS;
+}
+
+static struct spi_nor *init_spinor_device(int dev, bool force_init)
+{
+ struct spi_nor *nor;
+
+ nor = find_spi_nor_device(dev);
+ if (!nor) {
+ printf("No SPI-NOR device found! %x\n", dev);
+ return NULL;
+ }
+
+ if (force_init)
+ nor->init_done = 0;
+ if (spi_nor_scan(nor))
+ return NULL;
+
+ return nor;
+}
+
+static void print_spinor_info(struct spi_nor *nor)
+{
+ struct mtd_info *mtd = spi_nor_get_mtd_info(nor);
+
+ printf("bus: %s: %d\n", nor->dev->name, mtd->devnum);
+ printf("device: %s\n", mtd->name);
+ printf("page size: %d B\nerase size: ", mtd->writebufsize);
+ print_size(mtd->erasesize, "\nsize: ");
+ print_size(mtd->size, "");
+ if (nor->memory_map)
+ printf(", mapped at %p", nor->memory_map);
+ printf("\n");
+}
+
+static int do_spinor_info(void)
+{
+ struct spi_nor *nor;
+
+ if (curr_device < 0) {
+ if (get_spi_nor_num() > 0)
+ curr_device = 0;
+ else {
+ puts("No SPI-NOR device available\n");
+ return 1;
+ }
+ }
+
+ nor = init_spinor_device(curr_device, false);
+ if (!nor)
+ return CMD_RET_FAILURE;
+
+ print_spinor_info(nor);
+ return CMD_RET_SUCCESS;
+}
+
+static int do_spinor_dev(int argc, char * const argv[])
+{
+ struct spi_nor *nor;
+ int devnum = 0;
+ int ret;
+
+ if (argc == 2)
+ devnum = curr_device;
+ else if (argc == 3)
+ devnum = simple_strtoul(argv[2], NULL, 10);
+
+ nor = init_spinor_device(devnum, true);
+ if (!nor)
+ return CMD_RET_FAILURE;
+
+ ret = mtd_select_devnum(MTD_IF_TYPE_SPI_NOR, devnum);
+ printf("switch to dev #%d, %s\n", devnum, (!ret) ? "OK" : "ERROR");
+ if (ret)
+ return CMD_RET_FAILURE;
+
+ curr_device = devnum;
+ printf("spinor%d is current device\n", curr_device);
+
+ return CMD_RET_SUCCESS;
+}
+
+static int do_spinor_write_read(int argc, char * const argv[])
+{
+ struct mtd_info *mtd;
+ struct spi_nor *nor;
+ loff_t offset, addr, len, maxsize;
+ u_char *buf;
+ char *endp;
+ int idx = 0;
+ int ret = CMD_RET_FAILURE;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ nor = init_spinor_device(curr_device, false);
+ if (!nor)
+ return CMD_RET_FAILURE;
+
+ addr = simple_strtoul(argv[1], &endp, 16);
+ if (*argv[1] == 0 || *endp != 0)
+ return CMD_RET_FAILURE;
+
+ mtd = spi_nor_get_mtd_info(nor);
+ if (mtd_arg_off_size(argc - 2, &argv[2], &idx, &offset, &len,
+ &maxsize, MTD_DEV_TYPE_NOR, mtd->size))
+ return CMD_RET_FAILURE;
+
+ 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 = mtd_dwrite(mtd, offset, len, (size_t *)&len, buf);
+ else if (strcmp(argv[0], "read") == 0)
+ ret = mtd_dread(mtd, offset, len, (size_t *)&len, buf);
+
+ printf("SPI-NOR: %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 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
+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_spinor_erase(int argc, char * const argv[])
+{
+ struct mtd_info *mtd;
+ struct spi_nor *nor;
+ struct erase_info instr;
+ loff_t addr, len, maxsize;
+ int idx = 0;
+ int ret;
+
+ if (argc != 3)
+ return CMD_RET_USAGE;
+
+ nor = init_spinor_device(curr_device, false);
+ if (!nor)
+ return CMD_RET_FAILURE;
+
+ mtd = spi_nor_get_mtd_info(nor);
+ if (mtd_arg_off(argv[1], &idx, &addr, &len, &maxsize,
+ MTD_DEV_TYPE_NOR, mtd->size))
+ return CMD_RET_FAILURE;
+
+ ret = mtd_parse_len_arg(mtd, argv[2], &len);
+ if (ret != 1)
+ return CMD_RET_FAILURE;
+
+ instr.mtd = mtd;
+ instr.addr = addr;
+ instr.len = len;
+ instr.callback = 0;
+ ret = mtd_derase(mtd, &instr);
+ printf("SPI-NOR: %zu bytes @ %#llx Erased: %s\n", (size_t)len, addr,
+ ret ? "ERROR" : "OK");
+
+ return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
+static int do_spinor(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_spinor_list();
+ goto done;
+ }
+
+ if (strcmp(cmd, "dev") == 0) {
+ if (argc > 3)
+ goto usage;
+
+ ret = do_spinor_dev(argc, argv);
+ goto done;
+ }
+
+ if (strcmp(cmd, "info") == 0) {
+ if (argc > 2)
+ goto usage;
+
+ ret = do_spinor_info();
+ goto done;
+ }
+
+ if (argc < 3)
+ goto usage;
+
+ --argc;
+ ++argv;
+
+ if (strcmp(cmd, "erase") == 0) {
+ ret = do_spinor_erase(argc, argv);
+ goto done;
+ }
+
+ if (strcmp(cmd, "write") == 0 || strcmp(cmd, "read") == 0) {
+ ret = do_spinor_write_read(argc, argv);
+ goto done;
+ }
+
+done:
+ if (ret != -1)
+ return ret;
+
+usage:
+ return CMD_RET_USAGE;
+}
+
+static char spinor_help_text[] =
+ "list - show list of spinor devices\n"
+ "spinor info - show current spinor device info\n"
+ "spinor dev [devnum] - show or set current spinor device\n"
+ "spinor erase offset len - erase 'len' bytes from 'offset'\n"
+ "spinor write addr to len - write 'len' bytes to 'to' from 'addr'\n"
+ "spinor read addr from len - read 'len' bytes from 'from' to 'addr'";
+
+U_BOOT_CMD(
+ spinor, 5, 1, do_spinor,
+ "SPI-NOR Sub-system",
+ spinor_help_text
+);
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 20c0d0a..c5209ad 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -5,8 +5,11 @@
# SPDX-License-Identifier: GPL-2.0+
#

-ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
-obj-y += mtdcore.o mtd_uboot.o
+ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF),$(CONFIG_CMD_SPINOR)))
+obj-y += mtd_uboot.o
+ifndef CONFIG_MTD
+obj-y += mtdcore.o
+endif
endif
obj-$(CONFIG_MTD) += mtd-uclass.o
obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index fc4a649..9c3da70 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -217,5 +217,6 @@ struct spi_nor *find_spi_nor_device(int dev_num);
int get_spi_nor_num(void);
struct spi_nor *spi_nor_get_spi_nor_dev(struct udevice *dev);
struct mtd_info *spi_nor_get_mtd_info(struct spi_nor *nor);
+void print_spi_nor_devices(char separator);

#endif /* __MTD_SPI_NOR_H */
--
2.7.4