aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinghuan Lian <Minghuan.Lian@nxp.com>2017-07-05 02:59:02 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2017-08-31 11:19:39 -0400
commitfd100dab63ef634e1e0e8b5d9d6d4ba7df9be93f (patch)
treef928d82b8007a5403c9a7ccbff2fcba7ebd4c288
parent4dd5da65a39d9a0405304fdef0804afffece044b (diff)
irqchip/ls-scfg-msi: Add LS1043a v1.1 MSI support
A MSI controller of LS1043a v1.0 only includes one MSIR and is assigned one GIC interrupt. In order to support affinity, LS1043a v1.1 MSI is assigned 4 MSIRs and 4 GIC interrupts. But the MSIR has the different offset and only supports 8 MSIs. The bits between variable bit_start and bit_end in structure ls_scfg_msir are used to show 8 MSI interrupts. msir_irqs and msir_base are added to describe the difference of MSI between LS1043a v1.1 and other SoCs. Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com> Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt1
-rw-r--r--drivers/irqchip/irq-ls-scfg-msi.c45
2 files changed, 40 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
index dde455289c16..49ccabbfa6f3 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt
@@ -7,6 +7,7 @@ Required properties:
7 "fsl,ls1021a-msi" 7 "fsl,ls1021a-msi"
8 "fsl,ls1043a-msi" 8 "fsl,ls1043a-msi"
9 "fsl,ls1046a-msi" 9 "fsl,ls1046a-msi"
10 "fsl,ls1043a-v1.1-msi"
10- msi-controller: indicates that this is a PCIe MSI controller node 11- msi-controller: indicates that this is a PCIe MSI controller node
11- reg: physical base address of the controller and length of memory mapped. 12- reg: physical base address of the controller and length of memory mapped.
12- interrupts: an interrupt to the parent interrupt controller. 13- interrupts: an interrupt to the parent interrupt controller.
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 0b1f34ddab00..8d57a599c0fb 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -25,14 +25,21 @@
25#define MSI_IRQS_PER_MSIR 32 25#define MSI_IRQS_PER_MSIR 32
26#define MSI_MSIR_OFFSET 4 26#define MSI_MSIR_OFFSET 4
27 27
28#define MSI_LS1043V1_1_IRQS_PER_MSIR 8
29#define MSI_LS1043V1_1_MSIR_OFFSET 0x10
30
28struct ls_scfg_msi_cfg { 31struct ls_scfg_msi_cfg {
29 u32 ibs_shift; /* Shift of interrupt bit select */ 32 u32 ibs_shift; /* Shift of interrupt bit select */
33 u32 msir_irqs; /* The irq number per MSIR */
34 u32 msir_base; /* The base address of MSIR */
30}; 35};
31 36
32struct ls_scfg_msir { 37struct ls_scfg_msir {
33 struct ls_scfg_msi *msi_data; 38 struct ls_scfg_msi *msi_data;
34 unsigned int index; 39 unsigned int index;
35 unsigned int gic_irq; 40 unsigned int gic_irq;
41 unsigned int bit_start;
42 unsigned int bit_end;
36 void __iomem *reg; 43 void __iomem *reg;
37}; 44};
38 45
@@ -140,13 +147,18 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
140 struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc); 147 struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
141 struct ls_scfg_msi *msi_data = msir->msi_data; 148 struct ls_scfg_msi *msi_data = msir->msi_data;
142 unsigned long val; 149 unsigned long val;
143 int pos, virq, hwirq; 150 int pos, size, virq, hwirq;
144 151
145 chained_irq_enter(irq_desc_get_chip(desc), desc); 152 chained_irq_enter(irq_desc_get_chip(desc), desc);
146 153
147 val = ioread32be(msir->reg); 154 val = ioread32be(msir->reg);
148 for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) { 155
149 hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index; 156 pos = msir->bit_start;
157 size = msir->bit_end + 1;
158
159 for_each_set_bit_from(pos, &val, size) {
160 hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
161 msir->index;
150 virq = irq_find_mapping(msi_data->parent, hwirq); 162 virq = irq_find_mapping(msi_data->parent, hwirq);
151 if (virq) 163 if (virq)
152 generic_handle_irq(virq); 164 generic_handle_irq(virq);
@@ -193,14 +205,24 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
193 msir->index = index; 205 msir->index = index;
194 msir->msi_data = msi_data; 206 msir->msi_data = msi_data;
195 msir->gic_irq = virq; 207 msir->gic_irq = virq;
196 msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index; 208 msir->reg = msi_data->regs + msi_data->cfg->msir_base + 4 * index;
209
210 if (msi_data->cfg->msir_irqs == MSI_LS1043V1_1_IRQS_PER_MSIR) {
211 msir->bit_start = 32 - ((msir->index + 1) *
212 MSI_LS1043V1_1_IRQS_PER_MSIR);
213 msir->bit_end = msir->bit_start +
214 MSI_LS1043V1_1_IRQS_PER_MSIR - 1;
215 } else {
216 msir->bit_start = 0;
217 msir->bit_end = msi_data->cfg->msir_irqs - 1;
218 }
197 219
198 irq_set_chained_handler_and_data(msir->gic_irq, 220 irq_set_chained_handler_and_data(msir->gic_irq,
199 ls_scfg_msi_irq_handler, 221 ls_scfg_msi_irq_handler,
200 msir); 222 msir);
201 223
202 /* Release the hwirqs corresponding to this MSIR */ 224 /* Release the hwirqs corresponding to this MSIR */
203 for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { 225 for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
204 hwirq = i << msi_data->cfg->ibs_shift | msir->index; 226 hwirq = i << msi_data->cfg->ibs_shift | msir->index;
205 bitmap_clear(msi_data->used, hwirq, 1); 227 bitmap_clear(msi_data->used, hwirq, 1);
206 } 228 }
@@ -216,7 +238,7 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
216 if (msir->gic_irq > 0) 238 if (msir->gic_irq > 0)
217 irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL); 239 irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL);
218 240
219 for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { 241 for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
220 hwirq = i << msi_data->cfg->ibs_shift | msir->index; 242 hwirq = i << msi_data->cfg->ibs_shift | msir->index;
221 bitmap_set(msi_data->used, hwirq, 1); 243 bitmap_set(msi_data->used, hwirq, 1);
222 } 244 }
@@ -226,10 +248,20 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
226 248
227static struct ls_scfg_msi_cfg ls1021_msi_cfg = { 249static struct ls_scfg_msi_cfg ls1021_msi_cfg = {
228 .ibs_shift = 3, 250 .ibs_shift = 3,
251 .msir_irqs = MSI_IRQS_PER_MSIR,
252 .msir_base = MSI_MSIR_OFFSET,
229}; 253};
230 254
231static struct ls_scfg_msi_cfg ls1046_msi_cfg = { 255static struct ls_scfg_msi_cfg ls1046_msi_cfg = {
232 .ibs_shift = 2, 256 .ibs_shift = 2,
257 .msir_irqs = MSI_IRQS_PER_MSIR,
258 .msir_base = MSI_MSIR_OFFSET,
259};
260
261static struct ls_scfg_msi_cfg ls1043_v1_1_msi_cfg = {
262 .ibs_shift = 2,
263 .msir_irqs = MSI_LS1043V1_1_IRQS_PER_MSIR,
264 .msir_base = MSI_LS1043V1_1_MSIR_OFFSET,
233}; 265};
234 266
235static const struct of_device_id ls_scfg_msi_id[] = { 267static const struct of_device_id ls_scfg_msi_id[] = {
@@ -239,6 +271,7 @@ static const struct of_device_id ls_scfg_msi_id[] = {
239 271
240 { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg }, 272 { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
241 { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg }, 273 { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
274 { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg },
242 { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg }, 275 { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg },
243 {}, 276 {},
244}; 277};