diff options
author | Miodrag Dinic <miodrag.dinic@mips.com> | 2017-12-29 10:41:46 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2018-01-04 06:14:04 -0500 |
commit | 4235ff50cf98dd42ba15175687570f9f03e124a1 (patch) | |
tree | 413436fa79b8f1d9e0961255fdabe27357b8cf40 | |
parent | c2ba80af4805543ace4928191d877ffe706087e1 (diff) |
irqchip/irq-goldfish-pic: Add Goldfish PIC driver
Add device driver for a virtual programmable interrupt controller
The virtual PIC is designed as a device tree-based interrupt controller.
The compatible string used by OS for binding the driver is
"google,goldfish-pic".
Signed-off-by: Miodrag Dinic <miodrag.dinic@mips.com>
Signed-off-by: Goran Ferenc <goran.ferenc@mips.com>
Signed-off-by: Aleksandar Markovic <aleksandar.markovic@mips.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/irqchip/Kconfig | 8 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-goldfish-pic.c | 139 |
4 files changed, 149 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index fe9a60ac81d8..f3b9b8775e41 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -871,6 +871,7 @@ ANDROID GOLDFISH PIC DRIVER | |||
871 | M: Miodrag Dinic <miodrag.dinic@mips.com> | 871 | M: Miodrag Dinic <miodrag.dinic@mips.com> |
872 | S: Supported | 872 | S: Supported |
873 | F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt | 873 | F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt |
874 | F: drivers/irqchip/irq-goldfish-pic.c | ||
874 | 875 | ||
875 | ANDROID GOLDFISH RTC DRIVER | 876 | ANDROID GOLDFISH RTC DRIVER |
876 | M: Miodrag Dinic <miodrag.dinic@mips.com> | 877 | M: Miodrag Dinic <miodrag.dinic@mips.com> |
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index c70476b34a53..d913aec85109 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -343,4 +343,12 @@ config MESON_IRQ_GPIO | |||
343 | help | 343 | help |
344 | Support Meson SoC Family GPIO Interrupt Multiplexer | 344 | Support Meson SoC Family GPIO Interrupt Multiplexer |
345 | 345 | ||
346 | config GOLDFISH_PIC | ||
347 | bool "Goldfish programmable interrupt controller" | ||
348 | depends on MIPS && (GOLDFISH || COMPILE_TEST) | ||
349 | select IRQ_DOMAIN | ||
350 | help | ||
351 | Say yes here to enable Goldfish interrupt controller driver used | ||
352 | for Goldfish based virtual platforms. | ||
353 | |||
346 | endmenu | 354 | endmenu |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index d2df34a54d38..d27e3e3619e0 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -84,3 +84,4 @@ obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o | |||
84 | obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o | 84 | obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o |
85 | obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o | 85 | obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o |
86 | obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o | 86 | obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o |
87 | obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o | ||
diff --git a/drivers/irqchip/irq-goldfish-pic.c b/drivers/irqchip/irq-goldfish-pic.c new file mode 100644 index 000000000000..2a92f03c73e4 --- /dev/null +++ b/drivers/irqchip/irq-goldfish-pic.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Driver for MIPS Goldfish Programmable Interrupt Controller. | ||
3 | * | ||
4 | * Author: Miodrag Dinic <miodrag.dinic@mips.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | |||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/irqchip.h> | ||
17 | #include <linux/irqchip/chained_irq.h> | ||
18 | #include <linux/irqdomain.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/of_irq.h> | ||
21 | |||
22 | #define GFPIC_NR_IRQS 32 | ||
23 | |||
24 | /* 8..39 Cascaded Goldfish PIC interrupts */ | ||
25 | #define GFPIC_IRQ_BASE 8 | ||
26 | |||
27 | #define GFPIC_REG_IRQ_PENDING 0x04 | ||
28 | #define GFPIC_REG_IRQ_DISABLE_ALL 0x08 | ||
29 | #define GFPIC_REG_IRQ_DISABLE 0x0c | ||
30 | #define GFPIC_REG_IRQ_ENABLE 0x10 | ||
31 | |||
32 | struct goldfish_pic_data { | ||
33 | void __iomem *base; | ||
34 | struct irq_domain *irq_domain; | ||
35 | }; | ||
36 | |||
37 | static void goldfish_pic_cascade(struct irq_desc *desc) | ||
38 | { | ||
39 | struct goldfish_pic_data *gfpic = irq_desc_get_handler_data(desc); | ||
40 | struct irq_chip *host_chip = irq_desc_get_chip(desc); | ||
41 | u32 pending, hwirq, virq; | ||
42 | |||
43 | chained_irq_enter(host_chip, desc); | ||
44 | |||
45 | pending = readl(gfpic->base + GFPIC_REG_IRQ_PENDING); | ||
46 | while (pending) { | ||
47 | hwirq = __fls(pending); | ||
48 | virq = irq_linear_revmap(gfpic->irq_domain, hwirq); | ||
49 | generic_handle_irq(virq); | ||
50 | pending &= ~(1 << hwirq); | ||
51 | } | ||
52 | |||
53 | chained_irq_exit(host_chip, desc); | ||
54 | } | ||
55 | |||
56 | static const struct irq_domain_ops goldfish_irq_domain_ops = { | ||
57 | .xlate = irq_domain_xlate_onecell, | ||
58 | }; | ||
59 | |||
60 | static int __init goldfish_pic_of_init(struct device_node *of_node, | ||
61 | struct device_node *parent) | ||
62 | { | ||
63 | struct goldfish_pic_data *gfpic; | ||
64 | struct irq_chip_generic *gc; | ||
65 | struct irq_chip_type *ct; | ||
66 | unsigned int parent_irq; | ||
67 | int ret = 0; | ||
68 | |||
69 | gfpic = kzalloc(sizeof(*gfpic), GFP_KERNEL); | ||
70 | if (!gfpic) { | ||
71 | ret = -ENOMEM; | ||
72 | goto out_err; | ||
73 | } | ||
74 | |||
75 | parent_irq = irq_of_parse_and_map(of_node, 0); | ||
76 | if (!parent_irq) { | ||
77 | pr_err("Failed to map parent IRQ!\n"); | ||
78 | ret = -EINVAL; | ||
79 | goto out_free; | ||
80 | } | ||
81 | |||
82 | gfpic->base = of_iomap(of_node, 0); | ||
83 | if (!gfpic->base) { | ||
84 | pr_err("Failed to map base address!\n"); | ||
85 | ret = -ENOMEM; | ||
86 | goto out_unmap_irq; | ||
87 | } | ||
88 | |||
89 | /* Mask interrupts. */ | ||
90 | writel(1, gfpic->base + GFPIC_REG_IRQ_DISABLE_ALL); | ||
91 | |||
92 | gc = irq_alloc_generic_chip("GFPIC", 1, GFPIC_IRQ_BASE, gfpic->base, | ||
93 | handle_level_irq); | ||
94 | if (!gc) { | ||
95 | pr_err("Failed to allocate chip structures!\n"); | ||
96 | ret = -ENOMEM; | ||
97 | goto out_iounmap; | ||
98 | } | ||
99 | |||
100 | ct = gc->chip_types; | ||
101 | ct->regs.enable = GFPIC_REG_IRQ_ENABLE; | ||
102 | ct->regs.disable = GFPIC_REG_IRQ_DISABLE; | ||
103 | ct->chip.irq_unmask = irq_gc_unmask_enable_reg; | ||
104 | ct->chip.irq_mask = irq_gc_mask_disable_reg; | ||
105 | |||
106 | irq_setup_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS), 0, | ||
107 | IRQ_NOPROBE | IRQ_LEVEL, 0); | ||
108 | |||
109 | gfpic->irq_domain = irq_domain_add_legacy(of_node, GFPIC_NR_IRQS, | ||
110 | GFPIC_IRQ_BASE, 0, | ||
111 | &goldfish_irq_domain_ops, | ||
112 | NULL); | ||
113 | if (!gfpic->irq_domain) { | ||
114 | pr_err("Failed to add irqdomain!\n"); | ||
115 | ret = -ENOMEM; | ||
116 | goto out_destroy_generic_chip; | ||
117 | } | ||
118 | |||
119 | irq_set_chained_handler_and_data(parent_irq, | ||
120 | goldfish_pic_cascade, gfpic); | ||
121 | |||
122 | pr_info("Successfully registered.\n"); | ||
123 | return 0; | ||
124 | |||
125 | out_destroy_generic_chip: | ||
126 | irq_destroy_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS), | ||
127 | IRQ_NOPROBE | IRQ_LEVEL, 0); | ||
128 | out_iounmap: | ||
129 | iounmap(gfpic->base); | ||
130 | out_unmap_irq: | ||
131 | irq_dispose_mapping(parent_irq); | ||
132 | out_free: | ||
133 | kfree(gfpic); | ||
134 | out_err: | ||
135 | pr_err("Failed to initialize! (errno = %d)\n", ret); | ||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | IRQCHIP_DECLARE(google_gf_pic, "google,goldfish-pic", goldfish_pic_of_init); | ||