This implements more efficient reads of SPI-attached flash content.

Signed-off-by: Rafał Miłecki <[email protected]>
---
 drivers/spi/spi-bcm53xx.c | 73 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c
index cc3f938..3bc7b77 100644
--- a/drivers/spi/spi-bcm53xx.c
+++ b/drivers/spi/spi-bcm53xx.c
@@ -17,8 +17,10 @@
 struct bcm53xxspi {
        struct bcma_device *core;
        struct spi_master *master;
+       void __iomem *mmio_base;
 
        size_t read_offset;
+       bool bspi;                              /* Boot SPI mode with memory 
mapping */
 };
 
 static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
@@ -32,6 +34,50 @@ static inline void bcm53xxspi_write(struct bcm53xxspi 
*b53spi, u16 offset,
        bcma_write32(b53spi->core, offset, value);
 }
 
+static void bcm53xxspi_disable_bspi(struct bcm53xxspi *b53spi)
+{
+       struct device *dev = &b53spi->core->dev;
+       unsigned long deadline;
+       u32 tmp;
+
+       if (!b53spi->bspi)
+               return;
+
+       tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
+       if (tmp & 0x1)
+               return;
+
+       deadline = jiffies + usecs_to_jiffies(200);
+       do {
+               tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_BUSY_STATUS);
+               if (!(tmp & 0x1)) {
+                       bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL,
+                                        0x1);
+                       ndelay(200);
+                       b53spi->bspi = false;
+                       return;
+               }
+               udelay(1);
+       } while (!time_after_eq(jiffies, deadline));
+
+       dev_warn(dev, "Timeout disabling BSPI\n");
+}
+
+static void bcm53xxspi_enable_bspi(struct bcm53xxspi *b53spi)
+{
+       u32 tmp;
+
+       if (b53spi->bspi)
+               return;
+
+       tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
+       if (!(tmp & 0x1))
+               return;
+
+       bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, 0x0);
+       b53spi->bspi = true;
+}
+
 static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
 {
        /* Do some magic calculation based on length and buad. Add 10% and 1. */
@@ -176,6 +222,8 @@ static int bcm53xxspi_transfer_one(struct spi_master 
*master,
        u8 *buf;
        size_t left;
 
+       bcm53xxspi_disable_bspi(b53spi);
+
        if (t->tx_buf) {
                buf = (u8 *)t->tx_buf;
                left = t->len;
@@ -206,6 +254,19 @@ static int bcm53xxspi_transfer_one(struct spi_master 
*master,
        return 0;
 }
 
+static int bcm53xxspi_flash_read(struct spi_device *spi,
+                                struct spi_flash_read_message *msg)
+{
+       struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master);
+       int ret = 0;
+
+       bcm53xxspi_enable_bspi(b53spi);
+       memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
+       msg->retlen = msg->len;
+
+       return ret;
+}
+
 /**************************************************
  * BCMA
  **************************************************/
@@ -222,6 +283,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl);
 
 static int bcm53xxspi_bcma_probe(struct bcma_device *core)
 {
+       struct device *dev = &core->dev;
        struct bcm53xxspi *b53spi;
        struct spi_master *master;
        int err;
@@ -231,7 +293,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
                return -ENOTSUPP;
        }
 
-       master = spi_alloc_master(&core->dev, sizeof(*b53spi));
+       master = spi_alloc_master(dev, sizeof(*b53spi));
        if (!master)
                return -ENOMEM;
 
@@ -239,11 +301,18 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
        b53spi->master = master;
        b53spi->core = core;
 
+       if (core->addr_s[0])
+               b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0], SZ_32M);
+       b53spi->bspi = true;
+       bcm53xxspi_disable_bspi(b53spi);
+
        master->transfer_one = bcm53xxspi_transfer_one;
+       if (b53spi->mmio_base)
+               master->spi_flash_read = bcm53xxspi_flash_read;
 
        bcma_set_drvdata(core, b53spi);
 
-       err = devm_spi_register_master(&core->dev, master);
+       err = devm_spi_register_master(dev, master);
        if (err) {
                spi_master_put(master);
                bcma_set_drvdata(core, NULL);
-- 
1.8.4.5

Reply via email to