Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: iproc-qspi: Add Broadcom iProc SoCs support

This spi driver uses the common spi-bcm-qspi driver and implements iProc
SoCs specific interrupt controller. The common driver now calls the SoC
handlers when present. Adding support for both muxed l1 and unmuxed interrupt
sources.

Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Signed-off-by: Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Kamal Dasu and committed by
Mark Brown
cc20a386 71b8f350

+291 -5
+1 -1
drivers/spi/Makefile
··· 21 21 obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o 22 22 obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o 23 23 obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o 24 - obj-$(CONFIG_SPI_BCM_QSPI) += spi-brcmstb-qspi.o spi-bcm-qspi.o 24 + obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o 25 25 obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o 26 26 obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o 27 27 obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
+94 -3
drivers/spi/spi-bcm-qspi.c
··· 175 175 BASEMAX, 176 176 }; 177 177 178 + enum irq_source { 179 + SINGLE_L2, 180 + MUXED_L1, 181 + }; 182 + 178 183 struct bcm_qspi_irq { 179 184 const char *irq_name; 180 185 const irq_handler_t irq_handler; 186 + int irq_source; 181 187 u32 mask; 182 188 }; 183 189 ··· 204 198 u32 base_clk; 205 199 u32 max_speed_hz; 206 200 void __iomem *base[BASEMAX]; 201 + 202 + /* Some SoCs provide custom interrupt status register(s) */ 203 + struct bcm_qspi_soc_intc *soc_intc; 204 + 207 205 struct bcm_qspi_parms last_parms; 208 206 struct qspi_trans trans_pos; 209 207 int curr_cs; ··· 816 806 u32 addr = 0, len, len_words; 817 807 int ret = 0; 818 808 unsigned long timeo = msecs_to_jiffies(100); 809 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; 819 810 820 811 if (bcm_qspi_bspi_ver_three(qspi)) 821 812 if (msg->addr_width == BSPI_ADDRLEN_4BYTES) ··· 860 849 bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr); 861 850 bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words); 862 851 bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0); 852 + 853 + if (qspi->soc_intc) { 854 + /* 855 + * clear soc MSPI and BSPI interrupts and enable 856 + * BSPI interrupts. 857 + */ 858 + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); 859 + soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true); 860 + } 863 861 864 862 /* Must flush previous writes before starting BSPI operation */ 865 863 mb(); ··· 972 952 u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS); 973 953 974 954 if (status & MSPI_MSPI_STATUS_SPIF) { 955 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; 975 956 /* clear interrupt */ 976 957 status &= ~MSPI_MSPI_STATUS_SPIF; 977 958 bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status); 959 + if (qspi->soc_intc) 960 + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_DONE); 978 961 complete(&qspi->mspi_done); 979 962 return IRQ_HANDLED; 980 963 } ··· 989 966 { 990 967 struct bcm_qspi_dev_id *qspi_dev_id = dev_id; 991 968 struct bcm_qspi *qspi = qspi_dev_id->dev; 992 - u32 status; 969 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; 970 + u32 status = qspi_dev_id->irqp->mask; 993 971 994 972 if (qspi->bspi_enabled && qspi->bspi_rf_msg) { 995 973 bcm_qspi_bspi_lr_data_read(qspi); 996 974 if (qspi->bspi_rf_msg_len == 0) { 997 975 qspi->bspi_rf_msg = NULL; 976 + if (qspi->soc_intc) { 977 + /* disable soc BSPI interrupt */ 978 + soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, 979 + false); 980 + /* indicate done */ 981 + status = INTR_BSPI_LR_SESSION_DONE_MASK; 982 + } 983 + 998 984 if (qspi->bspi_rf_msg_status) 999 985 bcm_qspi_bspi_lr_clear(qspi); 1000 986 else 1001 987 bcm_qspi_bspi_flush_prefetch_buffers(qspi); 1002 988 } 989 + 990 + if (qspi->soc_intc) 991 + /* clear soc BSPI interrupt */ 992 + soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_DONE); 1003 993 } 1004 994 1005 - status = (qspi_dev_id->irqp->mask & INTR_BSPI_LR_SESSION_DONE_MASK); 995 + status &= INTR_BSPI_LR_SESSION_DONE_MASK; 1006 996 if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0) 1007 997 complete(&qspi->bspi_done); 1008 998 ··· 1026 990 { 1027 991 struct bcm_qspi_dev_id *qspi_dev_id = dev_id; 1028 992 struct bcm_qspi *qspi = qspi_dev_id->dev; 993 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; 1029 994 1030 995 dev_err(&qspi->pdev->dev, "BSPI INT error\n"); 1031 996 qspi->bspi_rf_msg_status = -EIO; 997 + if (qspi->soc_intc) 998 + /* clear soc interrupt */ 999 + soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR); 1000 + 1032 1001 complete(&qspi->bspi_done); 1033 1002 return IRQ_HANDLED; 1003 + } 1004 + 1005 + static irqreturn_t bcm_qspi_l1_isr(int irq, void *dev_id) 1006 + { 1007 + struct bcm_qspi_dev_id *qspi_dev_id = dev_id; 1008 + struct bcm_qspi *qspi = qspi_dev_id->dev; 1009 + struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; 1010 + irqreturn_t ret = IRQ_NONE; 1011 + 1012 + if (soc_intc) { 1013 + u32 status = soc_intc->bcm_qspi_get_int_status(soc_intc); 1014 + 1015 + if (status & MSPI_DONE) 1016 + ret = bcm_qspi_mspi_l2_isr(irq, dev_id); 1017 + else if (status & BSPI_DONE) 1018 + ret = bcm_qspi_bspi_lr_l2_isr(irq, dev_id); 1019 + else if (status & BSPI_ERR) 1020 + ret = bcm_qspi_bspi_lr_err_l2_isr(irq, dev_id); 1021 + } 1022 + 1023 + return ret; 1034 1024 } 1035 1025 1036 1026 static const struct bcm_qspi_irq qspi_irq_tab[] = { ··· 1097 1035 .irq_name = "mspi_halted", 1098 1036 .irq_handler = bcm_qspi_mspi_l2_isr, 1099 1037 .mask = INTR_MSPI_HALTED_MASK, 1038 + }, 1039 + { 1040 + /* single muxed L1 interrupt source */ 1041 + .irq_name = "spi_l1_intr", 1042 + .irq_handler = bcm_qspi_l1_isr, 1043 + .irq_source = MUXED_L1, 1044 + .mask = QSPI_INTERRUPTS_ALL, 1100 1045 }, 1101 1046 }; 1102 1047 ··· 1251 1182 for (val = 0; val < num_irqs; val++) { 1252 1183 irq = -1; 1253 1184 name = qspi_irq_tab[val].irq_name; 1254 - irq = platform_get_irq_byname(pdev, name); 1185 + if (qspi_irq_tab[val].irq_source == SINGLE_L2) { 1186 + /* get the l2 interrupts */ 1187 + irq = platform_get_irq_byname(pdev, name); 1188 + } else if (!num_ints && soc_intc) { 1189 + /* all mspi, bspi intrs muxed to one L1 intr */ 1190 + irq = platform_get_irq(pdev, 0); 1191 + } 1255 1192 1256 1193 if (irq >= 0) { 1257 1194 ret = devm_request_irq(&pdev->dev, irq, ··· 1282 1207 dev_err(&pdev->dev, "no IRQs registered, cannot init driver\n"); 1283 1208 ret = -EINVAL; 1284 1209 goto qspi_probe_err; 1210 + } 1211 + 1212 + /* 1213 + * Some SoCs integrate spi controller (e.g., its interrupt bits) 1214 + * in specific ways 1215 + */ 1216 + if (soc_intc) { 1217 + qspi->soc_intc = soc_intc; 1218 + soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true); 1219 + } else { 1220 + qspi->soc_intc = NULL; 1285 1221 } 1286 1222 1287 1223 qspi->clk = devm_clk_get(&pdev->dev, NULL); ··· 1374 1288 1375 1289 bcm_qspi_hw_init(qspi); 1376 1290 bcm_qspi_chip_select(qspi, qspi->curr_cs); 1291 + if (qspi->soc_intc) 1292 + /* enable MSPI interrupt */ 1293 + qspi->soc_intc->bcm_qspi_int_set(qspi->soc_intc, MSPI_DONE, 1294 + true); 1295 + 1377 1296 ret = clk_enable(qspi->clk); 1378 1297 if (!ret) 1379 1298 spi_master_resume(qspi->master);
+33 -1
drivers/spi/spi-bcm-qspi.h
··· 48 48 (INTR_MSPI_DONE_MASK | \ 49 49 INTR_MSPI_HALTED_MASK) 50 50 51 + #define QSPI_INTERRUPTS_ALL \ 52 + (MSPI_INTERRUPTS_ALL | \ 53 + BSPI_LR_INTERRUPTS_ALL) 54 + 51 55 struct platform_device; 52 56 struct dev_pm_ops; 53 57 54 - struct bcm_qspi_soc_intc; 58 + enum { 59 + MSPI_DONE = 0x1, 60 + BSPI_DONE = 0x2, 61 + BSPI_ERR = 0x4, 62 + MSPI_BSPI_DONE = 0x7 63 + }; 64 + 65 + struct bcm_qspi_soc_intc { 66 + void (*bcm_qspi_int_ack)(struct bcm_qspi_soc_intc *soc_intc, int type); 67 + void (*bcm_qspi_int_set)(struct bcm_qspi_soc_intc *soc_intc, int type, 68 + bool en); 69 + u32 (*bcm_qspi_get_int_status)(struct bcm_qspi_soc_intc *soc_intc); 70 + }; 55 71 56 72 /* Read controller register*/ 57 73 static inline u32 bcm_qspi_readl(bool be, void __iomem *addr) ··· 86 70 iowrite32be(data, addr); 87 71 else 88 72 writel_relaxed(data, addr); 73 + } 74 + 75 + static inline u32 get_qspi_mask(int type) 76 + { 77 + switch (type) { 78 + case MSPI_DONE: 79 + return INTR_MSPI_DONE_MASK; 80 + case BSPI_DONE: 81 + return BSPI_LR_INTERRUPTS_ALL; 82 + case MSPI_BSPI_DONE: 83 + return QSPI_INTERRUPTS_ALL; 84 + case BSPI_ERR: 85 + return BSPI_LR_INTERRUPTS_ERROR; 86 + } 87 + 88 + return 0; 89 89 } 90 90 91 91 /* The common driver functions to be called by the SoC platform driver */
+163
drivers/spi/spi-iproc-qspi.c
··· 1 + /* 2 + * Copyright 2016 Broadcom Limited 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <linux/device.h> 15 + #include <linux/io.h> 16 + #include <linux/ioport.h> 17 + #include <linux/module.h> 18 + #include <linux/of.h> 19 + #include <linux/of_address.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/slab.h> 22 + 23 + #include "spi-bcm-qspi.h" 24 + 25 + #define INTR_BASE_BIT_SHIFT 0x02 26 + #define INTR_COUNT 0x07 27 + 28 + struct bcm_iproc_intc { 29 + struct bcm_qspi_soc_intc soc_intc; 30 + struct platform_device *pdev; 31 + void __iomem *int_reg; 32 + void __iomem *int_status_reg; 33 + spinlock_t soclock; 34 + bool big_endian; 35 + }; 36 + 37 + static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc) 38 + { 39 + struct bcm_iproc_intc *priv = 40 + container_of(soc_intc, struct bcm_iproc_intc, soc_intc); 41 + void __iomem *mmio = priv->int_status_reg; 42 + int i; 43 + u32 val = 0, sts = 0; 44 + 45 + for (i = 0; i < INTR_COUNT; i++) { 46 + if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4))) 47 + val |= 1UL << i; 48 + } 49 + 50 + if (val & INTR_MSPI_DONE_MASK) 51 + sts |= MSPI_DONE; 52 + 53 + if (val & BSPI_LR_INTERRUPTS_ALL) 54 + sts |= BSPI_DONE; 55 + 56 + if (val & BSPI_LR_INTERRUPTS_ERROR) 57 + sts |= BSPI_ERR; 58 + 59 + return sts; 60 + } 61 + 62 + static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type) 63 + { 64 + struct bcm_iproc_intc *priv = 65 + container_of(soc_intc, struct bcm_iproc_intc, soc_intc); 66 + void __iomem *mmio = priv->int_status_reg; 67 + u32 mask = get_qspi_mask(type); 68 + int i; 69 + 70 + for (i = 0; i < INTR_COUNT; i++) { 71 + if (mask & (1UL << i)) 72 + bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4)); 73 + } 74 + } 75 + 76 + static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type, 77 + bool en) 78 + { 79 + struct bcm_iproc_intc *priv = 80 + container_of(soc_intc, struct bcm_iproc_intc, soc_intc); 81 + void __iomem *mmio = priv->int_reg; 82 + u32 mask = get_qspi_mask(type); 83 + u32 val; 84 + unsigned long flags; 85 + 86 + spin_lock_irqsave(&priv->soclock, flags); 87 + 88 + val = bcm_qspi_readl(priv->big_endian, mmio); 89 + 90 + if (en) 91 + val = val | (mask << INTR_BASE_BIT_SHIFT); 92 + else 93 + val = val & ~(mask << INTR_BASE_BIT_SHIFT); 94 + 95 + bcm_qspi_writel(priv->big_endian, val, mmio); 96 + 97 + spin_unlock_irqrestore(&priv->soclock, flags); 98 + } 99 + 100 + static int bcm_iproc_probe(struct platform_device *pdev) 101 + { 102 + struct device *dev = &pdev->dev; 103 + struct bcm_iproc_intc *priv; 104 + struct bcm_qspi_soc_intc *soc_intc; 105 + struct resource *res; 106 + 107 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 108 + if (!priv) 109 + return -ENOMEM; 110 + soc_intc = &priv->soc_intc; 111 + priv->pdev = pdev; 112 + 113 + spin_lock_init(&priv->soclock); 114 + 115 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs"); 116 + priv->int_reg = devm_ioremap_resource(dev, res); 117 + if (IS_ERR(priv->int_reg)) 118 + return PTR_ERR(priv->int_reg); 119 + 120 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 121 + "intr_status_reg"); 122 + priv->int_status_reg = devm_ioremap_resource(dev, res); 123 + if (IS_ERR(priv->int_status_reg)) 124 + return PTR_ERR(priv->int_status_reg); 125 + 126 + priv->big_endian = of_device_is_big_endian(dev->of_node); 127 + 128 + bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); 129 + bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false); 130 + 131 + soc_intc->bcm_qspi_int_ack = bcm_iproc_qspi_int_ack; 132 + soc_intc->bcm_qspi_int_set = bcm_iproc_qspi_int_set; 133 + soc_intc->bcm_qspi_get_int_status = bcm_iproc_qspi_get_l2_int_status; 134 + 135 + return bcm_qspi_probe(pdev, soc_intc); 136 + } 137 + 138 + static int bcm_iproc_remove(struct platform_device *pdev) 139 + { 140 + return bcm_qspi_remove(pdev); 141 + } 142 + 143 + static const struct of_device_id bcm_iproc_of_match[] = { 144 + { .compatible = "brcm,spi-nsp-qspi" }, 145 + { .compatible = "brcm,spi-ns2-qspi" }, 146 + {}, 147 + }; 148 + MODULE_DEVICE_TABLE(of, bcm_iproc_of_match); 149 + 150 + static struct platform_driver bcm_iproc_driver = { 151 + .probe = bcm_iproc_probe, 152 + .remove = bcm_iproc_remove, 153 + .driver = { 154 + .name = "bcm_iproc", 155 + .pm = &bcm_qspi_pm_ops, 156 + .of_match_table = bcm_iproc_of_match, 157 + } 158 + }; 159 + module_platform_driver(bcm_iproc_driver); 160 + 161 + MODULE_LICENSE("GPL v2"); 162 + MODULE_AUTHOR("Kamal Dasu"); 163 + MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");