summaryrefslogtreecommitdiff
path: root/target/mips/mikrotik-rb4xx/patches/3.14.43/0020-spi-ath79-add-fast-flash-read-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/mips/mikrotik-rb4xx/patches/3.14.43/0020-spi-ath79-add-fast-flash-read-support.patch')
-rw-r--r--target/mips/mikrotik-rb4xx/patches/3.14.43/0020-spi-ath79-add-fast-flash-read-support.patch202
1 files changed, 202 insertions, 0 deletions
diff --git a/target/mips/mikrotik-rb4xx/patches/3.14.43/0020-spi-ath79-add-fast-flash-read-support.patch b/target/mips/mikrotik-rb4xx/patches/3.14.43/0020-spi-ath79-add-fast-flash-read-support.patch
new file mode 100644
index 000000000..8fd174448
--- /dev/null
+++ b/target/mips/mikrotik-rb4xx/patches/3.14.43/0020-spi-ath79-add-fast-flash-read-support.patch
@@ -0,0 +1,202 @@
+From c4388a57860440e23c9654f4de2f515433e685a1 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 04:12:35 +0200
+Subject: [PATCH] spi-ath79: add fast flash read support
+
+---
+ .../include/asm/mach-ath79/ath79_spi_platform.h | 1 +
+ drivers/spi/spi-ath79.c | 124 ++++++++++++++++++++-
+ 2 files changed, 120 insertions(+), 5 deletions(-)
+
+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 aa2283e..65369fe 100644
+--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
++++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+@@ -18,6 +18,7 @@ struct ath79_spi_platform_data {
+
+ struct ath79_spi_controller_data {
+ unsigned gpio;
++ bool is_flash;
+ };
+
+ #endif /* _ATH79_SPI_PLATFORM_H */
+diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
+index c3b2fb9..a26a6a4 100644
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -35,6 +35,11 @@
+ #define ATH79_SPI_RRW_DELAY_FACTOR 12000
+ #define MHZ (1000 * 1000)
+
++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)
+@@ -104,9 +114,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)
+@@ -203,6 +210,110 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
+ 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;
+@@ -223,6 +334,8 @@ static int ath79_spi_probe(struct platform_device *pdev)
+
+ pdata = dev_get_platdata(&pdev->dev);
+
++ 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;
+@@ -234,7 +347,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
+ 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);
+@@ -259,7 +372,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;
+--
+1.8.5.3
+