diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2016-04-18 08:39:30 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-04-18 08:53:46 -0400 |
commit | a7b221d8f0d75511c5f959584712a5dd35f88a86 (patch) | |
tree | 1e353f731993c00e9bdd1af8ab1d65a5faf970cf /drivers/spi/spi-bcm53xx.c | |
parent | f55532a0c0b8bb6148f4e07853b876ef73bc69ca (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/spi/spi-bcm53xx.c')
-rw-r--r-- | drivers/spi/spi-bcm53xx.c | 78 |
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 @@ | |||
17 | struct bcm53xxspi { | 18 | struct 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 | ||
24 | static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset) | 27 | static 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 | ||
38 | static 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 | |||
67 | static 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 | |||
35 | static inline unsigned int bcm53xxspi_calc_timeout(size_t len) | 82 | static 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 | ||
258 | static 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 | ||
223 | static int bcm53xxspi_bcma_probe(struct bcma_device *core) | 288 | static 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); |