spi: bcm53xx: add spi_flash_read callback for MMIO-based reads

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>
This commit is contained in:
Rafał Miłecki 2016-04-18 14:39:30 +02:00 коммит произвёл Mark Brown
Родитель f55532a0c0
Коммит a7b221d8f0
1 изменённых файлов: 76 добавлений и 2 удалений

Просмотреть файл

@ -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(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 +223,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 +255,22 @@ 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;
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_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 +297,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 +305,19 @@ 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],
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);