diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt | 14 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt | 33 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt | 4 | ||||
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 1 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-armada-370-xp.c | 89 | ||||
-rw-r--r-- | drivers/irqchip/irq-digicolor.c | 4 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic.c | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 21 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-irqc.c | 54 | ||||
-rw-r--r-- | drivers/irqchip/irq-vf610-mscm-ir.c | 212 | ||||
-rw-r--r-- | include/linux/irqchip/mips-gic.h | 2 |
12 files changed, 396 insertions, 41 deletions
diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt new file mode 100644 index 000000000000..44aa3c451ccf --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt | |||
@@ -0,0 +1,14 @@ | |||
1 | Freescale Vybrid Miscellaneous System Control - CPU Configuration | ||
2 | |||
3 | The MSCM IP contains multiple sub modules, this binding describes the first | ||
4 | block of registers which contains CPU configuration information. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: "fsl,vf610-mscm-cpucfg", "syscon" | ||
8 | - reg: the register range of the MSCM CPU configuration registers | ||
9 | |||
10 | Example: | ||
11 | mscm_cpucfg: cpucfg@40001000 { | ||
12 | compatible = "fsl,vf610-mscm-cpucfg", "syscon"; | ||
13 | reg = <0x40001000 0x800>; | ||
14 | } | ||
diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt new file mode 100644 index 000000000000..669808b2af49 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-ir.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | Freescale Vybrid Miscellaneous System Control - Interrupt Router | ||
2 | |||
3 | The MSCM IP contains multiple sub modules, this binding describes the second | ||
4 | block of registers which control the interrupt router. The interrupt router | ||
5 | allows to configure the recipient of each peripheral interrupt. Furthermore | ||
6 | it controls the directed processor interrupts. The module is available in all | ||
7 | Vybrid SoC's but is only really useful in dual core configurations (VF6xx | ||
8 | which comes with a Cortex-A5/Cortex-M4 combination). | ||
9 | |||
10 | Required properties: | ||
11 | - compatible: "fsl,vf610-mscm-ir" | ||
12 | - reg: the register range of the MSCM Interrupt Router | ||
13 | - fsl,cpucfg: The handle to the MSCM CPU configuration node, required | ||
14 | to get the current CPU ID | ||
15 | - interrupt-controller: Identifies the node as an interrupt controller | ||
16 | - #interrupt-cells: Two cells, interrupt number and cells. | ||
17 | The hardware interrupt number according to interrupt | ||
18 | assignment of the interrupt router is required. | ||
19 | Flags get passed only when using GIC as parent. Flags | ||
20 | encoding as documented by the GIC bindings. | ||
21 | - interrupt-parent: Should be the phandle for the interrupt controller of | ||
22 | the CPU the device tree is intended to be used on. This | ||
23 | is either the node of the GIC or NVIC controller. | ||
24 | |||
25 | Example: | ||
26 | mscm_ir: interrupt-controller@40001800 { | ||
27 | compatible = "fsl,vf610-mscm-ir"; | ||
28 | reg = <0x40001800 0x400>; | ||
29 | fsl,cpucfg = <&mscm_cpucfg>; | ||
30 | interrupt-controller; | ||
31 | #interrupt-cells = <2>; | ||
32 | interrupt-parent = <&intc>; | ||
33 | } | ||
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt index 1a88e62228e5..63633bdea7e4 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt | |||
@@ -4,7 +4,7 @@ Required properties: | |||
4 | 4 | ||
5 | - compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback. | 5 | - compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback. |
6 | Examples with soctypes are: | 6 | Examples with soctypes are: |
7 | - "renesas,irqc-r8a73a4" (R-Mobile AP6) | 7 | - "renesas,irqc-r8a73a4" (R-Mobile APE6) |
8 | - "renesas,irqc-r8a7790" (R-Car H2) | 8 | - "renesas,irqc-r8a7790" (R-Car H2) |
9 | - "renesas,irqc-r8a7791" (R-Car M2-W) | 9 | - "renesas,irqc-r8a7791" (R-Car M2-W) |
10 | - "renesas,irqc-r8a7792" (R-Car V2H) | 10 | - "renesas,irqc-r8a7792" (R-Car V2H) |
@@ -12,6 +12,7 @@ Required properties: | |||
12 | - "renesas,irqc-r8a7794" (R-Car E2) | 12 | - "renesas,irqc-r8a7794" (R-Car E2) |
13 | - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in | 13 | - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in |
14 | interrupts.txt in this directory | 14 | interrupts.txt in this directory |
15 | - clocks: Must contain a reference to the functional clock. | ||
15 | 16 | ||
16 | Optional properties: | 17 | Optional properties: |
17 | 18 | ||
@@ -29,4 +30,5 @@ Example: | |||
29 | <0 1 IRQ_TYPE_LEVEL_HIGH>, | 30 | <0 1 IRQ_TYPE_LEVEL_HIGH>, |
30 | <0 2 IRQ_TYPE_LEVEL_HIGH>, | 31 | <0 2 IRQ_TYPE_LEVEL_HIGH>, |
31 | <0 3 IRQ_TYPE_LEVEL_HIGH>; | 32 | <0 3 IRQ_TYPE_LEVEL_HIGH>; |
33 | clocks = <&mstp4_clks R8A7790_CLK_IRQC>; | ||
32 | }; | 34 | }; |
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index e8627e04e1e6..c8dffcee9736 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig | |||
@@ -631,6 +631,7 @@ config SOC_IMX6SX | |||
631 | 631 | ||
632 | config SOC_VF610 | 632 | config SOC_VF610 |
633 | bool "Vybrid Family VF610 support" | 633 | bool "Vybrid Family VF610 support" |
634 | select IRQ_DOMAIN_HIERARCHY | ||
634 | select ARM_GIC | 635 | select ARM_GIC |
635 | select PINCTRL_VF610 | 636 | select PINCTRL_VF610 |
636 | select PL310_ERRATA_769419 if CACHE_L2X0 | 637 | select PL310_ERRATA_769419 if CACHE_L2X0 |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 9bb4fd191e94..f117092ae014 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -38,6 +38,7 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o | |||
38 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o | 38 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o |
39 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o | 39 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o |
40 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o | 40 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o |
41 | obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o | ||
41 | obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o | 42 | obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o |
42 | obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o | 43 | obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o |
43 | obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o | 44 | obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o |
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 4387dae14e45..daccc8bdbb42 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c | |||
@@ -38,6 +38,8 @@ | |||
38 | /* Interrupt Controller Registers Map */ | 38 | /* Interrupt Controller Registers Map */ |
39 | #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) | 39 | #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) |
40 | #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) | 40 | #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) |
41 | #define ARMADA_370_XP_INT_FABRIC_MASK_OFFS (0x54) | ||
42 | #define ARMADA_370_XP_INT_CAUSE_PERF(cpu) (1 << cpu) | ||
41 | 43 | ||
42 | #define ARMADA_370_XP_INT_CONTROL (0x00) | 44 | #define ARMADA_370_XP_INT_CONTROL (0x00) |
43 | #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) | 45 | #define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) |
@@ -56,6 +58,7 @@ | |||
56 | #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) | 58 | #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) |
57 | 59 | ||
58 | #define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5) | 60 | #define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5) |
61 | #define ARMADA_370_XP_FABRIC_IRQ (3) | ||
59 | 62 | ||
60 | #define IPI_DOORBELL_START (0) | 63 | #define IPI_DOORBELL_START (0) |
61 | #define IPI_DOORBELL_END (8) | 64 | #define IPI_DOORBELL_END (8) |
@@ -77,6 +80,17 @@ static DEFINE_MUTEX(msi_used_lock); | |||
77 | static phys_addr_t msi_doorbell_addr; | 80 | static phys_addr_t msi_doorbell_addr; |
78 | #endif | 81 | #endif |
79 | 82 | ||
83 | static inline bool is_percpu_irq(irq_hw_number_t irq) | ||
84 | { | ||
85 | switch (irq) { | ||
86 | case ARMADA_370_XP_TIMER0_PER_CPU_IRQ: | ||
87 | case ARMADA_370_XP_FABRIC_IRQ: | ||
88 | return true; | ||
89 | default: | ||
90 | return false; | ||
91 | } | ||
92 | } | ||
93 | |||
80 | /* | 94 | /* |
81 | * In SMP mode: | 95 | * In SMP mode: |
82 | * For shared global interrupts, mask/unmask global enable bit | 96 | * For shared global interrupts, mask/unmask global enable bit |
@@ -86,7 +100,7 @@ static void armada_370_xp_irq_mask(struct irq_data *d) | |||
86 | { | 100 | { |
87 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | 101 | irq_hw_number_t hwirq = irqd_to_hwirq(d); |
88 | 102 | ||
89 | if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) | 103 | if (!is_percpu_irq(hwirq)) |
90 | writel(hwirq, main_int_base + | 104 | writel(hwirq, main_int_base + |
91 | ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); | 105 | ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); |
92 | else | 106 | else |
@@ -98,7 +112,7 @@ static void armada_370_xp_irq_unmask(struct irq_data *d) | |||
98 | { | 112 | { |
99 | irq_hw_number_t hwirq = irqd_to_hwirq(d); | 113 | irq_hw_number_t hwirq = irqd_to_hwirq(d); |
100 | 114 | ||
101 | if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) | 115 | if (!is_percpu_irq(hwirq)) |
102 | writel(hwirq, main_int_base + | 116 | writel(hwirq, main_int_base + |
103 | ARMADA_370_XP_INT_SET_ENABLE_OFFS); | 117 | ARMADA_370_XP_INT_SET_ENABLE_OFFS); |
104 | else | 118 | else |
@@ -281,20 +295,21 @@ static struct irq_chip armada_370_xp_irq_chip = { | |||
281 | #ifdef CONFIG_SMP | 295 | #ifdef CONFIG_SMP |
282 | .irq_set_affinity = armada_xp_set_affinity, | 296 | .irq_set_affinity = armada_xp_set_affinity, |
283 | #endif | 297 | #endif |
298 | .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, | ||
284 | }; | 299 | }; |
285 | 300 | ||
286 | static int armada_370_xp_mpic_irq_map(struct irq_domain *h, | 301 | static int armada_370_xp_mpic_irq_map(struct irq_domain *h, |
287 | unsigned int virq, irq_hw_number_t hw) | 302 | unsigned int virq, irq_hw_number_t hw) |
288 | { | 303 | { |
289 | armada_370_xp_irq_mask(irq_get_irq_data(virq)); | 304 | armada_370_xp_irq_mask(irq_get_irq_data(virq)); |
290 | if (hw != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) | 305 | if (!is_percpu_irq(hw)) |
291 | writel(hw, per_cpu_int_base + | 306 | writel(hw, per_cpu_int_base + |
292 | ARMADA_370_XP_INT_CLEAR_MASK_OFFS); | 307 | ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
293 | else | 308 | else |
294 | writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); | 309 | writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); |
295 | irq_set_status_flags(virq, IRQ_LEVEL); | 310 | irq_set_status_flags(virq, IRQ_LEVEL); |
296 | 311 | ||
297 | if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) { | 312 | if (is_percpu_irq(hw)) { |
298 | irq_set_percpu_devid(virq); | 313 | irq_set_percpu_devid(virq); |
299 | irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, | 314 | irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, |
300 | handle_percpu_devid_irq); | 315 | handle_percpu_devid_irq); |
@@ -308,28 +323,6 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, | |||
308 | return 0; | 323 | return 0; |
309 | } | 324 | } |
310 | 325 | ||
311 | #ifdef CONFIG_SMP | ||
312 | static void armada_mpic_send_doorbell(const struct cpumask *mask, | ||
313 | unsigned int irq) | ||
314 | { | ||
315 | int cpu; | ||
316 | unsigned long map = 0; | ||
317 | |||
318 | /* Convert our logical CPU mask into a physical one. */ | ||
319 | for_each_cpu(cpu, mask) | ||
320 | map |= 1 << cpu_logical_map(cpu); | ||
321 | |||
322 | /* | ||
323 | * Ensure that stores to Normal memory are visible to the | ||
324 | * other CPUs before issuing the IPI. | ||
325 | */ | ||
326 | dsb(); | ||
327 | |||
328 | /* submit softirq */ | ||
329 | writel((map << 8) | irq, main_int_base + | ||
330 | ARMADA_370_XP_SW_TRIG_INT_OFFS); | ||
331 | } | ||
332 | |||
333 | static void armada_xp_mpic_smp_cpu_init(void) | 326 | static void armada_xp_mpic_smp_cpu_init(void) |
334 | { | 327 | { |
335 | u32 control; | 328 | u32 control; |
@@ -352,11 +345,44 @@ static void armada_xp_mpic_smp_cpu_init(void) | |||
352 | writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); | 345 | writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
353 | } | 346 | } |
354 | 347 | ||
348 | static void armada_xp_mpic_perf_init(void) | ||
349 | { | ||
350 | unsigned long cpuid = cpu_logical_map(smp_processor_id()); | ||
351 | |||
352 | /* Enable Performance Counter Overflow interrupts */ | ||
353 | writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), | ||
354 | per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); | ||
355 | } | ||
356 | |||
357 | #ifdef CONFIG_SMP | ||
358 | static void armada_mpic_send_doorbell(const struct cpumask *mask, | ||
359 | unsigned int irq) | ||
360 | { | ||
361 | int cpu; | ||
362 | unsigned long map = 0; | ||
363 | |||
364 | /* Convert our logical CPU mask into a physical one. */ | ||
365 | for_each_cpu(cpu, mask) | ||
366 | map |= 1 << cpu_logical_map(cpu); | ||
367 | |||
368 | /* | ||
369 | * Ensure that stores to Normal memory are visible to the | ||
370 | * other CPUs before issuing the IPI. | ||
371 | */ | ||
372 | dsb(); | ||
373 | |||
374 | /* submit softirq */ | ||
375 | writel((map << 8) | irq, main_int_base + | ||
376 | ARMADA_370_XP_SW_TRIG_INT_OFFS); | ||
377 | } | ||
378 | |||
355 | static int armada_xp_mpic_secondary_init(struct notifier_block *nfb, | 379 | static int armada_xp_mpic_secondary_init(struct notifier_block *nfb, |
356 | unsigned long action, void *hcpu) | 380 | unsigned long action, void *hcpu) |
357 | { | 381 | { |
358 | if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) | 382 | if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) { |
383 | armada_xp_mpic_perf_init(); | ||
359 | armada_xp_mpic_smp_cpu_init(); | 384 | armada_xp_mpic_smp_cpu_init(); |
385 | } | ||
360 | 386 | ||
361 | return NOTIFY_OK; | 387 | return NOTIFY_OK; |
362 | } | 388 | } |
@@ -369,8 +395,10 @@ static struct notifier_block armada_370_xp_mpic_cpu_notifier = { | |||
369 | static int mpic_cascaded_secondary_init(struct notifier_block *nfb, | 395 | static int mpic_cascaded_secondary_init(struct notifier_block *nfb, |
370 | unsigned long action, void *hcpu) | 396 | unsigned long action, void *hcpu) |
371 | { | 397 | { |
372 | if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) | 398 | if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) { |
399 | armada_xp_mpic_perf_init(); | ||
373 | enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); | 400 | enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); |
401 | } | ||
374 | 402 | ||
375 | return NOTIFY_OK; | 403 | return NOTIFY_OK; |
376 | } | 404 | } |
@@ -379,7 +407,6 @@ static struct notifier_block mpic_cascaded_cpu_notifier = { | |||
379 | .notifier_call = mpic_cascaded_secondary_init, | 407 | .notifier_call = mpic_cascaded_secondary_init, |
380 | .priority = 100, | 408 | .priority = 100, |
381 | }; | 409 | }; |
382 | |||
383 | #endif /* CONFIG_SMP */ | 410 | #endif /* CONFIG_SMP */ |
384 | 411 | ||
385 | static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { | 412 | static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { |
@@ -588,9 +615,9 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, | |||
588 | 615 | ||
589 | BUG_ON(!armada_370_xp_mpic_domain); | 616 | BUG_ON(!armada_370_xp_mpic_domain); |
590 | 617 | ||
591 | #ifdef CONFIG_SMP | 618 | /* Setup for the boot CPU */ |
619 | armada_xp_mpic_perf_init(); | ||
592 | armada_xp_mpic_smp_cpu_init(); | 620 | armada_xp_mpic_smp_cpu_init(); |
593 | #endif | ||
594 | 621 | ||
595 | armada_370_xp_msi_init(node, main_int_res.start); | 622 | armada_370_xp_msi_init(node, main_int_res.start); |
596 | 623 | ||
diff --git a/drivers/irqchip/irq-digicolor.c b/drivers/irqchip/irq-digicolor.c index 930a2a2fac7f..3cbc658afe27 100644 --- a/drivers/irqchip/irq-digicolor.c +++ b/drivers/irqchip/irq-digicolor.c | |||
@@ -55,8 +55,8 @@ static void __exception_irq_entry digicolor_handle_irq(struct pt_regs *regs) | |||
55 | } while (1); | 55 | } while (1); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void digicolor_set_gc(void __iomem *reg_base, unsigned irq_base, | 58 | static void __init digicolor_set_gc(void __iomem *reg_base, unsigned irq_base, |
59 | unsigned en_reg, unsigned ack_reg) | 59 | unsigned en_reg, unsigned ack_reg) |
60 | { | 60 | { |
61 | struct irq_chip_generic *gc; | 61 | struct irq_chip_generic *gc; |
62 | 62 | ||
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 0b4a4d0238e7..d6d6b74801d4 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c | |||
@@ -414,7 +414,7 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic) | |||
414 | break; | 414 | break; |
415 | } | 415 | } |
416 | 416 | ||
417 | if (!mask) | 417 | if (!mask && num_possible_cpus() > 1) |
418 | pr_crit("GIC CPU mask not found - kernel will fail to boot.\n"); | 418 | pr_crit("GIC CPU mask not found - kernel will fail to boot.\n"); |
419 | 419 | ||
420 | return mask; | 420 | return mask; |
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 9acdc080e7ec..f2d269bca789 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c | |||
@@ -166,6 +166,27 @@ cycle_t gic_read_compare(void) | |||
166 | 166 | ||
167 | return (((cycle_t) hi) << 32) + lo; | 167 | return (((cycle_t) hi) << 32) + lo; |
168 | } | 168 | } |
169 | |||
170 | void gic_start_count(void) | ||
171 | { | ||
172 | u32 gicconfig; | ||
173 | |||
174 | /* Start the counter */ | ||
175 | gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); | ||
176 | gicconfig &= ~(1 << GIC_SH_CONFIG_COUNTSTOP_SHF); | ||
177 | gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); | ||
178 | } | ||
179 | |||
180 | void gic_stop_count(void) | ||
181 | { | ||
182 | u32 gicconfig; | ||
183 | |||
184 | /* Stop the counter */ | ||
185 | gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); | ||
186 | gicconfig |= 1 << GIC_SH_CONFIG_COUNTSTOP_SHF; | ||
187 | gic_write(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); | ||
188 | } | ||
189 | |||
169 | #endif | 190 | #endif |
170 | 191 | ||
171 | static bool gic_local_irq_is_routable(int intr) | 192 | static bool gic_local_irq_is_routable(int intr) |
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 2ea3412fdf8c..cdf80b7794cd 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/clk.h> | ||
20 | #include <linux/init.h> | 21 | #include <linux/init.h> |
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
@@ -29,15 +30,26 @@ | |||
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
30 | #include <linux/module.h> | 31 | #include <linux/module.h> |
31 | #include <linux/platform_data/irq-renesas-irqc.h> | 32 | #include <linux/platform_data/irq-renesas-irqc.h> |
33 | #include <linux/pm_runtime.h> | ||
32 | 34 | ||
33 | #define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */ | 35 | #define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */ |
34 | 36 | ||
35 | #define IRQC_REQ_STS 0x00 | 37 | #define IRQC_REQ_STS 0x00 /* Interrupt Request Status Register */ |
36 | #define IRQC_EN_STS 0x04 | 38 | #define IRQC_EN_STS 0x04 /* Interrupt Enable Status Register */ |
37 | #define IRQC_EN_SET 0x08 | 39 | #define IRQC_EN_SET 0x08 /* Interrupt Enable Set Register */ |
38 | #define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10)) | 40 | #define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10)) |
39 | #define DETECT_STATUS 0x100 | 41 | /* SYS-CPU vs. RT-CPU */ |
42 | #define DETECT_STATUS 0x100 /* IRQn Detect Status Register */ | ||
43 | #define MONITOR 0x104 /* IRQn Signal Level Monitor Register */ | ||
44 | #define HLVL_STS 0x108 /* IRQn High Level Detect Status Register */ | ||
45 | #define LLVL_STS 0x10c /* IRQn Low Level Detect Status Register */ | ||
46 | #define S_R_EDGE_STS 0x110 /* IRQn Sync Rising Edge Detect Status Reg. */ | ||
47 | #define S_F_EDGE_STS 0x114 /* IRQn Sync Falling Edge Detect Status Reg. */ | ||
48 | #define A_R_EDGE_STS 0x118 /* IRQn Async Rising Edge Detect Status Reg. */ | ||
49 | #define A_F_EDGE_STS 0x11c /* IRQn Async Falling Edge Detect Status Reg. */ | ||
50 | #define CHTEN_STS 0x120 /* Chattering Reduction Status Register */ | ||
40 | #define IRQC_CONFIG(n) (0x180 + ((n) * 0x04)) | 51 | #define IRQC_CONFIG(n) (0x180 + ((n) * 0x04)) |
52 | /* IRQn Configuration Register */ | ||
41 | 53 | ||
42 | struct irqc_irq { | 54 | struct irqc_irq { |
43 | int hw_irq; | 55 | int hw_irq; |
@@ -55,6 +67,7 @@ struct irqc_priv { | |||
55 | struct platform_device *pdev; | 67 | struct platform_device *pdev; |
56 | struct irq_chip irq_chip; | 68 | struct irq_chip irq_chip; |
57 | struct irq_domain *irq_domain; | 69 | struct irq_domain *irq_domain; |
70 | struct clk *clk; | ||
58 | }; | 71 | }; |
59 | 72 | ||
60 | static void irqc_dbg(struct irqc_irq *i, char *str) | 73 | static void irqc_dbg(struct irqc_irq *i, char *str) |
@@ -108,6 +121,21 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type) | |||
108 | return 0; | 121 | return 0; |
109 | } | 122 | } |
110 | 123 | ||
124 | static int irqc_irq_set_wake(struct irq_data *d, unsigned int on) | ||
125 | { | ||
126 | struct irqc_priv *p = irq_data_get_irq_chip_data(d); | ||
127 | |||
128 | if (!p->clk) | ||
129 | return 0; | ||
130 | |||
131 | if (on) | ||
132 | clk_enable(p->clk); | ||
133 | else | ||
134 | clk_disable(p->clk); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
111 | static irqreturn_t irqc_irq_handler(int irq, void *dev_id) | 139 | static irqreturn_t irqc_irq_handler(int irq, void *dev_id) |
112 | { | 140 | { |
113 | struct irqc_irq *i = dev_id; | 141 | struct irqc_irq *i = dev_id; |
@@ -170,6 +198,15 @@ static int irqc_probe(struct platform_device *pdev) | |||
170 | p->pdev = pdev; | 198 | p->pdev = pdev; |
171 | platform_set_drvdata(pdev, p); | 199 | platform_set_drvdata(pdev, p); |
172 | 200 | ||
201 | p->clk = devm_clk_get(&pdev->dev, NULL); | ||
202 | if (IS_ERR(p->clk)) { | ||
203 | dev_warn(&pdev->dev, "unable to get clock\n"); | ||
204 | p->clk = NULL; | ||
205 | } | ||
206 | |||
207 | pm_runtime_enable(&pdev->dev); | ||
208 | pm_runtime_get_sync(&pdev->dev); | ||
209 | |||
173 | /* get hold of manadatory IOMEM */ | 210 | /* get hold of manadatory IOMEM */ |
174 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 211 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
175 | if (!io) { | 212 | if (!io) { |
@@ -210,7 +247,8 @@ static int irqc_probe(struct platform_device *pdev) | |||
210 | irq_chip->irq_mask = irqc_irq_disable; | 247 | irq_chip->irq_mask = irqc_irq_disable; |
211 | irq_chip->irq_unmask = irqc_irq_enable; | 248 | irq_chip->irq_unmask = irqc_irq_enable; |
212 | irq_chip->irq_set_type = irqc_irq_set_type; | 249 | irq_chip->irq_set_type = irqc_irq_set_type; |
213 | irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; | 250 | irq_chip->irq_set_wake = irqc_irq_set_wake; |
251 | irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; | ||
214 | 252 | ||
215 | p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, | 253 | p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, |
216 | p->number_of_irqs, | 254 | p->number_of_irqs, |
@@ -250,6 +288,8 @@ err3: | |||
250 | err2: | 288 | err2: |
251 | iounmap(p->iomem); | 289 | iounmap(p->iomem); |
252 | err1: | 290 | err1: |
291 | pm_runtime_put(&pdev->dev); | ||
292 | pm_runtime_disable(&pdev->dev); | ||
253 | kfree(p); | 293 | kfree(p); |
254 | err0: | 294 | err0: |
255 | return ret; | 295 | return ret; |
@@ -265,6 +305,8 @@ static int irqc_remove(struct platform_device *pdev) | |||
265 | 305 | ||
266 | irq_domain_remove(p->irq_domain); | 306 | irq_domain_remove(p->irq_domain); |
267 | iounmap(p->iomem); | 307 | iounmap(p->iomem); |
308 | pm_runtime_put(&pdev->dev); | ||
309 | pm_runtime_disable(&pdev->dev); | ||
268 | kfree(p); | 310 | kfree(p); |
269 | return 0; | 311 | return 0; |
270 | } | 312 | } |
diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c new file mode 100644 index 000000000000..9521057d4744 --- /dev/null +++ b/drivers/irqchip/irq-vf610-mscm-ir.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2015 Toradex AG | ||
3 | * Author: Stefan Agner <stefan@agner.ch> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * | ||
10 | * IRQ chip driver for MSCM interrupt router available on Vybrid SoC's. | ||
11 | * The interrupt router is between the CPU's interrupt controller and the | ||
12 | * peripheral. The router allows to route the peripheral interrupts to | ||
13 | * one of the two available CPU's on Vybrid VF6xx SoC's (Cortex-A5 or | ||
14 | * Cortex-M4). The router will be configured transparently on a IRQ | ||
15 | * request. | ||
16 | * | ||
17 | * o All peripheral interrupts of the Vybrid SoC can be routed to | ||
18 | * CPU 0, CPU 1 or both. The routing is useful for dual-core | ||
19 | * variants of Vybrid SoC such as VF6xx. This driver routes the | ||
20 | * requested interrupt to the CPU currently running on. | ||
21 | * | ||
22 | * o It is required to setup the interrupt router even on single-core | ||
23 | * variants of Vybrid. | ||
24 | */ | ||
25 | |||
26 | #include <linux/cpu_pm.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/irqdomain.h> | ||
30 | #include <linux/mfd/syscon.h> | ||
31 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
32 | #include <linux/of.h> | ||
33 | #include <linux/of_address.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/regmap.h> | ||
36 | |||
37 | #include "irqchip.h" | ||
38 | |||
39 | #define MSCM_CPxNUM 0x4 | ||
40 | |||
41 | #define MSCM_IRSPRC(n) (0x80 + 2 * (n)) | ||
42 | #define MSCM_IRSPRC_CPEN_MASK 0x3 | ||
43 | |||
44 | #define MSCM_IRSPRC_NUM 112 | ||
45 | |||
46 | struct vf610_mscm_ir_chip_data { | ||
47 | void __iomem *mscm_ir_base; | ||
48 | u16 cpu_mask; | ||
49 | u16 saved_irsprc[MSCM_IRSPRC_NUM]; | ||
50 | }; | ||
51 | |||
52 | static struct vf610_mscm_ir_chip_data *mscm_ir_data; | ||
53 | |||
54 | static inline void vf610_mscm_ir_save(struct vf610_mscm_ir_chip_data *data) | ||
55 | { | ||
56 | int i; | ||
57 | |||
58 | for (i = 0; i < MSCM_IRSPRC_NUM; i++) | ||
59 | data->saved_irsprc[i] = readw_relaxed(data->mscm_ir_base + MSCM_IRSPRC(i)); | ||
60 | } | ||
61 | |||
62 | static inline void vf610_mscm_ir_restore(struct vf610_mscm_ir_chip_data *data) | ||
63 | { | ||
64 | int i; | ||
65 | |||
66 | for (i = 0; i < MSCM_IRSPRC_NUM; i++) | ||
67 | writew_relaxed(data->saved_irsprc[i], data->mscm_ir_base + MSCM_IRSPRC(i)); | ||
68 | } | ||
69 | |||
70 | static int vf610_mscm_ir_notifier(struct notifier_block *self, | ||
71 | unsigned long cmd, void *v) | ||
72 | { | ||
73 | switch (cmd) { | ||
74 | case CPU_CLUSTER_PM_ENTER: | ||
75 | vf610_mscm_ir_save(mscm_ir_data); | ||
76 | break; | ||
77 | case CPU_CLUSTER_PM_ENTER_FAILED: | ||
78 | case CPU_CLUSTER_PM_EXIT: | ||
79 | vf610_mscm_ir_restore(mscm_ir_data); | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | return NOTIFY_OK; | ||
84 | } | ||
85 | |||
86 | static struct notifier_block mscm_ir_notifier_block = { | ||
87 | .notifier_call = vf610_mscm_ir_notifier, | ||
88 | }; | ||
89 | |||
90 | static void vf610_mscm_ir_enable(struct irq_data *data) | ||
91 | { | ||
92 | irq_hw_number_t hwirq = data->hwirq; | ||
93 | struct vf610_mscm_ir_chip_data *chip_data = data->chip_data; | ||
94 | u16 irsprc; | ||
95 | |||
96 | irsprc = readw_relaxed(chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); | ||
97 | irsprc &= MSCM_IRSPRC_CPEN_MASK; | ||
98 | |||
99 | WARN_ON(irsprc & ~chip_data->cpu_mask); | ||
100 | |||
101 | writew_relaxed(chip_data->cpu_mask, | ||
102 | chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); | ||
103 | |||
104 | irq_chip_unmask_parent(data); | ||
105 | } | ||
106 | |||
107 | static void vf610_mscm_ir_disable(struct irq_data *data) | ||
108 | { | ||
109 | irq_hw_number_t hwirq = data->hwirq; | ||
110 | struct vf610_mscm_ir_chip_data *chip_data = data->chip_data; | ||
111 | |||
112 | writew_relaxed(0x0, chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); | ||
113 | |||
114 | irq_chip_mask_parent(data); | ||
115 | } | ||
116 | |||
117 | static struct irq_chip vf610_mscm_ir_irq_chip = { | ||
118 | .name = "mscm-ir", | ||
119 | .irq_mask = irq_chip_mask_parent, | ||
120 | .irq_unmask = irq_chip_unmask_parent, | ||
121 | .irq_eoi = irq_chip_eoi_parent, | ||
122 | .irq_enable = vf610_mscm_ir_enable, | ||
123 | .irq_disable = vf610_mscm_ir_disable, | ||
124 | .irq_retrigger = irq_chip_retrigger_hierarchy, | ||
125 | .irq_set_affinity = irq_chip_set_affinity_parent, | ||
126 | }; | ||
127 | |||
128 | static int vf610_mscm_ir_domain_alloc(struct irq_domain *domain, unsigned int virq, | ||
129 | unsigned int nr_irqs, void *arg) | ||
130 | { | ||
131 | int i; | ||
132 | irq_hw_number_t hwirq; | ||
133 | struct of_phandle_args *irq_data = arg; | ||
134 | struct of_phandle_args gic_data; | ||
135 | |||
136 | if (irq_data->args_count != 2) | ||
137 | return -EINVAL; | ||
138 | |||
139 | hwirq = irq_data->args[0]; | ||
140 | for (i = 0; i < nr_irqs; i++) | ||
141 | irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, | ||
142 | &vf610_mscm_ir_irq_chip, | ||
143 | domain->host_data); | ||
144 | |||
145 | gic_data.np = domain->parent->of_node; | ||
146 | gic_data.args_count = 3; | ||
147 | gic_data.args[0] = GIC_SPI; | ||
148 | gic_data.args[1] = irq_data->args[0]; | ||
149 | gic_data.args[2] = irq_data->args[1]; | ||
150 | return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); | ||
151 | } | ||
152 | |||
153 | static const struct irq_domain_ops mscm_irq_domain_ops = { | ||
154 | .xlate = irq_domain_xlate_twocell, | ||
155 | .alloc = vf610_mscm_ir_domain_alloc, | ||
156 | .free = irq_domain_free_irqs_common, | ||
157 | }; | ||
158 | |||
159 | static int __init vf610_mscm_ir_of_init(struct device_node *node, | ||
160 | struct device_node *parent) | ||
161 | { | ||
162 | struct irq_domain *domain, *domain_parent; | ||
163 | struct regmap *mscm_cp_regmap; | ||
164 | int ret, cpuid; | ||
165 | |||
166 | domain_parent = irq_find_host(parent); | ||
167 | if (!domain_parent) { | ||
168 | pr_err("vf610_mscm_ir: interrupt-parent not found\n"); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | mscm_ir_data = kzalloc(sizeof(*mscm_ir_data), GFP_KERNEL); | ||
173 | if (!mscm_ir_data) | ||
174 | return -ENOMEM; | ||
175 | |||
176 | mscm_ir_data->mscm_ir_base = of_io_request_and_map(node, 0, "mscm-ir"); | ||
177 | |||
178 | if (!mscm_ir_data->mscm_ir_base) { | ||
179 | pr_err("vf610_mscm_ir: unable to map mscm register\n"); | ||
180 | ret = -ENOMEM; | ||
181 | goto out_free; | ||
182 | } | ||
183 | |||
184 | mscm_cp_regmap = syscon_regmap_lookup_by_phandle(node, "fsl,cpucfg"); | ||
185 | if (IS_ERR(mscm_cp_regmap)) { | ||
186 | ret = PTR_ERR(mscm_cp_regmap); | ||
187 | pr_err("vf610_mscm_ir: regmap lookup for cpucfg failed\n"); | ||
188 | goto out_unmap; | ||
189 | } | ||
190 | |||
191 | regmap_read(mscm_cp_regmap, MSCM_CPxNUM, &cpuid); | ||
192 | mscm_ir_data->cpu_mask = 0x1 << cpuid; | ||
193 | |||
194 | domain = irq_domain_add_hierarchy(domain_parent, 0, | ||
195 | MSCM_IRSPRC_NUM, node, | ||
196 | &mscm_irq_domain_ops, mscm_ir_data); | ||
197 | if (!domain) { | ||
198 | ret = -ENOMEM; | ||
199 | goto out_unmap; | ||
200 | } | ||
201 | |||
202 | cpu_pm_register_notifier(&mscm_ir_notifier_block); | ||
203 | |||
204 | return 0; | ||
205 | |||
206 | out_unmap: | ||
207 | iounmap(mscm_ir_data->mscm_ir_base); | ||
208 | out_free: | ||
209 | kfree(mscm_ir_data); | ||
210 | return ret; | ||
211 | } | ||
212 | IRQCHIP_DECLARE(vf610_mscm_ir, "fsl,vf610-mscm-ir", vf610_mscm_ir_of_init); | ||
diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index e6a6aac451db..3ea2e4754c40 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h | |||
@@ -240,6 +240,8 @@ extern unsigned int gic_get_count_width(void); | |||
240 | extern cycle_t gic_read_compare(void); | 240 | extern cycle_t gic_read_compare(void); |
241 | extern void gic_write_compare(cycle_t cnt); | 241 | extern void gic_write_compare(cycle_t cnt); |
242 | extern void gic_write_cpu_compare(cycle_t cnt, int cpu); | 242 | extern void gic_write_cpu_compare(cycle_t cnt, int cpu); |
243 | extern void gic_start_count(void); | ||
244 | extern void gic_stop_count(void); | ||
243 | extern void gic_send_ipi(unsigned int intr); | 245 | extern void gic_send_ipi(unsigned int intr); |
244 | extern unsigned int plat_ipi_call_int_xlate(unsigned int); | 246 | extern unsigned int plat_ipi_call_int_xlate(unsigned int); |
245 | extern unsigned int plat_ipi_resched_int_xlate(unsigned int); | 247 | extern unsigned int plat_ipi_resched_int_xlate(unsigned int); |