xref: /openbmc/linux/drivers/irqchip/irq-ixp4xx.c (revision 2243acd5)
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 asmlinkage void __exception_irq_entry
109 ixp4xx_handle_irq(struct pt_regs *regs)
110 {
111 	struct ixp4xx_irq *ixi = &ixirq;
112 	unsigned long status;
113 	int i;
114 
115 	status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
116 	for_each_set_bit(i, &status, 32)
117 		generic_handle_domain_irq(ixi->domain, i);
118 
119 	/*
120 	 * IXP465/IXP435 has an upper IRQ status register
121 	 */
122 	if (ixi->is_356) {
123 		status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
124 		for_each_set_bit(i, &status, 32)
125 			generic_handle_domain_irq(ixi->domain, i + 32);
126 	}
127 }
128 
129 static int ixp4xx_irq_domain_translate(struct irq_domain *domain,
130 				       struct irq_fwspec *fwspec,
131 				       unsigned long *hwirq,
132 				       unsigned int *type)
133 {
134 	/* We support standard DT translation */
135 	if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
136 		*hwirq = fwspec->param[0];
137 		*type = fwspec->param[1];
138 		return 0;
139 	}
140 
141 	if (is_fwnode_irqchip(fwspec->fwnode)) {
142 		if (fwspec->param_count != 2)
143 			return -EINVAL;
144 		*hwirq = fwspec->param[0];
145 		*type = fwspec->param[1];
146 		WARN_ON(*type == IRQ_TYPE_NONE);
147 		return 0;
148 	}
149 
150 	return -EINVAL;
151 }
152 
153 static int ixp4xx_irq_domain_alloc(struct irq_domain *d,
154 				   unsigned int irq, unsigned int nr_irqs,
155 				   void *data)
156 {
157 	struct ixp4xx_irq *ixi = d->host_data;
158 	irq_hw_number_t hwirq;
159 	unsigned int type = IRQ_TYPE_NONE;
160 	struct irq_fwspec *fwspec = data;
161 	int ret;
162 	int i;
163 
164 	ret = ixp4xx_irq_domain_translate(d, fwspec, &hwirq, &type);
165 	if (ret)
166 		return ret;
167 
168 	for (i = 0; i < nr_irqs; i++) {
169 		/*
170 		 * TODO: after converting IXP4xx to only device tree, set
171 		 * handle_bad_irq as default handler and assume all consumers
172 		 * call .set_type() as this is provided in the second cell in
173 		 * the device tree phandle.
174 		 */
175 		irq_domain_set_info(d,
176 				    irq + i,
177 				    hwirq + i,
178 				    &ixi->irqchip,
179 				    ixi,
180 				    handle_level_irq,
181 				    NULL, NULL);
182 		irq_set_probe(irq + i);
183 	}
184 
185 	return 0;
186 }
187 
188 /*
189  * This needs to be a hierarchical irqdomain to work well with the
190  * GPIO irqchip (which is lower in the hierarchy)
191  */
192 static const struct irq_domain_ops ixp4xx_irqdomain_ops = {
193 	.translate = ixp4xx_irq_domain_translate,
194 	.alloc = ixp4xx_irq_domain_alloc,
195 	.free = irq_domain_free_irqs_common,
196 };
197 
198 /**
199  * ixp4x_irq_setup() - Common setup code for the IXP4xx interrupt controller
200  * @ixi: State container
201  * @irqbase: Virtual memory base for the interrupt controller
202  * @fwnode: Corresponding fwnode abstraction for this controller
203  * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
204  */
205 static int __init ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
206 				   void __iomem *irqbase,
207 				   struct fwnode_handle *fwnode,
208 				   bool is_356)
209 {
210 	int nr_irqs;
211 
212 	ixi->irqbase = irqbase;
213 	ixi->is_356 = is_356;
214 
215 	/* Route all sources to IRQ instead of FIQ */
216 	__raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR);
217 
218 	/* Disable all interrupts */
219 	__raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR);
220 
221 	if (is_356) {
222 		/* Route upper 32 sources to IRQ instead of FIQ */
223 		__raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR2);
224 
225 		/* Disable upper 32 interrupts */
226 		__raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR2);
227 
228 		nr_irqs = 64;
229 	} else {
230 		nr_irqs = 32;
231 	}
232 
233 	ixi->irqchip.name = "IXP4xx";
234 	ixi->irqchip.irq_mask = ixp4xx_irq_mask;
235 	ixi->irqchip.irq_unmask	= ixp4xx_irq_unmask;
236 	ixi->irqchip.irq_set_type = ixp4xx_set_irq_type;
237 
238 	ixi->domain = irq_domain_create_linear(fwnode, nr_irqs,
239 					       &ixp4xx_irqdomain_ops,
240 					       ixi);
241 	if (!ixi->domain) {
242 		pr_crit("IXP4XX: can not add primary irqdomain\n");
243 		return -ENODEV;
244 	}
245 
246 	set_handle_irq(ixp4xx_handle_irq);
247 
248 	return 0;
249 }
250 
251 static int __init ixp4xx_of_init_irq(struct device_node *np,
252 				     struct device_node *parent)
253 {
254 	struct ixp4xx_irq *ixi = &ixirq;
255 	void __iomem *base;
256 	struct fwnode_handle *fwnode;
257 	bool is_356;
258 	int ret;
259 
260 	base = of_iomap(np, 0);
261 	if (!base) {
262 		pr_crit("IXP4XX: could not ioremap interrupt controller\n");
263 		return -ENODEV;
264 	}
265 	fwnode = of_node_to_fwnode(np);
266 
267 	/* These chip variants have 64 interrupts */
268 	is_356 = of_device_is_compatible(np, "intel,ixp43x-interrupt") ||
269 		of_device_is_compatible(np, "intel,ixp45x-interrupt") ||
270 		of_device_is_compatible(np, "intel,ixp46x-interrupt");
271 
272 	ret = ixp4xx_irq_setup(ixi, base, fwnode, is_356);
273 	if (ret)
274 		pr_crit("IXP4XX: failed to set up irqchip\n");
275 
276 	return ret;
277 }
278 IRQCHIP_DECLARE(ixp42x, "intel,ixp42x-interrupt",
279 		ixp4xx_of_init_irq);
280 IRQCHIP_DECLARE(ixp43x, "intel,ixp43x-interrupt",
281 		ixp4xx_of_init_irq);
282 IRQCHIP_DECLARE(ixp45x, "intel,ixp45x-interrupt",
283 		ixp4xx_of_init_irq);
284 IRQCHIP_DECLARE(ixp46x, "intel,ixp46x-interrupt",
285 		ixp4xx_of_init_irq);
286