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