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