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 <[email protected]> --- 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 [email protected] https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
