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

Heiner Kallweit hkallweit1 at gmail.com
Sat Apr 23 16:15:11 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 two commits:

556351f14e74 "spi: introduce accelerated read support for spi flash devices"
08922f644878 "mtd: devices: m25p80: add support for mmap read request"

I cherry-picked them for use with ar71xx default kernel version 4.1
(new patches 460 + 461)
Once the ar71xx kernel version reaches 4.6 / 4.7 these patches
can be removed.

New patch 462 includes changes from old patch 463 which are not related
to the fast flash read feature.

New patch 463 includes the new implementation for the fast flash read
feature on ath79.

These four new patches replace old patches 460-464.

So far for testing I made the change for the 4.1 version only.
If it looks good I can do the same for the 4.4 version.

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
---
 .../460-spi-add-generic-flash-read.patch           | 159 ++++++++++++++++++
 .../460-spi-bitbang-export-spi_bitbang_bufs.patch  |  28 ----
 .../patches-4.1/461-m25p80-add-flash-read.patch    |  33 ++++
 .../461-spi-add-type-field-to-spi_transfer.patch   |  23 ---
 .../462-mtd-m25p80-set-spi-transfer-type.patch     |  15 --
 .../patches-4.1/462-spi-extend-ath79_spi.patch     |  32 ++++
 .../463-spi-ath79-add-fast-flash-read.patch        | 185 ---------------------
 .../463-spi-ath79-fast-flash-read.patch            |  94 +++++++++++
 .../464-spi-ath79-fix-fast-flash-read.patch        |  35 ----
 9 files changed, 318 insertions(+), 286 deletions(-)
 create mode 100644 target/linux/ar71xx/patches-4.1/460-spi-add-generic-flash-read.patch
 delete mode 100644 target/linux/ar71xx/patches-4.1/460-spi-bitbang-export-spi_bitbang_bufs.patch
 create mode 100644 target/linux/ar71xx/patches-4.1/461-m25p80-add-flash-read.patch
 delete mode 100644 target/linux/ar71xx/patches-4.1/461-spi-add-type-field-to-spi_transfer.patch
 delete mode 100644 target/linux/ar71xx/patches-4.1/462-mtd-m25p80-set-spi-transfer-type.patch
 create mode 100644 target/linux/ar71xx/patches-4.1/462-spi-extend-ath79_spi.patch
 delete mode 100644 target/linux/ar71xx/patches-4.1/463-spi-ath79-add-fast-flash-read.patch
 create mode 100644 target/linux/ar71xx/patches-4.1/463-spi-ath79-fast-flash-read.patch
 delete mode 100644 target/linux/ar71xx/patches-4.1/464-spi-ath79-fix-fast-flash-read.patch

