diff options
author | Bartosz Golaszewski <bgolaszewski@baylibre.com> | 2019-02-14 09:52:30 -0500 |
---|---|---|
committer | Sekhar Nori <nsekhar@ti.com> | 2019-02-19 09:33:42 -0500 |
commit | 0fc3d74cf946b52dfea3be978ec07bf86990a46c (patch) | |
tree | c08763b1542e18b524161c5054fa67f606567375 /arch/arm/mach-davinci | |
parent | 3114111af5b1a4b4d111e8e78e8b97f76e4d326d (diff) |
irqchip: davinci-cp-intc: move the driver to drivers/irqchip
The cp-intc driver has now been cleaned up. Move it to drivers/irqchip
where it belongs.
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: David Lechner <david@lechnology.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Diffstat (limited to 'arch/arm/mach-davinci')
-rw-r--r-- | arch/arm/mach-davinci/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mach-davinci/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-davinci/cp_intc.c | 260 |
3 files changed, 2 insertions, 268 deletions
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 71a4d875dd39..5a59cebc7d0a 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig | |||
@@ -1,10 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | if ARCH_DAVINCI | 2 | if ARCH_DAVINCI |
3 | 3 | ||
4 | config CP_INTC | ||
5 | bool | ||
6 | select IRQ_DOMAIN | ||
7 | |||
8 | config ARCH_DAVINCI_DMx | 4 | config ARCH_DAVINCI_DMx |
9 | bool | 5 | bool |
10 | 6 | ||
@@ -33,13 +29,13 @@ config ARCH_DAVINCI_DA830 | |||
33 | select ARCH_DAVINCI_DA8XX | 29 | select ARCH_DAVINCI_DA8XX |
34 | # needed on silicon revs 1.0, 1.1: | 30 | # needed on silicon revs 1.0, 1.1: |
35 | select CPU_DCACHE_WRITETHROUGH if !CPU_DCACHE_DISABLE | 31 | select CPU_DCACHE_WRITETHROUGH if !CPU_DCACHE_DISABLE |
36 | select CP_INTC | 32 | select DAVINCI_CP_INTC |
37 | 33 | ||
38 | config ARCH_DAVINCI_DA850 | 34 | config ARCH_DAVINCI_DA850 |
39 | bool "DA850/OMAP-L138/AM18x based system" | 35 | bool "DA850/OMAP-L138/AM18x based system" |
40 | depends on !ARCH_DAVINCI_DMx || (AUTO_ZRELADDR && ARM_PATCH_PHYS_VIRT) | 36 | depends on !ARCH_DAVINCI_DMx || (AUTO_ZRELADDR && ARM_PATCH_PHYS_VIRT) |
41 | select ARCH_DAVINCI_DA8XX | 37 | select ARCH_DAVINCI_DA8XX |
42 | select CP_INTC | 38 | select DAVINCI_CP_INTC |
43 | 39 | ||
44 | config ARCH_DAVINCI_DA8XX | 40 | config ARCH_DAVINCI_DA8XX |
45 | bool | 41 | bool |
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index 983865a99616..f76a8482784f 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile | |||
@@ -18,8 +18,6 @@ obj-$(CONFIG_ARCH_DAVINCI_DM365) += dm365.o devices.o | |||
18 | obj-$(CONFIG_ARCH_DAVINCI_DA830) += da830.o devices-da8xx.o usb-da8xx.o | 18 | obj-$(CONFIG_ARCH_DAVINCI_DA830) += da830.o devices-da8xx.o usb-da8xx.o |
19 | obj-$(CONFIG_ARCH_DAVINCI_DA850) += da850.o devices-da8xx.o usb-da8xx.o | 19 | obj-$(CONFIG_ARCH_DAVINCI_DA850) += da850.o devices-da8xx.o usb-da8xx.o |
20 | 20 | ||
21 | obj-$(CONFIG_CP_INTC) += cp_intc.o | ||
22 | |||
23 | # Board specific | 21 | # Board specific |
24 | obj-$(CONFIG_MACH_DA8XX_DT) += da8xx-dt.o pdata-quirks.o | 22 | obj-$(CONFIG_MACH_DA8XX_DT) += da8xx-dt.o pdata-quirks.o |
25 | obj-$(CONFIG_MACH_DAVINCI_EVM) += board-dm644x-evm.o | 23 | obj-$(CONFIG_MACH_DAVINCI_EVM) += board-dm644x-evm.o |
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c deleted file mode 100644 index 276da2772e7f..000000000000 --- a/arch/arm/mach-davinci/cp_intc.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | // | ||
3 | // Author: Steve Chen <schen@mvista.com> | ||
4 | // Copyright (C) 2008-2009, MontaVista Software, Inc. <source@mvista.com> | ||
5 | // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
6 | // Copyright (C) 2019, Texas Instruments | ||
7 | // | ||
8 | // TI Common Platform Interrupt Controller (cp_intc) driver | ||
9 | |||
10 | #include <linux/export.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/irq.h> | ||
13 | #include <linux/irqchip.h> | ||
14 | #include <linux/irqchip/irq-davinci-cp-intc.h> | ||
15 | #include <linux/irqdomain.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/of_irq.h> | ||
20 | |||
21 | #include <asm/exception.h> | ||
22 | |||
23 | #define DAVINCI_CP_INTC_CTRL 0x04 | ||
24 | #define DAVINCI_CP_INTC_HOST_CTRL 0x0c | ||
25 | #define DAVINCI_CP_INTC_GLOBAL_ENABLE 0x10 | ||
26 | #define DAVINCI_CP_INTC_SYS_STAT_IDX_CLR 0x24 | ||
27 | #define DAVINCI_CP_INTC_SYS_ENABLE_IDX_SET 0x28 | ||
28 | #define DAVINCI_CP_INTC_SYS_ENABLE_IDX_CLR 0x2c | ||
29 | #define DAVINCI_CP_INTC_HOST_ENABLE_IDX_SET 0x34 | ||
30 | #define DAVINCI_CP_INTC_HOST_ENABLE_IDX_CLR 0x38 | ||
31 | #define DAVINCI_CP_INTC_PRIO_IDX 0x80 | ||
32 | #define DAVINCI_CP_INTC_SYS_STAT_CLR(n) (0x0280 + (n << 2)) | ||
33 | #define DAVINCI_CP_INTC_SYS_ENABLE_CLR(n) (0x0380 + (n << 2)) | ||
34 | #define DAVINCI_CP_INTC_CHAN_MAP(n) (0x0400 + (n << 2)) | ||
35 | #define DAVINCI_CP_INTC_SYS_POLARITY(n) (0x0d00 + (n << 2)) | ||
36 | #define DAVINCI_CP_INTC_SYS_TYPE(n) (0x0d80 + (n << 2)) | ||
37 | #define DAVINCI_CP_INTC_HOST_ENABLE(n) (0x1500 + (n << 2)) | ||
38 | #define DAVINCI_CP_INTC_PRI_INDX_MASK GENMASK(9, 0) | ||
39 | #define DAVINCI_CP_INTC_GPIR_NONE BIT(31) | ||
40 | |||
41 | static void __iomem *davinci_cp_intc_base; | ||
42 | static struct irq_domain *davinci_cp_intc_irq_domain; | ||
43 | |||
44 | static inline unsigned int davinci_cp_intc_read(unsigned int offset) | ||
45 | { | ||
46 | return readl_relaxed(davinci_cp_intc_base + offset); | ||
47 | } | ||
48 | |||
49 | static inline void davinci_cp_intc_write(unsigned long value, | ||
50 | unsigned int offset) | ||
51 | { | ||
52 | writel_relaxed(value, davinci_cp_intc_base + offset); | ||
53 | } | ||
54 | |||
55 | static void davinci_cp_intc_ack_irq(struct irq_data *d) | ||
56 | { | ||
57 | davinci_cp_intc_write(d->hwirq, DAVINCI_CP_INTC_SYS_STAT_IDX_CLR); | ||
58 | } | ||
59 | |||
60 | static void davinci_cp_intc_mask_irq(struct irq_data *d) | ||
61 | { | ||
62 | /* XXX don't know why we need to disable nIRQ here... */ | ||
63 | davinci_cp_intc_write(1, DAVINCI_CP_INTC_HOST_ENABLE_IDX_CLR); | ||
64 | davinci_cp_intc_write(d->hwirq, DAVINCI_CP_INTC_SYS_ENABLE_IDX_CLR); | ||
65 | davinci_cp_intc_write(1, DAVINCI_CP_INTC_HOST_ENABLE_IDX_SET); | ||
66 | } | ||
67 | |||
68 | static void davinci_cp_intc_unmask_irq(struct irq_data *d) | ||
69 | { | ||
70 | davinci_cp_intc_write(d->hwirq, DAVINCI_CP_INTC_SYS_ENABLE_IDX_SET); | ||
71 | } | ||
72 | |||
73 | static int davinci_cp_intc_set_irq_type(struct irq_data *d, | ||
74 | unsigned int flow_type) | ||
75 | { | ||
76 | unsigned int reg, mask, polarity, type; | ||
77 | |||
78 | reg = BIT_WORD(d->hwirq); | ||
79 | mask = BIT_MASK(d->hwirq); | ||
80 | polarity = davinci_cp_intc_read(DAVINCI_CP_INTC_SYS_POLARITY(reg)); | ||
81 | type = davinci_cp_intc_read(DAVINCI_CP_INTC_SYS_TYPE(reg)); | ||
82 | |||
83 | switch (flow_type) { | ||
84 | case IRQ_TYPE_EDGE_RISING: | ||
85 | polarity |= mask; | ||
86 | type |= mask; | ||
87 | break; | ||
88 | case IRQ_TYPE_EDGE_FALLING: | ||
89 | polarity &= ~mask; | ||
90 | type |= mask; | ||
91 | break; | ||
92 | case IRQ_TYPE_LEVEL_HIGH: | ||
93 | polarity |= mask; | ||
94 | type &= ~mask; | ||
95 | break; | ||
96 | case IRQ_TYPE_LEVEL_LOW: | ||
97 | polarity &= ~mask; | ||
98 | type &= ~mask; | ||
99 | break; | ||
100 | default: | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | davinci_cp_intc_write(polarity, DAVINCI_CP_INTC_SYS_POLARITY(reg)); | ||
105 | davinci_cp_intc_write(type, DAVINCI_CP_INTC_SYS_TYPE(reg)); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static struct irq_chip davinci_cp_intc_irq_chip = { | ||
111 | .name = "cp_intc", | ||
112 | .irq_ack = davinci_cp_intc_ack_irq, | ||
113 | .irq_mask = davinci_cp_intc_mask_irq, | ||
114 | .irq_unmask = davinci_cp_intc_unmask_irq, | ||
115 | .irq_set_type = davinci_cp_intc_set_irq_type, | ||
116 | .flags = IRQCHIP_SKIP_SET_WAKE, | ||
117 | }; | ||
118 | |||
119 | static asmlinkage void __exception_irq_entry | ||
120 | davinci_cp_intc_handle_irq(struct pt_regs *regs) | ||
121 | { | ||
122 | int gpir, irqnr, none; | ||
123 | |||
124 | /* | ||
125 | * The interrupt number is in first ten bits. The NONE field set to 1 | ||
126 | * indicates a spurious irq. | ||
127 | */ | ||
128 | |||
129 | gpir = davinci_cp_intc_read(DAVINCI_CP_INTC_PRIO_IDX); | ||
130 | irqnr = gpir & DAVINCI_CP_INTC_PRI_INDX_MASK; | ||
131 | none = gpir & DAVINCI_CP_INTC_GPIR_NONE; | ||
132 | |||
133 | if (unlikely(none)) { | ||
134 | pr_err_once("%s: spurious irq!\n", __func__); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | handle_domain_irq(davinci_cp_intc_irq_domain, irqnr, regs); | ||
139 | } | ||
140 | |||
141 | static int davinci_cp_intc_host_map(struct irq_domain *h, unsigned int virq, | ||
142 | irq_hw_number_t hw) | ||
143 | { | ||
144 | pr_debug("cp_intc_host_map(%d, 0x%lx)\n", virq, hw); | ||
145 | |||
146 | irq_set_chip(virq, &davinci_cp_intc_irq_chip); | ||
147 | irq_set_probe(virq); | ||
148 | irq_set_handler(virq, handle_edge_irq); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static const struct irq_domain_ops davinci_cp_intc_irq_domain_ops = { | ||
154 | .map = davinci_cp_intc_host_map, | ||
155 | .xlate = irq_domain_xlate_onetwocell, | ||
156 | }; | ||
157 | |||
158 | static int __init | ||
159 | davinci_cp_intc_do_init(const struct davinci_cp_intc_config *config, | ||
160 | struct device_node *node) | ||
161 | { | ||
162 | unsigned int num_regs = BITS_TO_LONGS(config->num_irqs); | ||
163 | int offset, irq_base; | ||
164 | void __iomem *req; | ||
165 | |||
166 | req = request_mem_region(config->reg.start, | ||
167 | resource_size(&config->reg), | ||
168 | "davinci-cp-intc"); | ||
169 | if (!req) { | ||
170 | pr_err("%s: register range busy\n", __func__); | ||
171 | return -EBUSY; | ||
172 | } | ||
173 | |||
174 | davinci_cp_intc_base = ioremap(config->reg.start, | ||
175 | resource_size(&config->reg)); | ||
176 | if (!davinci_cp_intc_base) { | ||
177 | pr_err("%s: unable to ioremap register range\n", __func__); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | |||
181 | davinci_cp_intc_write(0, DAVINCI_CP_INTC_GLOBAL_ENABLE); | ||
182 | |||
183 | /* Disable all host interrupts */ | ||
184 | davinci_cp_intc_write(0, DAVINCI_CP_INTC_HOST_ENABLE(0)); | ||
185 | |||
186 | /* Disable system interrupts */ | ||
187 | for (offset = 0; offset < num_regs; offset++) | ||
188 | davinci_cp_intc_write(~0, | ||
189 | DAVINCI_CP_INTC_SYS_ENABLE_CLR(offset)); | ||
190 | |||
191 | /* Set to normal mode, no nesting, no priority hold */ | ||
192 | davinci_cp_intc_write(0, DAVINCI_CP_INTC_CTRL); | ||
193 | davinci_cp_intc_write(0, DAVINCI_CP_INTC_HOST_CTRL); | ||
194 | |||
195 | /* Clear system interrupt status */ | ||
196 | for (offset = 0; offset < num_regs; offset++) | ||
197 | davinci_cp_intc_write(~0, | ||
198 | DAVINCI_CP_INTC_SYS_STAT_CLR(offset)); | ||
199 | |||
200 | /* Enable nIRQ (what about nFIQ?) */ | ||
201 | davinci_cp_intc_write(1, DAVINCI_CP_INTC_HOST_ENABLE_IDX_SET); | ||
202 | |||
203 | /* Default all priorities to channel 7. */ | ||
204 | num_regs = (config->num_irqs + 3) >> 2; /* 4 channels per register */ | ||
205 | for (offset = 0; offset < num_regs; offset++) | ||
206 | davinci_cp_intc_write(0x07070707, | ||
207 | DAVINCI_CP_INTC_CHAN_MAP(offset)); | ||
208 | |||
209 | irq_base = irq_alloc_descs(-1, 0, config->num_irqs, 0); | ||
210 | if (irq_base < 0) { | ||
211 | pr_err("%s: unable to allocate interrupt descriptors: %d\n", | ||
212 | __func__, irq_base); | ||
213 | return irq_base; | ||
214 | } | ||
215 | |||
216 | davinci_cp_intc_irq_domain = irq_domain_add_legacy( | ||
217 | node, config->num_irqs, irq_base, 0, | ||
218 | &davinci_cp_intc_irq_domain_ops, NULL); | ||
219 | |||
220 | if (!davinci_cp_intc_irq_domain) { | ||
221 | pr_err("%s: unable to create an interrupt domain\n", __func__); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | set_handle_irq(davinci_cp_intc_handle_irq); | ||
226 | |||
227 | /* Enable global interrupt */ | ||
228 | davinci_cp_intc_write(1, DAVINCI_CP_INTC_GLOBAL_ENABLE); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | int __init davinci_cp_intc_init(const struct davinci_cp_intc_config *config) | ||
234 | { | ||
235 | return davinci_cp_intc_do_init(config, NULL); | ||
236 | } | ||
237 | |||
238 | static int __init davinci_cp_intc_of_init(struct device_node *node, | ||
239 | struct device_node *parent) | ||
240 | { | ||
241 | struct davinci_cp_intc_config config = { }; | ||
242 | int ret; | ||
243 | |||
244 | ret = of_address_to_resource(node, 0, &config.reg); | ||
245 | if (ret) { | ||
246 | pr_err("%s: unable to get the register range from device-tree\n", | ||
247 | __func__); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | ret = of_property_read_u32(node, "ti,intc-size", &config.num_irqs); | ||
252 | if (ret) { | ||
253 | pr_err("%s: unable to read the 'ti,intc-size' property\n", | ||
254 | __func__); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | return davinci_cp_intc_do_init(&config, node); | ||
259 | } | ||
260 | IRQCHIP_DECLARE(cp_intc, "ti,cp-intc", davinci_cp_intc_of_init); | ||