You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.1 KiB
157 lines
4.1 KiB
From a7b221d8f0d75511c5f959584712a5dd35f88a86 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
Date: Mon, 18 Apr 2016 14:39:30 +0200
|
|
Subject: [PATCH] spi: bcm53xx: add spi_flash_read callback for MMIO-based
|
|
reads
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This implements more efficient reads of SPI-attached flash content.
|
|
|
|
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
Signed-off-by: Mark Brown <broonie@kernel.org>
|
|
---
|
|
|
|
--- a/drivers/spi/spi-bcm53xx.c
|
|
+++ b/drivers/spi/spi-bcm53xx.c
|
|
@@ -10,6 +10,7 @@
|
|
#include "spi-bcm53xx.h"
|
|
|
|
#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */
|
|
+#define BCM53XXSPI_FLASH_WINDOW SZ_32M
|
|
|
|
/* The longest observed required wait was 19 ms */
|
|
#define BCM53XXSPI_SPE_TIMEOUT_MS 80
|
|
@@ -17,8 +18,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 +35,50 @@ static inline void bcm53xxspi_write(stru
|
|
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 +223,8 @@ static int bcm53xxspi_transfer_one(struc
|
|
u8 *buf;
|
|
size_t left;
|
|
|
|
+ bcm53xxspi_disable_bspi(b53spi);
|
|
+
|
|
if (t->tx_buf) {
|
|
buf = (u8 *)t->tx_buf;
|
|
left = t->len;
|
|
@@ -206,6 +255,22 @@ static int bcm53xxspi_transfer_one(struc
|
|
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;
|
|
+
|
|
+ if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW)
|
|
+ return -EINVAL;
|
|
+
|
|
+ bcm53xxspi_enable_bspi(b53spi);
|
|
+ memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
|
|
+ msg->retlen = msg->len;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/**************************************************
|
|
* BCMA
|
|
**************************************************/
|
|
@@ -222,6 +287,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcm
|
|
|
|
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 +297,7 @@ static int bcm53xxspi_bcma_probe(struct
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
- master = spi_alloc_master(&core->dev, sizeof(*b53spi));
|
|
+ master = spi_alloc_master(dev, sizeof(*b53spi));
|
|
if (!master)
|
|
return -ENOMEM;
|
|
|
|
@@ -239,11 +305,19 @@ static int bcm53xxspi_bcma_probe(struct
|
|
b53spi->master = master;
|
|
b53spi->core = core;
|
|
|
|
+ if (core->addr_s[0])
|
|
+ b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0],
|
|
+ BCM53XXSPI_FLASH_WINDOW);
|
|
+ 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);
|
|
|