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