[OpenWrt-Devel] [PATCH v3] ar71xx: modernize fast SPI flash read

Heiner Kallweit hkallweit1 at gmail.com
Wed Apr 27 14:36:44 EDT 2016


OpenWRT has own support for the memory-mapped fast SPI flash read on ath79.
With mainline kernel 4.6/4.7 more elegant generic support for this feature
was added upstream consisting of these commits:

556351f14e74 "spi: introduce accelerated read support for spi flash devices"
08922f644878 "mtd: devices: m25p80: add support for mmap read request"
7ba2f2757d84 "spi: core: add hook flash_read_supported to spi_master"

The first two commits have been added as patches 045 and 080 under
generic/patches-4.4 recently.
The third one is added as part of this patch set as generic patch 082.

The change was successfully tested on a TP-Link TL-WDR3600.

Signed-off-by: Heiner Kallweit <hkallweit1 at gmail.com>
---
v2:
- make change compatible with ath79_register_m25p80_multi():
  >1 flash chip but one can be mmap-accessed only
v3:
- adjusted commit message
- removed content of new generic patches 045 and 080
- added generic patch 082
---
 .../460-spi-bitbang-export-spi_bitbang_bufs.patch  |  28 ----
 .../patches-4.4/460-spi-extend-ath79_spi.patch     |  32 ++++
 .../461-spi-add-type-field-to-spi_transfer.patch   |  23 ---
 .../461-spi-ath79-fast-flash-read.patch            |  56 +++++++
 .../462-mtd-m25p80-set-spi-transfer-type.patch     |  15 --
 .../463-spi-ath79-add-fast-flash-read.patch        | 185 ---------------------
 .../464-spi-ath79-fix-fast-flash-read.patch        |  35 ----
 .../082-backport-spi-flash-read-supported.patch    |  29 ++++
 8 files changed, 117 insertions(+), 286 deletions(-)
 delete mode 100644 target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/460-spi-extend-ath79_spi.patch
 delete mode 100644 target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
 create mode 100644 target/linux/ar71xx/patches-4.4/461-spi-ath79-fast-flash-read.patch
 delete mode 100644 target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
 delete mode 100644 target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch
 delete mode 100644 target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
 create mode 100644 target/linux/generic/patches-4.4/082-backport-spi-flash-read-supported.patch