diff --git a/target/linux/ar71xx/patches-4.1/460-spi-add-generic-flash-read.patch b/target/linux/ar71xx/patches-4.1/460-spi-add-generic-flash-read.patch
new file mode 100644
index 0000000..afc977e
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.1/460-spi-add-generic-flash-read.patch
@@ -0,0 +1,159 @@
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 47eff80..dcc6f6e 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1152,6 +1152,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
+ 		}
+ 	}
+ 
++	mutex_lock(&master->bus_lock_mutex);
+ 	trace_spi_message_start(master->cur_msg);
+ 
+ 	if (master->prepare_message) {
+@@ -1161,6 +1162,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
+ 				"failed to prepare message: %d\n", ret);
+ 			master->cur_msg->status = ret;
+ 			spi_finalize_current_message(master);
++			mutex_unlock(&master->bus_lock_mutex);
+ 			return;
+ 		}
+ 		master->cur_msg_prepared = true;
+@@ -1170,6 +1172,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
+ 	if (ret) {
+ 		master->cur_msg->status = ret;
+ 		spi_finalize_current_message(master);
++		mutex_unlock(&master->bus_lock_mutex);
+ 		return;
+ 	}
+ 
+@@ -1177,8 +1180,10 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
+ 	if (ret) {
+ 		dev_err(&master->dev,
+ 			"failed to transfer one message from queue\n");
++		mutex_unlock(&master->bus_lock_mutex);
+ 		return;
+ 	}
++	mutex_unlock(&master->bus_lock_mutex);
+ }
+ 
+ /**
+@@ -2351,6 +2356,46 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message)
+ EXPORT_SYMBOL_GPL(spi_async_locked);
+ 
+ 
++int spi_flash_read(struct spi_device *spi,
++		   struct spi_flash_read_message *msg)
++
++{
++	struct spi_master *master = spi->master;
++	int ret;
++
++	if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
++	     msg->addr_nbits == SPI_NBITS_DUAL) &&
++	    !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
++		return -EINVAL;
++	if ((msg->opcode_nbits == SPI_NBITS_QUAD ||
++	     msg->addr_nbits == SPI_NBITS_QUAD) &&
++	    !(spi->mode & SPI_TX_QUAD))
++		return -EINVAL;
++	if (msg->data_nbits == SPI_NBITS_DUAL &&
++	    !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
++		return -EINVAL;
++	if (msg->data_nbits == SPI_NBITS_QUAD &&
++	    !(spi->mode &  SPI_RX_QUAD))
++		return -EINVAL;
++
++	if (master->auto_runtime_pm) {
++		ret = pm_runtime_get_sync(master->dev.parent);
++		if (ret < 0) {
++			dev_err(&master->dev, "Failed to power device: %d\n",
++				ret);
++			return ret;
++		}
++	}
++	mutex_lock(&master->bus_lock_mutex);
++	ret = master->spi_flash_read(spi, msg);
++	mutex_unlock(&master->bus_lock_mutex);
++	if (master->auto_runtime_pm)
++		pm_runtime_put(master->dev.parent);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(spi_flash_read);
++
+ /*-------------------------------------------------------------------------*/
+ 
+ /* Utility methods for SPI master protocol drivers, layered on
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 53be3a4..ba0dee9 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -25,6 +25,7 @@
+ struct dma_chan;
+ struct spi_master;
+ struct spi_transfer;
++struct spi_flash_read_message;
+ 
+ /*
+  * INTERFACES between SPI master-side drivers and SPI infrastructure.
+@@ -361,6 +362,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
+  * @handle_err: the subsystem calls the driver to handle an error that occurs
+  *		in the generic implementation of transfer_one_message().
+  * @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.
+  * @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).
+@@ -513,6 +516,8 @@ struct spi_master {
+ 			       struct spi_message *message);
+ 	int (*unprepare_message)(struct spi_master *master,
+ 				 struct spi_message *message);
++	int (*spi_flash_read)(struct  spi_device *spi,
++			      struct spi_flash_read_message *msg);
+ 
+ 	/*
+ 	 * These hooks are for drivers that use a generic implementation
+@@ -1019,6 +1024,42 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd)
+ 	return be16_to_cpu(result);
+ }
+ 
++/**
++ * struct spi_flash_read_message - flash specific information for
++ * spi-masters that provide accelerated flash read interfaces
++ * @buf: buffer to read data
++ * @from: offset within the flash from where data is to be read
++ * @len: length of data to be read
++ * @retlen: actual length of data read
++ * @read_opcode: read_opcode to be used to communicate with flash
++ * @addr_width: number of address bytes
++ * @dummy_bytes: number of dummy bytes
++ * @opcode_nbits: number of lines to send opcode
++ * @addr_nbits: number of lines to send address
++ * @data_nbits: number of lines for data
++ */
++struct spi_flash_read_message {
++	void *buf;
++	loff_t from;
++	size_t len;
++	size_t retlen;
++	u8 read_opcode;
++	u8 addr_width;
++	u8 dummy_bytes;
++	u8 opcode_nbits;
++	u8 addr_nbits;
++	u8 data_nbits;
++};
++
++/* 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;
++}
++
++int spi_flash_read(struct spi_device *spi,
++		   struct spi_flash_read_message *msg);
++
+ /*---------------------------------------------------------------------------*/
+ 
+ /*
diff --git a/target/linux/ar71xx/patches-4.1/460-spi-bitbang-export-spi_bitbang_bufs.patch b/target/linux/ar71xx/patches-4.1/460-spi-bitbang-export-spi_bitbang_bufs.patch
deleted file mode 100644
index 4f0de01..0000000
--- a/target/linux/ar71xx/patches-4.1/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
-@@ -230,13 +230,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.1/461-m25p80-add-flash-read.patch b/target/linux/ar71xx/patches-4.1/461-m25p80-add-flash-read.patch
new file mode 100644
index 0000000..46c6928
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.1/461-m25p80-add-flash-read.patch
@@ -0,0 +1,33 @@
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index c9c3b7f..9d68544 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -131,6 +131,28 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+ 	/* convert the dummy cycles to the number of bytes */
+ 	dummy /= 8;
+ 
++	if (spi_flash_read_supported(spi)) {
++		struct spi_flash_read_message msg;
++		int ret;
++
++		memset(&msg, 0, sizeof(msg));
++
++		msg.buf = buf;
++		msg.from = from;
++		msg.len = len;
++		msg.read_opcode = nor->read_opcode;
++		msg.addr_width = nor->addr_width;
++		msg.dummy_bytes = dummy;
++		/* TODO: Support other combinations */
++		msg.opcode_nbits = SPI_NBITS_SINGLE;
++		msg.addr_nbits = SPI_NBITS_SINGLE;
++		msg.data_nbits = m25p80_rx_nbits(nor);
++
++		ret = spi_flash_read(spi, &msg);
++		*retlen = msg.retlen;
++		return ret;
++	}
++
+ 	spi_message_init(&m);
+ 	memset(t, 0, (sizeof t));
+ 
diff --git a/target/linux/ar71xx/patches-4.1/461-spi-add-type-field-to-spi_transfer.patch b/target/linux/ar71xx/patches-4.1/461-spi-add-type-field-to-spi_transfer.patch
deleted file mode 100644
index ce1b69c..0000000
--- a/target/linux/ar71xx/patches-4.1/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
-@@ -506,6 +506,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
-  *
-@@ -626,6 +632,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.1/462-mtd-m25p80-set-spi-transfer-type.patch b/target/linux/ar71xx/patches-4.1/462-mtd-m25p80-set-spi-transfer-type.patch
deleted file mode 100644
index 11bf9ff..0000000
--- a/target/linux/ar71xx/patches-4.1/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.1/462-spi-extend-ath79_spi.patch b/target/linux/ar71xx/patches-4.1/462-spi-extend-ath79_spi.patch
new file mode 100644
index 0000000..312d7be
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.1/462-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.1/463-spi-ath79-add-fast-flash-read.patch b/target/linux/ar71xx/patches-4.1/463-spi-ath79-add-fast-flash-read.patch
deleted file mode 100644
index 0e0e28f..0000000
--- a/target/linux/ar71xx/patches-4.1/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)
-@@ -224,6 +231,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;
-@@ -246,6 +357,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;
-@@ -255,7 +368,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);
-@@ -280,7 +393,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.1/463-spi-ath79-fast-flash-read.patch b/target/linux/ar71xx/patches-4.1/463-spi-ath79-fast-flash-read.patch
new file mode 100644
index 0000000..fdc9516
--- /dev/null
+++ b/target/linux/ar71xx/patches-4.1/463-spi-ath79-fast-flash-read.patch
@@ -0,0 +1,94 @@
+diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+index 259fd2d..a3edba7 100644
+--- 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/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
+index d72a4d1..695fc86 100644
+--- 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/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index c987e2e..531fe2d 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -296,6 +296,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).
+@@ -443,6 +444,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
+@@ -959,7 +961,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
+
diff --git a/target/linux/ar71xx/patches-4.1/464-spi-ath79-fix-fast-flash-read.patch b/target/linux/ar71xx/patches-4.1/464-spi-ath79-fix-fast-flash-read.patch
deleted file mode 100644
index 758d231..0000000
--- a/target/linux/ar71xx/patches-4.1/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
-@@ -260,6 +260,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
-@@ -633,6 +633,7 @@ struct spi_transfer {
- 	u16		delay_usecs;
- 	u32		speed_hz;
- 	enum spi_transfer_type type;
-+	bool dummy;
- 
- 	struct list_head transfer_list;
- };
-- 
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