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