kernel: update 4.4 to 4.4.86
[openwrt/openwrt.git] / target / linux / bcm53xx / patches-4.4 / 083-0008-spi-iproc-qspi-Add-Broadcom-iProc-SoCs-support.patch
1 From cc20a38612dbc87dc7396affc9758e3bfbe92340 Mon Sep 17 00:00:00 2001
2 From: Kamal Dasu <kdasu.kdev@gmail.com>
3 Date: Wed, 24 Aug 2016 18:04:29 -0400
4 Subject: [PATCH] spi: iproc-qspi: Add Broadcom iProc SoCs support
5
6 This spi driver uses the common spi-bcm-qspi driver and implements iProc
7 SoCs specific interrupt controller. The common driver now calls the SoC
8 handlers when present. Adding support for both muxed l1 and unmuxed interrupt
9 sources.
10
11 Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
12 Signed-off-by: Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com>
13 Signed-off-by: Mark Brown <broonie@kernel.org>
14 ---
15 drivers/spi/Makefile | 2 +-
16 drivers/spi/spi-bcm-qspi.c | 97 ++++++++++++++++++++++++-
17 drivers/spi/spi-bcm-qspi.h | 34 ++++++++-
18 drivers/spi/spi-iproc-qspi.c | 163 +++++++++++++++++++++++++++++++++++++++++++
19 4 files changed, 291 insertions(+), 5 deletions(-)
20 create mode 100644 drivers/spi/spi-iproc-qspi.c
21
22 --- a/drivers/spi/Makefile
23 +++ b/drivers/spi/Makefile
24 @@ -19,7 +19,7 @@ obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm
25 obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o
26 obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
27 obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
28 -obj-$(CONFIG_SPI_BCM_QSPI) += spi-brcmstb-qspi.o spi-bcm-qspi.o
29 +obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o
30 obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
31 obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o
32 obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
33 --- a/drivers/spi/spi-bcm-qspi.c
34 +++ b/drivers/spi/spi-bcm-qspi.c
35 @@ -175,9 +175,15 @@ enum base_type {
36 BASEMAX,
37 };
38
39 +enum irq_source {
40 + SINGLE_L2,
41 + MUXED_L1,
42 +};
43 +
44 struct bcm_qspi_irq {
45 const char *irq_name;
46 const irq_handler_t irq_handler;
47 + int irq_source;
48 u32 mask;
49 };
50
51 @@ -198,6 +204,10 @@ struct bcm_qspi {
52 u32 base_clk;
53 u32 max_speed_hz;
54 void __iomem *base[BASEMAX];
55 +
56 + /* Some SoCs provide custom interrupt status register(s) */
57 + struct bcm_qspi_soc_intc *soc_intc;
58 +
59 struct bcm_qspi_parms last_parms;
60 struct qspi_trans trans_pos;
61 int curr_cs;
62 @@ -806,6 +816,7 @@ static int bcm_qspi_bspi_flash_read(stru
63 u32 addr = 0, len, len_words;
64 int ret = 0;
65 unsigned long timeo = msecs_to_jiffies(100);
66 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
67
68 if (bcm_qspi_bspi_ver_three(qspi))
69 if (msg->addr_width == BSPI_ADDRLEN_4BYTES)
70 @@ -850,6 +861,15 @@ static int bcm_qspi_bspi_flash_read(stru
71 bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words);
72 bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0);
73
74 + if (qspi->soc_intc) {
75 + /*
76 + * clear soc MSPI and BSPI interrupts and enable
77 + * BSPI interrupts.
78 + */
79 + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
80 + soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true);
81 + }
82 +
83 /* Must flush previous writes before starting BSPI operation */
84 mb();
85
86 @@ -952,9 +972,12 @@ static irqreturn_t bcm_qspi_mspi_l2_isr(
87 u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
88
89 if (status & MSPI_MSPI_STATUS_SPIF) {
90 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
91 /* clear interrupt */
92 status &= ~MSPI_MSPI_STATUS_SPIF;
93 bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status);
94 + if (qspi->soc_intc)
95 + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_DONE);
96 complete(&qspi->mspi_done);
97 return IRQ_HANDLED;
98 }
99 @@ -966,20 +989,33 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_i
100 {
101 struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
102 struct bcm_qspi *qspi = qspi_dev_id->dev;
103 - u32 status;
104 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
105 + u32 status = qspi_dev_id->irqp->mask;
106
107 if (qspi->bspi_enabled && qspi->bspi_rf_msg) {
108 bcm_qspi_bspi_lr_data_read(qspi);
109 if (qspi->bspi_rf_msg_len == 0) {
110 qspi->bspi_rf_msg = NULL;
111 + if (qspi->soc_intc) {
112 + /* disable soc BSPI interrupt */
113 + soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE,
114 + false);
115 + /* indicate done */
116 + status = INTR_BSPI_LR_SESSION_DONE_MASK;
117 + }
118 +
119 if (qspi->bspi_rf_msg_status)
120 bcm_qspi_bspi_lr_clear(qspi);
121 else
122 bcm_qspi_bspi_flush_prefetch_buffers(qspi);
123 }
124 +
125 + if (qspi->soc_intc)
126 + /* clear soc BSPI interrupt */
127 + soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_DONE);
128 }
129
130 - status = (qspi_dev_id->irqp->mask & INTR_BSPI_LR_SESSION_DONE_MASK);
131 + status &= INTR_BSPI_LR_SESSION_DONE_MASK;
132 if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0)
133 complete(&qspi->bspi_done);
134
135 @@ -990,13 +1026,39 @@ static irqreturn_t bcm_qspi_bspi_lr_err_
136 {
137 struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
138 struct bcm_qspi *qspi = qspi_dev_id->dev;
139 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
140
141 dev_err(&qspi->pdev->dev, "BSPI INT error\n");
142 qspi->bspi_rf_msg_status = -EIO;
143 + if (qspi->soc_intc)
144 + /* clear soc interrupt */
145 + soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR);
146 +
147 complete(&qspi->bspi_done);
148 return IRQ_HANDLED;
149 }
150
151 +static irqreturn_t bcm_qspi_l1_isr(int irq, void *dev_id)
152 +{
153 + struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
154 + struct bcm_qspi *qspi = qspi_dev_id->dev;
155 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
156 + irqreturn_t ret = IRQ_NONE;
157 +
158 + if (soc_intc) {
159 + u32 status = soc_intc->bcm_qspi_get_int_status(soc_intc);
160 +
161 + if (status & MSPI_DONE)
162 + ret = bcm_qspi_mspi_l2_isr(irq, dev_id);
163 + else if (status & BSPI_DONE)
164 + ret = bcm_qspi_bspi_lr_l2_isr(irq, dev_id);
165 + else if (status & BSPI_ERR)
166 + ret = bcm_qspi_bspi_lr_err_l2_isr(irq, dev_id);
167 + }
168 +
169 + return ret;
170 +}
171 +
172 static const struct bcm_qspi_irq qspi_irq_tab[] = {
173 {
174 .irq_name = "spi_lr_fullness_reached",
175 @@ -1036,6 +1098,13 @@ static const struct bcm_qspi_irq qspi_ir
176 .irq_handler = bcm_qspi_mspi_l2_isr,
177 .mask = INTR_MSPI_HALTED_MASK,
178 },
179 + {
180 + /* single muxed L1 interrupt source */
181 + .irq_name = "spi_l1_intr",
182 + .irq_handler = bcm_qspi_l1_isr,
183 + .irq_source = MUXED_L1,
184 + .mask = QSPI_INTERRUPTS_ALL,
185 + },
186 };
187
188 static void bcm_qspi_bspi_init(struct bcm_qspi *qspi)
189 @@ -1182,7 +1251,13 @@ int bcm_qspi_probe(struct platform_devic
190 for (val = 0; val < num_irqs; val++) {
191 irq = -1;
192 name = qspi_irq_tab[val].irq_name;
193 - irq = platform_get_irq_byname(pdev, name);
194 + if (qspi_irq_tab[val].irq_source == SINGLE_L2) {
195 + /* get the l2 interrupts */
196 + irq = platform_get_irq_byname(pdev, name);
197 + } else if (!num_ints && soc_intc) {
198 + /* all mspi, bspi intrs muxed to one L1 intr */
199 + irq = platform_get_irq(pdev, 0);
200 + }
201
202 if (irq >= 0) {
203 ret = devm_request_irq(&pdev->dev, irq,
204 @@ -1209,6 +1284,17 @@ int bcm_qspi_probe(struct platform_devic
205 goto qspi_probe_err;
206 }
207
208 + /*
209 + * Some SoCs integrate spi controller (e.g., its interrupt bits)
210 + * in specific ways
211 + */
212 + if (soc_intc) {
213 + qspi->soc_intc = soc_intc;
214 + soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
215 + } else {
216 + qspi->soc_intc = NULL;
217 + }
218 +
219 qspi->clk = devm_clk_get(&pdev->dev, NULL);
220 if (IS_ERR(qspi->clk)) {
221 dev_warn(dev, "unable to get clock\n");
222 @@ -1288,6 +1374,11 @@ static int __maybe_unused bcm_qspi_resum
223
224 bcm_qspi_hw_init(qspi);
225 bcm_qspi_chip_select(qspi, qspi->curr_cs);
226 + if (qspi->soc_intc)
227 + /* enable MSPI interrupt */
228 + qspi->soc_intc->bcm_qspi_int_set(qspi->soc_intc, MSPI_DONE,
229 + true);
230 +
231 ret = clk_enable(qspi->clk);
232 if (!ret)
233 spi_master_resume(qspi->master);
234 --- a/drivers/spi/spi-bcm-qspi.h
235 +++ b/drivers/spi/spi-bcm-qspi.h
236 @@ -48,10 +48,26 @@
237 (INTR_MSPI_DONE_MASK | \
238 INTR_MSPI_HALTED_MASK)
239
240 +#define QSPI_INTERRUPTS_ALL \
241 + (MSPI_INTERRUPTS_ALL | \
242 + BSPI_LR_INTERRUPTS_ALL)
243 +
244 struct platform_device;
245 struct dev_pm_ops;
246
247 -struct bcm_qspi_soc_intc;
248 +enum {
249 + MSPI_DONE = 0x1,
250 + BSPI_DONE = 0x2,
251 + BSPI_ERR = 0x4,
252 + MSPI_BSPI_DONE = 0x7
253 +};
254 +
255 +struct bcm_qspi_soc_intc {
256 + void (*bcm_qspi_int_ack)(struct bcm_qspi_soc_intc *soc_intc, int type);
257 + void (*bcm_qspi_int_set)(struct bcm_qspi_soc_intc *soc_intc, int type,
258 + bool en);
259 + u32 (*bcm_qspi_get_int_status)(struct bcm_qspi_soc_intc *soc_intc);
260 +};
261
262 /* Read controller register*/
263 static inline u32 bcm_qspi_readl(bool be, void __iomem *addr)
264 @@ -72,6 +88,22 @@ static inline void bcm_qspi_writel(bool
265 writel_relaxed(data, addr);
266 }
267
268 +static inline u32 get_qspi_mask(int type)
269 +{
270 + switch (type) {
271 + case MSPI_DONE:
272 + return INTR_MSPI_DONE_MASK;
273 + case BSPI_DONE:
274 + return BSPI_LR_INTERRUPTS_ALL;
275 + case MSPI_BSPI_DONE:
276 + return QSPI_INTERRUPTS_ALL;
277 + case BSPI_ERR:
278 + return BSPI_LR_INTERRUPTS_ERROR;
279 + }
280 +
281 + return 0;
282 +}
283 +
284 /* The common driver functions to be called by the SoC platform driver */
285 int bcm_qspi_probe(struct platform_device *pdev,
286 struct bcm_qspi_soc_intc *soc_intc);
287 --- /dev/null
288 +++ b/drivers/spi/spi-iproc-qspi.c
289 @@ -0,0 +1,163 @@
290 +/*
291 + * Copyright 2016 Broadcom Limited
292 + *
293 + * This program is free software; you can redistribute it and/or modify
294 + * it under the terms of the GNU General Public License version 2 as
295 + * published by the Free Software Foundation.
296 + *
297 + * This program is distributed in the hope that it will be useful,
298 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
299 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
300 + * GNU General Public License for more details.
301 + */
302 +
303 +#include <linux/device.h>
304 +#include <linux/io.h>
305 +#include <linux/ioport.h>
306 +#include <linux/module.h>
307 +#include <linux/of.h>
308 +#include <linux/of_address.h>
309 +#include <linux/platform_device.h>
310 +#include <linux/slab.h>
311 +
312 +#include "spi-bcm-qspi.h"
313 +
314 +#define INTR_BASE_BIT_SHIFT 0x02
315 +#define INTR_COUNT 0x07
316 +
317 +struct bcm_iproc_intc {
318 + struct bcm_qspi_soc_intc soc_intc;
319 + struct platform_device *pdev;
320 + void __iomem *int_reg;
321 + void __iomem *int_status_reg;
322 + spinlock_t soclock;
323 + bool big_endian;
324 +};
325 +
326 +static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc)
327 +{
328 + struct bcm_iproc_intc *priv =
329 + container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
330 + void __iomem *mmio = priv->int_status_reg;
331 + int i;
332 + u32 val = 0, sts = 0;
333 +
334 + for (i = 0; i < INTR_COUNT; i++) {
335 + if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4)))
336 + val |= 1UL << i;
337 + }
338 +
339 + if (val & INTR_MSPI_DONE_MASK)
340 + sts |= MSPI_DONE;
341 +
342 + if (val & BSPI_LR_INTERRUPTS_ALL)
343 + sts |= BSPI_DONE;
344 +
345 + if (val & BSPI_LR_INTERRUPTS_ERROR)
346 + sts |= BSPI_ERR;
347 +
348 + return sts;
349 +}
350 +
351 +static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type)
352 +{
353 + struct bcm_iproc_intc *priv =
354 + container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
355 + void __iomem *mmio = priv->int_status_reg;
356 + u32 mask = get_qspi_mask(type);
357 + int i;
358 +
359 + for (i = 0; i < INTR_COUNT; i++) {
360 + if (mask & (1UL << i))
361 + bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4));
362 + }
363 +}
364 +
365 +static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type,
366 + bool en)
367 +{
368 + struct bcm_iproc_intc *priv =
369 + container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
370 + void __iomem *mmio = priv->int_reg;
371 + u32 mask = get_qspi_mask(type);
372 + u32 val;
373 + unsigned long flags;
374 +
375 + spin_lock_irqsave(&priv->soclock, flags);
376 +
377 + val = bcm_qspi_readl(priv->big_endian, mmio);
378 +
379 + if (en)
380 + val = val | (mask << INTR_BASE_BIT_SHIFT);
381 + else
382 + val = val & ~(mask << INTR_BASE_BIT_SHIFT);
383 +
384 + bcm_qspi_writel(priv->big_endian, val, mmio);
385 +
386 + spin_unlock_irqrestore(&priv->soclock, flags);
387 +}
388 +
389 +static int bcm_iproc_probe(struct platform_device *pdev)
390 +{
391 + struct device *dev = &pdev->dev;
392 + struct bcm_iproc_intc *priv;
393 + struct bcm_qspi_soc_intc *soc_intc;
394 + struct resource *res;
395 +
396 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
397 + if (!priv)
398 + return -ENOMEM;
399 + soc_intc = &priv->soc_intc;
400 + priv->pdev = pdev;
401 +
402 + spin_lock_init(&priv->soclock);
403 +
404 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs");
405 + priv->int_reg = devm_ioremap_resource(dev, res);
406 + if (IS_ERR(priv->int_reg))
407 + return PTR_ERR(priv->int_reg);
408 +
409 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
410 + "intr_status_reg");
411 + priv->int_status_reg = devm_ioremap_resource(dev, res);
412 + if (IS_ERR(priv->int_status_reg))
413 + return PTR_ERR(priv->int_status_reg);
414 +
415 + priv->big_endian = of_device_is_big_endian(dev->of_node);
416 +
417 + bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
418 + bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false);
419 +
420 + soc_intc->bcm_qspi_int_ack = bcm_iproc_qspi_int_ack;
421 + soc_intc->bcm_qspi_int_set = bcm_iproc_qspi_int_set;
422 + soc_intc->bcm_qspi_get_int_status = bcm_iproc_qspi_get_l2_int_status;
423 +
424 + return bcm_qspi_probe(pdev, soc_intc);
425 +}
426 +
427 +static int bcm_iproc_remove(struct platform_device *pdev)
428 +{
429 + return bcm_qspi_remove(pdev);
430 +}
431 +
432 +static const struct of_device_id bcm_iproc_of_match[] = {
433 + { .compatible = "brcm,spi-nsp-qspi" },
434 + { .compatible = "brcm,spi-ns2-qspi" },
435 + {},
436 +};
437 +MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
438 +
439 +static struct platform_driver bcm_iproc_driver = {
440 + .probe = bcm_iproc_probe,
441 + .remove = bcm_iproc_remove,
442 + .driver = {
443 + .name = "bcm_iproc",
444 + .pm = &bcm_qspi_pm_ops,
445 + .of_match_table = bcm_iproc_of_match,
446 + }
447 +};
448 +module_platform_driver(bcm_iproc_driver);
449 +
450 +MODULE_LICENSE("GPL v2");
451 +MODULE_AUTHOR("Kamal Dasu");
452 +MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");