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
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
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>
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
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 {
46 const irq_handler_t irq_handler;
51 @@ -198,6 +204,10 @@ struct bcm_qspi {
54 void __iomem *base[BASEMAX];
56 + /* Some SoCs provide custom interrupt status register(s) */
57 + struct bcm_qspi_soc_intc *soc_intc;
59 struct bcm_qspi_parms last_parms;
60 struct qspi_trans trans_pos;
62 @@ -806,6 +816,7 @@ static int bcm_qspi_bspi_flash_read(stru
63 u32 addr = 0, len, len_words;
65 unsigned long timeo = msecs_to_jiffies(100);
66 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
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);
74 + if (qspi->soc_intc) {
76 + * clear soc MSPI and BSPI interrupts and enable
79 + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
80 + soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true);
83 /* Must flush previous writes before starting BSPI operation */
86 @@ -952,9 +972,12 @@ static irqreturn_t bcm_qspi_mspi_l2_isr(
87 u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
89 if (status & MSPI_MSPI_STATUS_SPIF) {
90 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
92 status &= ~MSPI_MSPI_STATUS_SPIF;
93 bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status);
95 + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_DONE);
96 complete(&qspi->mspi_done);
99 @@ -966,20 +989,33 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_i
101 struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
102 struct bcm_qspi *qspi = qspi_dev_id->dev;
104 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
105 + u32 status = qspi_dev_id->irqp->mask;
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,
115 + /* indicate done */
116 + status = INTR_BSPI_LR_SESSION_DONE_MASK;
119 if (qspi->bspi_rf_msg_status)
120 bcm_qspi_bspi_lr_clear(qspi);
122 bcm_qspi_bspi_flush_prefetch_buffers(qspi);
125 + if (qspi->soc_intc)
126 + /* clear soc BSPI interrupt */
127 + soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_DONE);
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);
135 @@ -990,13 +1026,39 @@ static irqreturn_t bcm_qspi_bspi_lr_err_
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;
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);
147 complete(&qspi->bspi_done);
151 +static irqreturn_t bcm_qspi_l1_isr(int irq, void *dev_id)
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;
159 + u32 status = soc_intc->bcm_qspi_get_int_status(soc_intc);
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);
172 static const struct bcm_qspi_irq qspi_irq_tab[] = {
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,
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,
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++) {
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);
203 ret = devm_request_irq(&pdev->dev, irq,
204 @@ -1209,6 +1284,17 @@ int bcm_qspi_probe(struct platform_devic
209 + * Some SoCs integrate spi controller (e.g., its interrupt bits)
213 + qspi->soc_intc = soc_intc;
214 + soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
216 + qspi->soc_intc = NULL;
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
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,
231 ret = clk_enable(qspi->clk);
233 spi_master_resume(qspi->master);
234 --- a/drivers/spi/spi-bcm-qspi.h
235 +++ b/drivers/spi/spi-bcm-qspi.h
237 (INTR_MSPI_DONE_MASK | \
238 INTR_MSPI_HALTED_MASK)
240 +#define QSPI_INTERRUPTS_ALL \
241 + (MSPI_INTERRUPTS_ALL | \
242 + BSPI_LR_INTERRUPTS_ALL)
244 struct platform_device;
247 -struct bcm_qspi_soc_intc;
252 + MSPI_BSPI_DONE = 0x7
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,
259 + u32 (*bcm_qspi_get_int_status)(struct bcm_qspi_soc_intc *soc_intc);
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);
268 +static inline u32 get_qspi_mask(int type)
272 + return INTR_MSPI_DONE_MASK;
274 + return BSPI_LR_INTERRUPTS_ALL;
275 + case MSPI_BSPI_DONE:
276 + return QSPI_INTERRUPTS_ALL;
278 + return BSPI_LR_INTERRUPTS_ERROR;
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);
288 +++ b/drivers/spi/spi-iproc-qspi.c
291 + * Copyright 2016 Broadcom Limited
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.
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.
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>
312 +#include "spi-bcm-qspi.h"
314 +#define INTR_BASE_BIT_SHIFT 0x02
315 +#define INTR_COUNT 0x07
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;
326 +static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc)
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;
332 + u32 val = 0, sts = 0;
334 + for (i = 0; i < INTR_COUNT; i++) {
335 + if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4)))
339 + if (val & INTR_MSPI_DONE_MASK)
342 + if (val & BSPI_LR_INTERRUPTS_ALL)
345 + if (val & BSPI_LR_INTERRUPTS_ERROR)
351 +static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type)
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);
359 + for (i = 0; i < INTR_COUNT; i++) {
360 + if (mask & (1UL << i))
361 + bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4));
365 +static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type,
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);
373 + unsigned long flags;
375 + spin_lock_irqsave(&priv->soclock, flags);
377 + val = bcm_qspi_readl(priv->big_endian, mmio);
380 + val = val | (mask << INTR_BASE_BIT_SHIFT);
382 + val = val & ~(mask << INTR_BASE_BIT_SHIFT);
384 + bcm_qspi_writel(priv->big_endian, val, mmio);
386 + spin_unlock_irqrestore(&priv->soclock, flags);
389 +static int bcm_iproc_probe(struct platform_device *pdev)
391 + struct device *dev = &pdev->dev;
392 + struct bcm_iproc_intc *priv;
393 + struct bcm_qspi_soc_intc *soc_intc;
394 + struct resource *res;
396 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
399 + soc_intc = &priv->soc_intc;
402 + spin_lock_init(&priv->soclock);
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);
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);
415 + priv->big_endian = of_device_is_big_endian(dev->of_node);
417 + bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
418 + bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false);
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;
424 + return bcm_qspi_probe(pdev, soc_intc);
427 +static int bcm_iproc_remove(struct platform_device *pdev)
429 + return bcm_qspi_remove(pdev);
432 +static const struct of_device_id bcm_iproc_of_match[] = {
433 + { .compatible = "brcm,spi-nsp-qspi" },
434 + { .compatible = "brcm,spi-ns2-qspi" },
437 +MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
439 +static struct platform_driver bcm_iproc_driver = {
440 + .probe = bcm_iproc_probe,
441 + .remove = bcm_iproc_remove,
443 + .name = "bcm_iproc",
444 + .pm = &bcm_qspi_pm_ops,
445 + .of_match_table = bcm_iproc_of_match,
448 +module_platform_driver(bcm_iproc_driver);
450 +MODULE_LICENSE("GPL v2");
451 +MODULE_AUTHOR("Kamal Dasu");
452 +MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");