aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLudovic Barre <ludovic.barre@st.com>2018-04-26 12:18:30 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2018-05-24 07:38:22 -0400
commit927abfc4461e7fd76d5bba593dabdec381571021 (patch)
tree315a582263eb9c674023f868dce8d4b285d02bcf
parent5a2490e029c29065c6bc2f63c10a985f85522998 (diff)
irqchip/stm32: Add stm32mp1 support with hierarchy domain
Exti controller has been differently integrated on stm32mp1 SoC. A parent irq has only one external interrupt. A hierachy domain could be used. Handlers are call by parent, each parent interrupt could be masked and unmasked according to the needs. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt3
-rw-r--r--drivers/irqchip/irq-stm32-exti.c322
2 files changed, 325 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
index edf03f09244b..136bd612bd83 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt
@@ -5,11 +5,14 @@ Required properties:
5- compatible: Should be: 5- compatible: Should be:
6 "st,stm32-exti" 6 "st,stm32-exti"
7 "st,stm32h7-exti" 7 "st,stm32h7-exti"
8 "st,stm32mp1-exti"
8- reg: Specifies base physical address and size of the registers 9- reg: Specifies base physical address and size of the registers
9- interrupt-controller: Indentifies the node as an interrupt controller 10- interrupt-controller: Indentifies the node as an interrupt controller
10- #interrupt-cells: Specifies the number of cells to encode an interrupt 11- #interrupt-cells: Specifies the number of cells to encode an interrupt
11 specifier, shall be 2 12 specifier, shall be 2
12- interrupts: interrupts references to primary interrupt controller 13- interrupts: interrupts references to primary interrupt controller
14 (only needed for exti controller with multiple exti under
15 same parent interrupt: st,stm32-exti and st,stm32h7-exti")
13 16
14Example: 17Example:
15 18
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index b38c6555d66f..ebf71460c668 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -15,6 +15,8 @@
15#include <linux/of_address.h> 15#include <linux/of_address.h>
16#include <linux/of_irq.h> 16#include <linux/of_irq.h>
17 17
18#include <dt-bindings/interrupt-controller/arm-gic.h>
19
18#define IRQS_PER_BANK 32 20#define IRQS_PER_BANK 32
19 21
20struct stm32_exti_bank { 22struct stm32_exti_bank {
@@ -29,14 +31,24 @@ struct stm32_exti_bank {
29 31
30#define UNDEF_REG ~0 32#define UNDEF_REG ~0
31 33
34struct stm32_desc_irq {
35 u32 exti;
36 u32 irq_parent;
37};
38
32struct stm32_exti_drv_data { 39struct stm32_exti_drv_data {
33 const struct stm32_exti_bank **exti_banks; 40 const struct stm32_exti_bank **exti_banks;
41 const struct stm32_desc_irq *desc_irqs;
34 u32 bank_nr; 42 u32 bank_nr;
43 u32 irq_nr;
35}; 44};
36 45
37struct stm32_exti_chip_data { 46struct stm32_exti_chip_data {
38 struct stm32_exti_host_data *host_data; 47 struct stm32_exti_host_data *host_data;
39 const struct stm32_exti_bank *reg_bank; 48 const struct stm32_exti_bank *reg_bank;
49 struct raw_spinlock rlock;
50 u32 wake_active;
51 u32 mask_cache;
40 u32 rtsr_cache; 52 u32 rtsr_cache;
41 u32 ftsr_cache; 53 u32 ftsr_cache;
42}; 54};
@@ -107,6 +119,89 @@ static const struct stm32_exti_drv_data stm32h7xx_drv_data = {
107 .bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks), 119 .bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks),
108}; 120};
109 121
122static const struct stm32_exti_bank stm32mp1_exti_b1 = {
123 .imr_ofst = 0x80,
124 .emr_ofst = 0x84,
125 .rtsr_ofst = 0x00,
126 .ftsr_ofst = 0x04,
127 .swier_ofst = 0x08,
128 .rpr_ofst = 0x0C,
129 .fpr_ofst = 0x10,
130};
131
132static const struct stm32_exti_bank stm32mp1_exti_b2 = {
133 .imr_ofst = 0x90,
134 .emr_ofst = 0x94,
135 .rtsr_ofst = 0x20,
136 .ftsr_ofst = 0x24,
137 .swier_ofst = 0x28,
138 .rpr_ofst = 0x2C,
139 .fpr_ofst = 0x30,
140};
141
142static const struct stm32_exti_bank stm32mp1_exti_b3 = {
143 .imr_ofst = 0xA0,
144 .emr_ofst = 0xA4,
145 .rtsr_ofst = 0x40,
146 .ftsr_ofst = 0x44,
147 .swier_ofst = 0x48,
148 .rpr_ofst = 0x4C,
149 .fpr_ofst = 0x50,
150};
151
152static const struct stm32_exti_bank *stm32mp1_exti_banks[] = {
153 &stm32mp1_exti_b1,
154 &stm32mp1_exti_b2,
155 &stm32mp1_exti_b3,
156};
157
158static const struct stm32_desc_irq stm32mp1_desc_irq[] = {
159 { .exti = 1, .irq_parent = 7 },
160 { .exti = 2, .irq_parent = 8 },
161 { .exti = 3, .irq_parent = 9 },
162 { .exti = 4, .irq_parent = 10 },
163 { .exti = 5, .irq_parent = 23 },
164 { .exti = 6, .irq_parent = 64 },
165 { .exti = 7, .irq_parent = 65 },
166 { .exti = 8, .irq_parent = 66 },
167 { .exti = 9, .irq_parent = 67 },
168 { .exti = 10, .irq_parent = 40 },
169 { .exti = 11, .irq_parent = 42 },
170 { .exti = 12, .irq_parent = 76 },
171 { .exti = 13, .irq_parent = 77 },
172 { .exti = 14, .irq_parent = 121 },
173 { .exti = 15, .irq_parent = 127 },
174 { .exti = 16, .irq_parent = 1 },
175 { .exti = 65, .irq_parent = 144 },
176 { .exti = 68, .irq_parent = 143 },
177 { .exti = 73, .irq_parent = 129 },
178};
179
180static const struct stm32_exti_drv_data stm32mp1_drv_data = {
181 .exti_banks = stm32mp1_exti_banks,
182 .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks),
183 .desc_irqs = stm32mp1_desc_irq,
184 .irq_nr = ARRAY_SIZE(stm32mp1_desc_irq),
185};
186
187static int stm32_exti_to_irq(const struct stm32_exti_drv_data *drv_data,
188 irq_hw_number_t hwirq)
189{
190 const struct stm32_desc_irq *desc_irq;
191 int i;
192
193 if (!drv_data->desc_irqs)
194 return -EINVAL;
195
196 for (i = 0; i < drv_data->irq_nr; i++) {
197 desc_irq = &drv_data->desc_irqs[i];
198 if (desc_irq->exti == hwirq)
199 return desc_irq->irq_parent;
200 }
201
202 return -EINVAL;
203}
204
110static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) 205static unsigned long stm32_exti_pending(struct irq_chip_generic *gc)
111{ 206{
112 struct stm32_exti_chip_data *chip_data = gc->private; 207 struct stm32_exti_chip_data *chip_data = gc->private;
@@ -282,6 +377,173 @@ static void stm32_irq_ack(struct irq_data *d)
282 377
283 irq_gc_unlock(gc); 378 irq_gc_unlock(gc);
284} 379}
380
381static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg)
382{
383 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
384 void __iomem *base = chip_data->host_data->base;
385 u32 val;
386
387 val = readl_relaxed(base + reg);
388 val |= BIT(d->hwirq % IRQS_PER_BANK);
389 writel_relaxed(val, base + reg);
390
391 return val;
392}
393
394static inline u32 stm32_exti_clr_bit(struct irq_data *d, u32 reg)
395{
396 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
397 void __iomem *base = chip_data->host_data->base;
398 u32 val;
399
400 val = readl_relaxed(base + reg);
401 val &= ~BIT(d->hwirq % IRQS_PER_BANK);
402 writel_relaxed(val, base + reg);
403
404 return val;
405}
406
407static void stm32_exti_h_eoi(struct irq_data *d)
408{
409 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
410 const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
411
412 raw_spin_lock(&chip_data->rlock);
413
414 stm32_exti_set_bit(d, stm32_bank->rpr_ofst);
415 if (stm32_bank->fpr_ofst != UNDEF_REG)
416 stm32_exti_set_bit(d, stm32_bank->fpr_ofst);
417
418 raw_spin_unlock(&chip_data->rlock);
419
420 if (d->parent_data->chip)
421 irq_chip_eoi_parent(d);
422}
423
424static void stm32_exti_h_mask(struct irq_data *d)
425{
426 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
427 const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
428
429 raw_spin_lock(&chip_data->rlock);
430 chip_data->mask_cache = stm32_exti_clr_bit(d, stm32_bank->imr_ofst);
431 raw_spin_unlock(&chip_data->rlock);
432
433 if (d->parent_data->chip)
434 irq_chip_mask_parent(d);
435}
436
437static void stm32_exti_h_unmask(struct irq_data *d)
438{
439 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
440 const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
441
442 raw_spin_lock(&chip_data->rlock);
443 chip_data->mask_cache = stm32_exti_set_bit(d, stm32_bank->imr_ofst);
444 raw_spin_unlock(&chip_data->rlock);
445
446 if (d->parent_data->chip)
447 irq_chip_unmask_parent(d);
448}
449
450static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
451{
452 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
453 const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
454 void __iomem *base = chip_data->host_data->base;
455 u32 rtsr, ftsr;
456 int err;
457
458 raw_spin_lock(&chip_data->rlock);
459 rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst);
460 ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst);
461
462 err = stm32_exti_set_type(d, type, &rtsr, &ftsr);
463 if (err) {
464 raw_spin_unlock(&chip_data->rlock);
465 return err;
466 }
467
468 writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst);
469 writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst);
470 raw_spin_unlock(&chip_data->rlock);
471
472 return 0;
473}
474
475static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on)
476{
477 struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
478 u32 mask = BIT(d->hwirq % IRQS_PER_BANK);
479
480 raw_spin_lock(&chip_data->rlock);
481
482 if (on)
483 chip_data->wake_active |= mask;
484 else
485 chip_data->wake_active &= ~mask;
486
487 raw_spin_unlock(&chip_data->rlock);
488
489 return 0;
490}
491
492static int stm32_exti_h_set_affinity(struct irq_data *d,
493 const struct cpumask *dest, bool force)
494{
495 if (d->parent_data->chip)
496 return irq_chip_set_affinity_parent(d, dest, force);
497
498 return -EINVAL;
499}
500
501static struct irq_chip stm32_exti_h_chip = {
502 .name = "stm32-exti-h",
503 .irq_eoi = stm32_exti_h_eoi,
504 .irq_mask = stm32_exti_h_mask,
505 .irq_unmask = stm32_exti_h_unmask,
506 .irq_retrigger = irq_chip_retrigger_hierarchy,
507 .irq_set_type = stm32_exti_h_set_type,
508 .irq_set_wake = stm32_exti_h_set_wake,
509 .flags = IRQCHIP_MASK_ON_SUSPEND,
510#ifdef CONFIG_SMP
511 .irq_set_affinity = stm32_exti_h_set_affinity,
512#endif
513};
514
515static int stm32_exti_h_domain_alloc(struct irq_domain *dm,
516 unsigned int virq,
517 unsigned int nr_irqs, void *data)
518{
519 struct stm32_exti_host_data *host_data = dm->host_data;
520 struct stm32_exti_chip_data *chip_data;
521 struct irq_fwspec *fwspec = data;
522 struct irq_fwspec p_fwspec;
523 irq_hw_number_t hwirq;
524 int p_irq, bank;
525
526 hwirq = fwspec->param[0];
527 bank = hwirq / IRQS_PER_BANK;
528 chip_data = &host_data->chips_data[bank];
529
530 irq_domain_set_hwirq_and_chip(dm, virq, hwirq,
531 &stm32_exti_h_chip, chip_data);
532
533 p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq);
534 if (p_irq >= 0) {
535 p_fwspec.fwnode = dm->parent->fwnode;
536 p_fwspec.param_count = 3;
537 p_fwspec.param[0] = GIC_SPI;
538 p_fwspec.param[1] = p_irq;
539 p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
540
541 return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec);
542 }
543
544 return 0;
545}
546
285static struct 547static struct
286stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, 548stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
287 struct device_node *node) 549 struct device_node *node)
@@ -323,6 +585,8 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
323 chip_data->host_data = h_data; 585 chip_data->host_data = h_data;
324 chip_data->reg_bank = stm32_bank; 586 chip_data->reg_bank = stm32_bank;
325 587
588 raw_spin_lock_init(&chip_data->rlock);
589
326 /* Determine number of irqs supported */ 590 /* Determine number of irqs supported */
327 writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); 591 writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst);
328 irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); 592 irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst);
@@ -421,6 +685,56 @@ out_free_mem:
421 return ret; 685 return ret;
422} 686}
423 687
688static const struct irq_domain_ops stm32_exti_h_domain_ops = {
689 .alloc = stm32_exti_h_domain_alloc,
690 .free = irq_domain_free_irqs_common,
691};
692
693static int
694__init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
695 struct device_node *node,
696 struct device_node *parent)
697{
698 struct irq_domain *parent_domain, *domain;
699 struct stm32_exti_host_data *host_data;
700 int ret, i;
701
702 parent_domain = irq_find_host(parent);
703 if (!parent_domain) {
704 pr_err("interrupt-parent not found\n");
705 return -EINVAL;
706 }
707
708 host_data = stm32_exti_host_init(drv_data, node);
709 if (!host_data) {
710 ret = -ENOMEM;
711 goto out_free_mem;
712 }
713
714 for (i = 0; i < drv_data->bank_nr; i++)
715 stm32_exti_chip_init(host_data, i, node);
716
717 domain = irq_domain_add_hierarchy(parent_domain, 0,
718 drv_data->bank_nr * IRQS_PER_BANK,
719 node, &stm32_exti_h_domain_ops,
720 host_data);
721
722 if (!domain) {
723 pr_err("%s: Could not register exti domain.\n", node->name);
724 ret = -ENOMEM;
725 goto out_unmap;
726 }
727
728 return 0;
729
730out_unmap:
731 iounmap(host_data->base);
732out_free_mem:
733 kfree(host_data->chips_data);
734 kfree(host_data);
735 return ret;
736}
737
424static int __init stm32f4_exti_of_init(struct device_node *np, 738static int __init stm32f4_exti_of_init(struct device_node *np,
425 struct device_node *parent) 739 struct device_node *parent)
426{ 740{
@@ -436,3 +750,11 @@ static int __init stm32h7_exti_of_init(struct device_node *np,
436} 750}
437 751
438IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); 752IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);
753
754static int __init stm32mp1_exti_of_init(struct device_node *np,
755 struct device_node *parent)
756{
757 return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent);
758}
759
760IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init);