xref: /linux/drivers/irqchip/irq-ixp4xx.c (revision 2fe3c78a2c26dd5ee811024a1b7d6cfb4d654319)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * irqchip for the IXP4xx interrupt controller
4  * Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
5  *
6  * Based on arch/arm/mach-ixp4xx/common.c
7  * Copyright 2002 (C) Intel Corporation
8  * Copyright 2003-2004 (C) MontaVista, Software, Inc.
9  * Copyright (C) Deepak Saxena <dsaxena@plexity.net>
10  */
11 #include <linux/bitops.h>
12 #include <linux/gpio/driver.h>
13 #include <linux/irq.h>
14 #include <linux/io.h>
15 #include <linux/irqchip.h>
16 #include <linux/irqdomain.h>
17 #include <linux/of.h>
18 #include <linux/of_address.h>
19 #include <linux/of_irq.h>
20 #include <linux/platform_device.h>
21 #include <linux/cpu.h>
22 
23 #include <asm/exception.h>
24 #include <asm/mach/irq.h>
25 
26 #define IXP4XX_ICPR	0x00 /* Interrupt Status */
27 #define IXP4XX_ICMR	0x04 /* Interrupt Enable */
28 #define IXP4XX_ICLR	0x08 /* Interrupt IRQ/FIQ Select */
29 #define IXP4XX_ICIP	0x0C /* IRQ Status */
30 #define IXP4XX_ICFP	0x10 /* FIQ Status */
31 #define IXP4XX_ICHR	0x14 /* Interrupt Priority */
32 #define IXP4XX_ICIH	0x18 /* IRQ Highest Pri Int */
33 #define IXP4XX_ICFH	0x1C /* FIQ Highest Pri Int */
34 
35 /* IXP43x and IXP46x-only */
36 #define	IXP4XX_ICPR2	0x20 /* Interrupt Status 2 */
37 #define	IXP4XX_ICMR2	0x24 /* Interrupt Enable 2 */
38 #define	IXP4XX_ICLR2	0x28 /* Interrupt IRQ/FIQ Select 2 */
39 #define IXP4XX_ICIP2	0x2C /* IRQ Status */
40 #define IXP4XX_ICFP2	0x30 /* FIQ Status */
41 #define IXP4XX_ICEEN	0x34 /* Error High Pri Enable */
42 
43 /**
44  * struct ixp4xx_irq - state container for the Faraday IRQ controller
45  * @irqbase: IRQ controller memory base in virtual memory
46  * @is_356: if this is an IXP43x, IXP45x or IX46x SoC (with 64 IRQs)
47  * @irqchip: irqchip for this instance
48  * @domain: IRQ domain for this instance
49  */
50 struct ixp4xx_irq {
51 	void __iomem *irqbase;
52 	bool is_356;
53 	struct irq_chip irqchip;
54 	struct irq_domain *domain;
55 };
56 
57 /* Local static state container */
58 static struct ixp4xx_irq ixirq;
59 
60 /* GPIO Clocks */
61 #define IXP4XX_GPIO_CLK_0		14
62 #define IXP4XX_GPIO_CLK_1		15
63 
64 static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
65 {
66 	/* All are level active high (asserted) here */
67 	if (type != IRQ_TYPE_LEVEL_HIGH)
68 		return -EINVAL;
69 	return 0;
70 }
71 
72 static void ixp4xx_irq_mask(struct irq_data *d)
73 {
74 	struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
75 	u32 val;
76 
77 	if (ixi->is_356 && d->hwirq >= 32) {
78 		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
79 		val &= ~BIT(d->hwirq - 32);
80 		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
81 	} else {
82 		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
83 		val &= ~BIT(d->hwirq);
84 		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
85 	}
86 }
87 
88 /*
89  * Level triggered interrupts on GPIO lines can only be cleared when the
90  * interrupt condition disappears.
91  */
92 static void ixp4xx_irq_unmask(struct irq_data *d)
93 {
94 	struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
95 	u32 val;
96 
97 	if (ixi->is_356 && d->hwirq >= 32) {
98 		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
99 		val |= BIT(d->hwirq - 32);
100 		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
101 	} else {
102 		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
103 		val |= BIT(d->hwirq);
104 		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
105 	}
106 }
107 
108 static void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
109 {
110 	struct ixp4xx_irq *ixi = &ixirq;
111 	unsigned long status;
112 	int i;
113 
114 	status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
115 	for_each_set_bit(i, &status, 32)
116 		generic_handle_domain_irq(ixi->domain, i);
117 
118 	/*
119 	 * IXP465/IXP435 has an upper IRQ status register
120 	 */
121 	if (ixi->is_356) {
122 		status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
123 		for_each_set_bit(i, &status, 32)
124 			generic_handle_domain_irq(ixi->domain, i + 32);
125 	}
126 }
127 
128 static int ixp4xx_irq_domain_translate(struct irq_domain *domain,
129 				       struct irq_fwspec *fwspec,
130 				       unsigned long *hwirq,
131 				       unsigned int *type)
132 {
133 	/* We support standard DT translation */
134 	if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
135 		*hwirq = fwspec->param[0];
136 		*type = fwspec->param[1];
137 		return 0;
138 	}
139 
140 	if (is_fwnode_irqchip(fwspec->fwnode)) {
141 		if (fwspec->param_count != 2)
142 			return -EINVAL;
143 		*hwirq = fwspec->param[0];
144 		*type = fwspec->param[1];
145 		WARN_ON(*type == IRQ_TYPE_NONE);
146 		return 0;
147 	}
148 
149 	return -EINVAL;
150 }
151 
152 static int ixp4xx_irq_domain_alloc(struct irq_domain *d,
153 				   unsigned int irq, unsigned int nr_irqs,
154 				   void *data)
155 {
156 	struct ixp4xx_irq *ixi = d->host_data;
157 	irq_hw_number_t hwirq;
158 	unsigned int type = IRQ_TYPE_NONE;
159 	struct irq_fwspec *fwspec = data;
160 	int ret;
161 	int i;
162 
163 	ret = ixp4xx_irq_domain_translate(d, fwspec, &hwirq, &type);
164 	if (ret)
165 		return ret;
166 
167 	for (i = 0; i < nr_irqs; i++) {
168 		/*
169 		 * TODO: after converting IXP4xx to only device tree, set
170 		 * handle_bad_irq as default handler and assume all consumers
171 		 * call .set_type() as this is provided in the second cell in
172 		 * the device tree phandle.
173 		 */
174 		irq_domain_set_info(d,
175 				    irq + i,
176 				    hwirq + i,
177 				    &ixi->irqchip,
178 				    ixi,
179 				    handle_level_irq,
180 				    NULL, NULL);
181 		irq_set_probe(irq + i);
182 	}
183 
184 	return 0;
185 }
186 
187 /*
188  * This needs to be a hierarchical irqdomain to work well with the
189  * GPIO irqchip (which is lower in the hierarchy)
190  */
191 static const struct irq_domain_ops ixp4xx_irqdomain_ops = {
192 	.translate = ixp4xx_irq_domain_translate,
193 	.alloc = ixp4xx_irq_domain_alloc,
194 	.free = irq_domain_free_irqs_common,
195 };
196 
197 /**
198  * ixp4x_irq_setup() - Common setup code for the IXP4xx interrupt controller
199  * @ixi: State container
200  * @irqbase: Virtual memory base for the interrupt controller
201  * @fwnode: Corresponding fwnode abstraction for this controller
202  * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
203  */
204 static int __init ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
205 				   void __iomem *irqbase,
206 				   struct fwnode_handle *fwnode,
207 				   bool is_356)
208 {
209 	int nr_irqs;
210 
211 	ixi->irqbase = irqbase;
212 	ixi->is_356 = is_356;
213 
214 	/* Route all sources to IRQ instead of FIQ */
215 	__raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR);
216 
217 	/* Disable all interrupts */
218 	__raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR);
219 
220 	if (is_356) {
221 		/* Route upper 32 sources to IRQ instead of FIQ */
222 		__raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR2);
223 
224 		/* Disable upper 32 interrupts */
225 		__raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR2);
226 
227 		nr_irqs = 64;
228 	} else {
229 		nr_irqs = 32;
230 	}
231 
232 	ixi->irqchip.name = "IXP4xx";
233 	ixi->irqchip.irq_mask = ixp4xx_irq_mask;
234 	ixi->irqchip.irq_unmask	= ixp4xx_irq_unmask;
235 	ixi->irqchip.irq_set_type = ixp4xx_set_irq_type;
236 
237 	ixi->domain = irq_domain_create_linear(fwnode, nr_irqs,
238 					       &ixp4xx_irqdomain_ops,
239 					       ixi);
240 	if (!ixi->domain) {
241 		pr_crit("IXP4XX: can not add primary irqdomain\n");
242 		return -ENODEV;
243 	}
244 
245 	set_handle_irq(ixp4xx_handle_irq);
246 
247 	return 0;
248 }
249 
250 static int __init ixp4xx_of_init_irq(struct device_node *np,
251 				     struct device_node *parent)
252 {
253 	struct ixp4xx_irq *ixi = &ixirq;
254 	void __iomem *base;
255 	struct fwnode_handle *fwnode;
256 	bool is_356;
257 	int ret;
258 
259 	base = of_iomap(np, 0);
260 	if (!base) {
261 		pr_crit("IXP4XX: could not ioremap interrupt controller\n");
262 		return -ENODEV;
263 	}
264 	fwnode = of_node_to_fwnode(np);
265 
266 	/* These chip variants have 64 interrupts */
267 	is_356 = of_device_is_compatible(np, "intel,ixp43x-interrupt") ||
268 		of_device_is_compatible(np, "intel,ixp45x-interrupt") ||
269 		of_device_is_compatible(np, "intel,ixp46x-interrupt");
270 
271 	ret = ixp4xx_irq_setup(ixi, base, fwnode, is_356);
272 	if (ret)
273 		pr_crit("IXP4XX: failed to set up irqchip\n");
274 
275 	return ret;
276 }
277 IRQCHIP_DECLARE(ixp42x, "intel,ixp42x-interrupt",
278 		ixp4xx_of_init_irq);
279 IRQCHIP_DECLARE(ixp43x, "intel,ixp43x-interrupt",
280 		ixp4xx_of_init_irq);
281 IRQCHIP_DECLARE(ixp45x, "intel,ixp45x-interrupt",
282 		ixp4xx_of_init_irq);
283 IRQCHIP_DECLARE(ixp46x, "intel,ixp46x-interrupt",
284 		ixp4xx_of_init_irq);
285