diff --git a/target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch b/target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch
deleted file mode 100644
index 2a8d7af..0000000
--- a/target/linux/ar71xx/patches-4.4/460-spi-bitbang-export-spi_bitbang_bufs.patch
+++ /dev/null
@@ -1,28 +0,0 @@
---- a/drivers/spi/spi-bitbang.c
-+++ b/drivers/spi/spi-bitbang.c
-@@ -231,13 +231,14 @@ void spi_bitbang_cleanup(struct spi_devi
- }
- EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
- 
--static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
-+int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
- {
- 	struct spi_bitbang_cs	*cs = spi->controller_state;
- 	unsigned		nsecs = cs->nsecs;
- 
- 	return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
- }
-+EXPORT_SYMBOL_GPL(spi_bitbang_bufs);
- 
- /*----------------------------------------------------------------------*/
- 
---- a/include/linux/spi/spi_bitbang.h
-+++ b/include/linux/spi/spi_bitbang.h
-@@ -39,6 +39,7 @@ extern int spi_bitbang_setup(struct spi_
- extern void spi_bitbang_cleanup(struct spi_device *spi);
- extern int spi_bitbang_setup_transfer(struct spi_device *spi,
- 				      struct spi_transfer *t);
-+extern int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t);
- 
- /* start or stop queue processing */
- extern int spi_bitbang_start(struct spi_bitbang *spi);
diff --git a/target/linux/ar71xx/patches-4.4/460-spi-extend-ath79_spi.patch b/target/linux/ar71xx/patches-4.4/460-spi-extend-ath79_spi.patch
new file mode 100644
index 0000000..312d7be
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/460-spi-extend-ath79_spi.patch
@@ -0,0 +1,32 @@
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -42,6 +42,9 @@ struct ath79_spi {
+ 	void __iomem		*base;
+ 	struct clk		*clk;
+ 	unsigned		rrw_delay;
++
++	u32			clk_div;
++	unsigned long		ahb_rate;
+ };
+ 
+ static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
+@@ -109,9 +112,6 @@ static void ath79_spi_enable(struct ath79_spi *sp)
+ 	/* save CTRL register */
+ 	sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
+ 	sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
+-
+-	/* TODO: setup speed? */
+-	ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
+ }
+ 
+ static void ath79_spi_disable(struct ath79_spi *sp)
+@@ -280,7 +280,8 @@ static int ath79_spi_probe(struct platform_device *pdev)
+ 	if (ret)
+ 		goto err_put_master;
+ 
+-	rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
++	sp->ahb_rate = clk_get_rate(sp->clk);
++	rate = DIV_ROUND_UP(sp->ahb_rate, MHZ);
+ 	if (!rate) {
+ 		ret = -EINVAL;
+ 		goto err_clk_disable;
diff --git a/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch b/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
deleted file mode 100644
index be6233c..0000000
--- a/target/linux/ar71xx/patches-4.4/461-spi-add-type-field-to-spi_transfer.patch
+++ /dev/null
@@ -1,23 +0,0 @@
---- a/include/linux/spi/spi.h
-+++ b/include/linux/spi/spi.h
-@@ -578,6 +578,12 @@ extern struct spi_master *spi_busnum_to_
- 
- /*---------------------------------------------------------------------------*/
- 
-+enum spi_transfer_type {
-+	SPI_TRANSFER_GENERIC = 0,
-+	SPI_TRANSFER_FLASH_READ_CMD,
-+	SPI_TRANSFER_FLASH_READ_DATA,
-+};
-+
- /*
-  * I/O INTERFACE between SPI controller and protocol drivers
-  *
-@@ -698,6 +704,7 @@ struct spi_transfer {
- 	u8		bits_per_word;
- 	u16		delay_usecs;
- 	u32		speed_hz;
-+	enum spi_transfer_type type;
- 
- 	struct list_head transfer_list;
- };
diff --git a/target/linux/ar71xx/patches-4.4/461-spi-ath79-fast-flash-read.patch b/target/linux/ar71xx/patches-4.4/461-spi-ath79-fast-flash-read.patch
new file mode 100644
index 0000000..ea71fc2
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.4/461-spi-ath79-fast-flash-read.patch
@@ -0,0 +1,56 @@
+--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
++++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+@@ -24,6 +24,7 @@ enum ath79_spi_cs_type {
+ struct ath79_spi_controller_data {
+ 	enum ath79_spi_cs_type cs_type;
+ 	unsigned cs_line;
++	bool is_flash;
+ };
+ 
+ #endif /* _ATH79_SPI_PLATFORM_H */
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -172,6 +172,34 @@ static void ath79_spi_cleanup_cs(struct spi_device *spi)
+ 	}
+ }
+ 
++static int ath79_spi_flash_read(struct spi_device *spi,
++				struct spi_flash_read_message *msg)
++{
++	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++
++	/* disable GPIO mode */
++	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
++
++	memcpy_fromio(msg->buf, sp->base + msg->from, msg->len);
++
++	/* enable GPIO mode */
++	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
++
++	/* restore IOC register */
++	ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
++
++	msg->retlen = msg->len;
++
++	return 0;
++}
++
++static bool ath79_spi_flash_read_supported(struct spi_device *spi)
++{
++	struct ath79_spi_controller_data *cdata = spi->controller_data;
++
++	return cdata->is_flash;
++}
++
+ static int ath79_spi_setup(struct spi_device *spi)
+ {
+ 	int status = 0;
+@@ -249,6 +277,8 @@ static int ath79_spi_probe(struct platform_device *pdev)
+ 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ 	master->setup = ath79_spi_setup;
+ 	master->cleanup = ath79_spi_cleanup;
++	master->spi_flash_read = ath79_spi_flash_read;
++	master->flash_read_supported = ath79_spi_flash_read_supported;
+ 	master->bus_num = pdata->bus_num;
+ 	master->num_chipselect = pdata->num_chipselect;
+ 
diff --git a/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch b/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
deleted file mode 100644
index 11bf9ff..0000000
--- a/target/linux/ar71xx/patches-4.4/462-mtd-m25p80-set-spi-transfer-type.patch
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/drivers/mtd/devices/m25p80.c
-+++ b/drivers/mtd/devices/m25p80.c
-@@ -137,10 +137,12 @@ static int m25p80_read(struct spi_nor *n
- 	flash->command[0] = nor->read_opcode;
- 	m25p_addr2cmd(nor, from, flash->command);
- 
-+	t[0].type = SPI_TRANSFER_FLASH_READ_CMD;
- 	t[0].tx_buf = flash->command;
- 	t[0].len = m25p_cmdsz(nor) + dummy;
- 	spi_message_add_tail(&t[0], &m);
- 
-+	t[1].type = SPI_TRANSFER_FLASH_READ_DATA;
- 	t[1].rx_buf = buf;
- 	t[1].rx_nbits = m25p80_rx_nbits(nor);
- 	t[1].len = len;
diff --git a/target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch b/target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch
deleted file mode 100644
index 408ce65..0000000
--- a/target/linux/ar71xx/patches-4.4/463-spi-ath79-add-fast-flash-read.patch
+++ /dev/null
@@ -1,185 +0,0 @@
---- a/drivers/spi/spi-ath79.c
-+++ b/drivers/spi/spi-ath79.c
-@@ -35,6 +35,11 @@
- 
- #define ATH79_SPI_CS_LINE_MAX		2
- 
-+enum ath79_spi_state {
-+	ATH79_SPI_STATE_WAIT_CMD = 0,
-+	ATH79_SPI_STATE_WAIT_READ,
-+};
-+
- struct ath79_spi {
- 	struct spi_bitbang	bitbang;
- 	u32			ioc_base;
-@@ -42,6 +47,11 @@ struct ath79_spi {
- 	void __iomem		*base;
- 	struct clk		*clk;
- 	unsigned		rrw_delay;
-+
-+	enum ath79_spi_state	state;
-+	u32			clk_div;
-+	unsigned long 		read_addr;
-+	unsigned long		ahb_rate;
- };
- 
- static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
-@@ -109,9 +119,6 @@ static void ath79_spi_enable(struct ath7
- 	/* save CTRL register */
- 	sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
- 	sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
--
--	/* TODO: setup speed? */
--	ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
- }
- 
- static void ath79_spi_disable(struct ath79_spi *sp)
-@@ -232,6 +239,110 @@ static u32 ath79_spi_txrx_mode0(struct s
- 	return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
- }
- 
-+static int ath79_spi_do_read_flash_data(struct spi_device *spi,
-+					struct spi_transfer *t)
-+{
-+	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
-+
-+	/* disable GPIO mode */
-+	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
-+
-+	memcpy_fromio(t->rx_buf, sp->base + sp->read_addr, t->len);
-+
-+	/* enable GPIO mode */
-+	ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
-+
-+	/* restore IOC register */
-+	ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
-+
-+	return t->len;
-+}
-+
-+static int ath79_spi_do_read_flash_cmd(struct spi_device *spi,
-+				       struct spi_transfer *t)
-+{
-+	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
-+	int len;
-+	const u8 *p;
-+
-+	sp->read_addr = 0;
-+
-+	len = t->len - 1;
-+	p = t->tx_buf;
-+
-+	while (len--) {
-+		p++;
-+		sp->read_addr <<= 8;
-+		sp->read_addr |= *p;
-+	}
-+
-+	return t->len;
-+}
-+
-+static bool ath79_spi_is_read_cmd(struct spi_device *spi,
-+				 struct spi_transfer *t)
-+{
-+	return t->type == SPI_TRANSFER_FLASH_READ_CMD;
-+}
-+
-+static bool ath79_spi_is_data_read(struct spi_device *spi,
-+				  struct spi_transfer *t)
-+{
-+	return t->type == SPI_TRANSFER_FLASH_READ_DATA;
-+}
-+
-+static int ath79_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
-+{
-+	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
-+	int ret;
-+
-+	switch (sp->state) {
-+	case ATH79_SPI_STATE_WAIT_CMD:
-+		if (ath79_spi_is_read_cmd(spi, t)) {
-+			ret = ath79_spi_do_read_flash_cmd(spi, t);
-+			sp->state = ATH79_SPI_STATE_WAIT_READ;
-+		} else {
-+			ret = spi_bitbang_bufs(spi, t);
-+		}
-+		break;
-+
-+	case ATH79_SPI_STATE_WAIT_READ:
-+		if (ath79_spi_is_data_read(spi, t)) {
-+			ret = ath79_spi_do_read_flash_data(spi, t);
-+		} else {
-+			dev_warn(&spi->dev, "flash data read expected\n");
-+			ret = -EIO;
-+		}
-+		sp->state = ATH79_SPI_STATE_WAIT_CMD;
-+		break;
-+
-+	default:
-+		BUG();
-+	}
-+
-+	return ret;
-+}
-+
-+static int ath79_spi_setup_transfer(struct spi_device *spi,
-+				    struct spi_transfer *t)
-+{
-+	struct ath79_spi *sp = ath79_spidev_to_sp(spi);
-+	struct ath79_spi_controller_data *cdata;
-+	int ret;
-+
-+	ret = spi_bitbang_setup_transfer(spi, t);
-+	if (ret)
-+		return ret;
-+
-+	cdata = spi->controller_data;
-+	if (cdata->is_flash)
-+		sp->bitbang.txrx_bufs = ath79_spi_txrx_bufs;
-+	else
-+		sp->bitbang.txrx_bufs = spi_bitbang_bufs;
-+
-+	return ret;
-+}
-+
- static int ath79_spi_probe(struct platform_device *pdev)
- {
- 	struct spi_master *master;
-@@ -254,6 +365,8 @@ static int ath79_spi_probe(struct platfo
- 	sp = spi_master_get_devdata(master);
- 	platform_set_drvdata(pdev, sp);
- 
-+	sp->state = ATH79_SPI_STATE_WAIT_CMD;
-+
- 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- 	master->setup = ath79_spi_setup;
- 	master->cleanup = ath79_spi_cleanup;
-@@ -263,7 +376,7 @@ static int ath79_spi_probe(struct platfo
- 	sp->bitbang.master = master;
- 	sp->bitbang.chipselect = ath79_spi_chipselect;
- 	sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
--	sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
-+	sp->bitbang.setup_transfer = ath79_spi_setup_transfer;
- 	sp->bitbang.flags = SPI_CS_HIGH;
- 
- 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-@@ -283,7 +396,8 @@ static int ath79_spi_probe(struct platfo
- 	if (ret)
- 		goto err_put_master;
- 
--	rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
-+	sp->ahb_rate = clk_get_rate(sp->clk);
-+	rate = DIV_ROUND_UP(sp->ahb_rate, MHZ);
- 	if (!rate) {
- 		ret = -EINVAL;
- 		goto err_clk_disable;
---- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
-+++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
-@@ -24,6 +24,7 @@ enum ath79_spi_cs_type {
- struct ath79_spi_controller_data {
- 	enum ath79_spi_cs_type cs_type;
- 	unsigned cs_line;
-+	bool is_flash;
- };
- 
- #endif /* _ATH79_SPI_PLATFORM_H */
diff --git a/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch b/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
deleted file mode 100644
index f8ae4e0..0000000
--- a/target/linux/ar71xx/patches-4.4/464-spi-ath79-fix-fast-flash-read.patch
+++ /dev/null
@@ -1,35 +0,0 @@
---- a/drivers/mtd/devices/m25p80.c
-+++ b/drivers/mtd/devices/m25p80.c
-@@ -137,6 +137,9 @@ static int m25p80_read(struct spi_nor *n
- 	flash->command[0] = nor->read_opcode;
- 	m25p_addr2cmd(nor, from, flash->command);
- 
-+	if (dummy == 1)
-+		t[0].dummy = true;
-+
- 	t[0].type = SPI_TRANSFER_FLASH_READ_CMD;
- 	t[0].tx_buf = flash->command;
- 	t[0].len = m25p_cmdsz(nor) + dummy;
---- a/drivers/spi/spi-ath79.c
-+++ b/drivers/spi/spi-ath79.c
-@@ -268,6 +268,10 @@ static int ath79_spi_do_read_flash_cmd(s
- 	sp->read_addr = 0;
- 
- 	len = t->len - 1;
-+
-+	if (t->dummy)
-+		len -= 1;
-+
- 	p = t->tx_buf;
- 
- 	while (len--) {
---- a/include/linux/spi/spi.h
-+++ b/include/linux/spi/spi.h
-@@ -705,6 +705,7 @@ struct spi_transfer {
- 	u16		delay_usecs;
- 	u32		speed_hz;
- 	enum spi_transfer_type type;
-+	bool dummy;
- 
- 	struct list_head transfer_list;
- };
diff --git a/target/linux/generic/patches-4.4/082-backport-spi-flash-read-supported.patch b/target/linux/generic/patches-4.4/082-backport-spi-flash-read-supported.patch
new file mode 100644
index 0000000..e6bc43a
--- /dev/null
+++ b/target/linux/generic/patches-4.4/082-backport-spi-flash-read-supported.patch
@@ -0,0 +1,29 @@
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -372,6 +372,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
+  * @unprepare_message: undo any work done by prepare_message().
+  * @spi_flash_read: to support spi-controller hardwares that provide
+  *                  accelerated interface to read from flash devices.
++ * @flash_read_supported: spi device supports flash read
+  * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
+  *	number. Any individual value may be -ENOENT for CS lines that
+  *	are not GPIOs (driven by the SPI controller itself).
+@@ -529,6 +530,7 @@ struct spi_master {
+ 				 struct spi_message *message);
+ 	int (*spi_flash_read)(struct  spi_device *spi,
+ 			      struct spi_flash_read_message *msg);
++	bool (*flash_read_supported)(struct spi_device *spi);
+ 
+ 	/*
+ 	 * These hooks are for drivers that use a generic implementation
+@@ -1158,7 +1160,9 @@ struct spi_flash_read_message {
+ /* SPI core interface for flash read support */
+ static inline bool spi_flash_read_supported(struct spi_device *spi)
+ {
+-	return spi->master->spi_flash_read ? true : false;
++	return spi->master->spi_flash_read &&
++	       (!spi->master->flash_read_supported ||
++	       spi->master->flash_read_supported(spi));
+ }
+ 
+ int spi_flash_read(struct spi_device *spi,
-- 
2.8.0
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list