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

Jagan Teki jagan at amarulasolutions.com
Thu Dec 28 06:12:27 UTC 2017


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

Signed-off-by: Suneel Garapati <suneelglinux at gmail.com>
Signed-off-by: Jagan Teki <jagan at 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 at 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



More information about the U-Boot mailing list