aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafał Miłecki <zajec5@gmail.com>2016-04-18 08:39:30 -0400
committerMark Brown <broonie@kernel.org>2016-04-18 08:53:46 -0400
commita7b221d8f0d75511c5f959584712a5dd35f88a86 (patch)
tree1e353f731993c00e9bdd1af8ab1d65a5faf970cf /drivers
parentf55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/spi-bcm53xx.c78
1 files changed, 76 insertions, 2 deletions
diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c
index cc3f938f0a6b..afb51699dbb5 100644
--- a/drivers/spi/spi-bcm53xx.c
+++ b/drivers/spi/spi-bcm53xx.c
@@ -10,6 +10,7 @@
10#include "spi-bcm53xx.h" 10#include "spi-bcm53xx.h"
11 11
12#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */ 12#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */
13#define BCM53XXSPI_FLASH_WINDOW SZ_32M
13 14
14/* The longest observed required wait was 19 ms */ 15/* The longest observed required wait was 19 ms */
15#define BCM53XXSPI_SPE_TIMEOUT_MS 80 16#define BCM53XXSPI_SPE_TIMEOUT_MS 80
@@ -17,8 +18,10 @@
17struct bcm53xxspi { 18struct bcm53xxspi {
18 struct bcma_device *core; 19 struct bcma_device *core;
19 struct spi_master *master; 20 struct spi_master *master;
21 void __iomem *mmio_base;
20 22
21 size_t read_offset; 23 size_t read_offset;
24 bool bspi; /* Boot SPI mode with memory mapping */
22}; 25};
23 26
24static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset) 27static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
@@ -32,6 +35,50 @@ static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset,
32 bcma_write32(b53spi->core, offset, value); 35 bcma_write32(b53spi->core, offset, value);
33} 36}
34 37
38static void bcm53xxspi_disable_bspi(struct bcm53xxspi *b53spi)
39{
40 struct device *dev = &b53spi->core->dev;
41 unsigned long deadline;
42 u32 tmp;
43
44 if (!b53spi->bspi)
45 return;
46
47 tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
48 if (tmp & 0x1)
49 return;
50
51 deadline = jiffies + usecs_to_jiffies(200);
52 do {
53 tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_BUSY_STATUS);
54 if (!(tmp & 0x1)) {
55 bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL,
56 0x1);
57 ndelay(200);
58 b53spi->bspi = false;
59 return;
60 }
61 udelay(1);
62 } while (!time_after_eq(jiffies, deadline));
63
64 dev_warn(dev, "Timeout disabling BSPI\n");
65}
66
67static void bcm53xxspi_enable_bspi(struct bcm53xxspi *b53spi)
68{
69 u32 tmp;
70
71 if (b53spi->bspi)
72 return;
73
74 tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL);
75 if (!(tmp & 0x1))
76 return;
77
78 bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, 0x0);
79 b53spi->bspi = true;
80}
81
35static inline unsigned int bcm53xxspi_calc_timeout(size_t len) 82static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
36{ 83{
37 /* Do some magic calculation based on length and buad. Add 10% and 1. */ 84 /* 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,
176 u8 *buf; 223 u8 *buf;
177 size_t left; 224 size_t left;
178 225
226 bcm53xxspi_disable_bspi(b53spi);
227
179 if (t->tx_buf) { 228 if (t->tx_buf) {
180 buf = (u8 *)t->tx_buf; 229 buf = (u8 *)t->tx_buf;
181 left = t->len; 230 left = t->len;
@@ -206,6 +255,22 @@ static int bcm53xxspi_transfer_one(struct spi_master *master,
206 return 0; 255 return 0;
207} 256}
208 257
258static int bcm53xxspi_flash_read(struct spi_device *spi,
259 struct spi_flash_read_message *msg)
260{
261 struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master);
262 int ret = 0;
263
264 if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW)
265 return -EINVAL;
266
267 bcm53xxspi_enable_bspi(b53spi);
268 memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
269 msg->retlen = msg->len;
270
271 return ret;
272}
273
209/************************************************** 274/**************************************************
210 * BCMA 275 * BCMA
211 **************************************************/ 276 **************************************************/
@@ -222,6 +287,7 @@ MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl);
222 287
223static int bcm53xxspi_bcma_probe(struct bcma_device *core) 288static int bcm53xxspi_bcma_probe(struct bcma_device *core)
224{ 289{
290 struct device *dev = &core->dev;
225 struct bcm53xxspi *b53spi; 291 struct bcm53xxspi *b53spi;
226 struct spi_master *master; 292 struct spi_master *master;
227 int err; 293 int err;
@@ -231,7 +297,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
231 return -ENOTSUPP; 297 return -ENOTSUPP;
232 } 298 }
233 299
234 master = spi_alloc_master(&core->dev, sizeof(*b53spi)); 300 master = spi_alloc_master(dev, sizeof(*b53spi));
235 if (!master) 301 if (!master)
236 return -ENOMEM; 302 return -ENOMEM;
237 303
@@ -239,11 +305,19 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
239 b53spi->master = master; 305 b53spi->master = master;
240 b53spi->core = core; 306 b53spi->core = core;
241 307
308 if (core->addr_s[0])
309 b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0],
310 BCM53XXSPI_FLASH_WINDOW);
311 b53spi->bspi = true;
312 bcm53xxspi_disable_bspi(b53spi);
313
242 master->transfer_one = bcm53xxspi_transfer_one; 314 master->transfer_one = bcm53xxspi_transfer_one;
315 if (b53spi->mmio_base)
316 master->spi_flash_read = bcm53xxspi_flash_read;
243 317
244 bcma_set_drvdata(core, b53spi); 318 bcma_set_drvdata(core, b53spi);
245 319
246 err = devm_spi_register_master(&core->dev, master); 320 err = devm_spi_register_master(dev, master);
247 if (err) { 321 if (err) {
248 spi_master_put(master); 322 spi_master_put(master);
249 bcma_set_drvdata(core, NULL); 323 bcma_set_drvdata(core, NULL);