mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 14:34:27 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
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);
 |