Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7b221d8 authored by Rafał Miłecki's avatar Rafał Miłecki Committed by Mark Brown
Browse files

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



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

Signed-off-by: default avatarRafał Miłecki <zajec5@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent f55532a0
Loading
Loading
Loading
Loading
+76 −2
Original line number Diff line number Diff line
@@ -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);