xref: /linux/arch/powerpc/platforms/85xx/socrates_fpga_pic.c (revision 9b9c280b9af2aa851d83e7d0b79f36a3d869d745)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  Copyright (C) 2008 Ilya Yanok, Emcraft Systems
4  */
5 
6 #include <linux/irq.h>
7 #include <linux/of_address.h>
8 #include <linux/of_irq.h>
9 #include <linux/io.h>
10 
11 #include "socrates_fpga_pic.h"
12 
13 /*
14  * The FPGA supports 9 interrupt sources, which can be routed to 3
15  * interrupt request lines of the MPIC. The line to be used can be
16  * specified through the third cell of FDT property  "interrupts".
17  */
18 
19 #define SOCRATES_FPGA_NUM_IRQS	9
20 
21 #define FPGA_PIC_IRQCFG		(0x0)
22 #define FPGA_PIC_IRQMASK(n)	(0x4 + 0x4 * (n))
23 
24 #define SOCRATES_FPGA_IRQ_MASK	((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
25 
26 struct socrates_fpga_irq_info {
27 	unsigned int irq_line;
28 	int type;
29 };
30 
31 /*
32  * Interrupt routing and type table
33  *
34  * IRQ_TYPE_NONE means the interrupt type is configurable,
35  * otherwise it's fixed to the specified value.
36  */
37 static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
38 	[0] = {0, IRQ_TYPE_NONE},
39 	[1] = {0, IRQ_TYPE_LEVEL_HIGH},
40 	[2] = {0, IRQ_TYPE_LEVEL_LOW},
41 	[3] = {0, IRQ_TYPE_NONE},
42 	[4] = {0, IRQ_TYPE_NONE},
43 	[5] = {0, IRQ_TYPE_NONE},
44 	[6] = {0, IRQ_TYPE_NONE},
45 	[7] = {0, IRQ_TYPE_NONE},
46 	[8] = {0, IRQ_TYPE_LEVEL_HIGH},
47 };
48 
49 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
50 
51 static void __iomem *socrates_fpga_pic_iobase;
52 static struct irq_domain *socrates_fpga_pic_irq_host;
53 static unsigned int socrates_fpga_irqs[3];
54 
55 static inline uint32_t socrates_fpga_pic_read(int reg)
56 {
57 	return in_be32(socrates_fpga_pic_iobase + reg);
58 }
59 
60 static inline void socrates_fpga_pic_write(int reg, uint32_t val)
61 {
62 	out_be32(socrates_fpga_pic_iobase + reg, val);
63 }
64 
65 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
66 {
67 	uint32_t cause;
68 	unsigned long flags;
69 	int i;
70 
71 	/* Check irq line routed to the MPIC */
72 	for (i = 0; i < 3; i++) {
73 		if (irq == socrates_fpga_irqs[i])
74 			break;
75 	}
76 	if (i == 3)
77 		return 0;
78 
79 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
80 	cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
81 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
82 	for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
83 		if (cause >> (i + 16))
84 			break;
85 	}
86 	return irq_linear_revmap(socrates_fpga_pic_irq_host,
87 			(irq_hw_number_t)i);
88 }
89 
90 static void socrates_fpga_pic_cascade(struct irq_desc *desc)
91 {
92 	struct irq_chip *chip = irq_desc_get_chip(desc);
93 	unsigned int irq = irq_desc_get_irq(desc);
94 	unsigned int cascade_irq;
95 
96 	/*
97 	 * See if we actually have an interrupt, call generic handling code if
98 	 * we do.
99 	 */
100 	cascade_irq = socrates_fpga_pic_get_irq(irq);
101 
102 	if (cascade_irq)
103 		generic_handle_irq(cascade_irq);
104 	chip->irq_eoi(&desc->irq_data);
105 }
106 
107 static void socrates_fpga_pic_ack(struct irq_data *d)
108 {
109 	unsigned long flags;
110 	unsigned int irq_line, hwirq = irqd_to_hwirq(d);
111 	uint32_t mask;
112 
113 	irq_line = fpga_irqs[hwirq].irq_line;
114 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
115 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
116 		& SOCRATES_FPGA_IRQ_MASK;
117 	mask |= (1 << (hwirq + 16));
118 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
119 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
120 }
121 
122 static void socrates_fpga_pic_mask(struct irq_data *d)
123 {
124 	unsigned long flags;
125 	unsigned int hwirq = irqd_to_hwirq(d);
126 	int irq_line;
127 	u32 mask;
128 
129 	irq_line = fpga_irqs[hwirq].irq_line;
130 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
131 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
132 		& SOCRATES_FPGA_IRQ_MASK;
133 	mask &= ~(1 << hwirq);
134 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
135 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
136 }
137 
138 static void socrates_fpga_pic_mask_ack(struct irq_data *d)
139 {
140 	unsigned long flags;
141 	unsigned int hwirq = irqd_to_hwirq(d);
142 	int irq_line;
143 	u32 mask;
144 
145 	irq_line = fpga_irqs[hwirq].irq_line;
146 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
147 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
148 		& SOCRATES_FPGA_IRQ_MASK;
149 	mask &= ~(1 << hwirq);
150 	mask |= (1 << (hwirq + 16));
151 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
152 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
153 }
154 
155 static void socrates_fpga_pic_unmask(struct irq_data *d)
156 {
157 	unsigned long flags;
158 	unsigned int hwirq = irqd_to_hwirq(d);
159 	int irq_line;
160 	u32 mask;
161 
162 	irq_line = fpga_irqs[hwirq].irq_line;
163 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
164 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
165 		& SOCRATES_FPGA_IRQ_MASK;
166 	mask |= (1 << hwirq);
167 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
168 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
169 }
170 
171 static void socrates_fpga_pic_eoi(struct irq_data *d)
172 {
173 	unsigned long flags;
174 	unsigned int hwirq = irqd_to_hwirq(d);
175 	int irq_line;
176 	u32 mask;
177 
178 	irq_line = fpga_irqs[hwirq].irq_line;
179 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
180 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
181 		& SOCRATES_FPGA_IRQ_MASK;
182 	mask |= (1 << (hwirq + 16));
183 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
184 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
185 }
186 
187 static int socrates_fpga_pic_set_type(struct irq_data *d,
188 		unsigned int flow_type)
189 {
190 	unsigned long flags;
191 	unsigned int hwirq = irqd_to_hwirq(d);
192 	int polarity;
193 	u32 mask;
194 
195 	if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
196 		return -EINVAL;
197 
198 	switch (flow_type & IRQ_TYPE_SENSE_MASK) {
199 	case IRQ_TYPE_LEVEL_HIGH:
200 		polarity = 1;
201 		break;
202 	case IRQ_TYPE_LEVEL_LOW:
203 		polarity = 0;
204 		break;
205 	default:
206 		return -EINVAL;
207 	}
208 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
209 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
210 	if (polarity)
211 		mask |= (1 << hwirq);
212 	else
213 		mask &= ~(1 << hwirq);
214 	socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
215 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
216 	return 0;
217 }
218 
219 static struct irq_chip socrates_fpga_pic_chip = {
220 	.name		= "FPGA-PIC",
221 	.irq_ack	= socrates_fpga_pic_ack,
222 	.irq_mask	= socrates_fpga_pic_mask,
223 	.irq_mask_ack	= socrates_fpga_pic_mask_ack,
224 	.irq_unmask	= socrates_fpga_pic_unmask,
225 	.irq_eoi	= socrates_fpga_pic_eoi,
226 	.irq_set_type	= socrates_fpga_pic_set_type,
227 };
228 
229 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
230 		irq_hw_number_t hwirq)
231 {
232 	/* All interrupts are LEVEL sensitive */
233 	irq_set_status_flags(virq, IRQ_LEVEL);
234 	irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
235 				 handle_fasteoi_irq);
236 
237 	return 0;
238 }
239 
240 static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
241 		struct device_node *ct,	const u32 *intspec, unsigned int intsize,
242 		irq_hw_number_t *out_hwirq, unsigned int *out_flags)
243 {
244 	struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
245 
246 	*out_hwirq = intspec[0];
247 	if  (fpga_irq->type == IRQ_TYPE_NONE) {
248 		/* type is configurable */
249 		if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
250 		    intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
251 			pr_warn("FPGA PIC: invalid irq type, setting default active low\n");
252 			*out_flags = IRQ_TYPE_LEVEL_LOW;
253 		} else {
254 			*out_flags = intspec[1];
255 		}
256 	} else {
257 		/* type is fixed */
258 		*out_flags = fpga_irq->type;
259 	}
260 
261 	/* Use specified interrupt routing */
262 	if (intspec[2] <= 2)
263 		fpga_irq->irq_line = intspec[2];
264 	else
265 		pr_warn("FPGA PIC: invalid irq routing\n");
266 
267 	return 0;
268 }
269 
270 static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
271 	.map    = socrates_fpga_pic_host_map,
272 	.xlate  = socrates_fpga_pic_host_xlate,
273 };
274 
275 void __init socrates_fpga_pic_init(struct device_node *pic)
276 {
277 	unsigned long flags;
278 	int i;
279 
280 	/* Setup an irq_domain structure */
281 	socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
282 		    SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
283 	if (socrates_fpga_pic_irq_host == NULL) {
284 		pr_err("FPGA PIC: Unable to allocate host\n");
285 		return;
286 	}
287 
288 	for (i = 0; i < 3; i++) {
289 		socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
290 		if (!socrates_fpga_irqs[i]) {
291 			pr_warn("FPGA PIC: can't get irq%d\n", i);
292 			continue;
293 		}
294 		irq_set_chained_handler(socrates_fpga_irqs[i],
295 					socrates_fpga_pic_cascade);
296 	}
297 
298 	socrates_fpga_pic_iobase = of_iomap(pic, 0);
299 
300 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
301 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
302 			SOCRATES_FPGA_IRQ_MASK << 16);
303 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
304 			SOCRATES_FPGA_IRQ_MASK << 16);
305 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
306 			SOCRATES_FPGA_IRQ_MASK << 16);
307 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
308 
309 	pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
310 }
311