xref: /linux/arch/powerpc/platforms/85xx/socrates_fpga_pic.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
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 static void socrates_fpga_pic_cascade(struct irq_desc *desc)
95 {
96 	struct irq_chip *chip = irq_desc_get_chip(desc);
97 	unsigned int irq = irq_desc_get_irq(desc);
98 	unsigned int cascade_irq;
99 
100 	/*
101 	 * See if we actually have an interrupt, call generic handling code if
102 	 * we do.
103 	 */
104 	cascade_irq = socrates_fpga_pic_get_irq(irq);
105 
106 	if (cascade_irq != NO_IRQ)
107 		generic_handle_irq(cascade_irq);
108 	chip->irq_eoi(&desc->irq_data);
109 }
110 
111 static void socrates_fpga_pic_ack(struct irq_data *d)
112 {
113 	unsigned long flags;
114 	unsigned int irq_line, hwirq = irqd_to_hwirq(d);
115 	uint32_t mask;
116 
117 	irq_line = fpga_irqs[hwirq].irq_line;
118 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
119 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
120 		& SOCRATES_FPGA_IRQ_MASK;
121 	mask |= (1 << (hwirq + 16));
122 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
123 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
124 }
125 
126 static void socrates_fpga_pic_mask(struct irq_data *d)
127 {
128 	unsigned long flags;
129 	unsigned int hwirq = irqd_to_hwirq(d);
130 	int irq_line;
131 	u32 mask;
132 
133 	irq_line = fpga_irqs[hwirq].irq_line;
134 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
135 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
136 		& SOCRATES_FPGA_IRQ_MASK;
137 	mask &= ~(1 << hwirq);
138 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
139 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
140 }
141 
142 static void socrates_fpga_pic_mask_ack(struct irq_data *d)
143 {
144 	unsigned long flags;
145 	unsigned int hwirq = irqd_to_hwirq(d);
146 	int irq_line;
147 	u32 mask;
148 
149 	irq_line = fpga_irqs[hwirq].irq_line;
150 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
151 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
152 		& SOCRATES_FPGA_IRQ_MASK;
153 	mask &= ~(1 << hwirq);
154 	mask |= (1 << (hwirq + 16));
155 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
156 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
157 }
158 
159 static void socrates_fpga_pic_unmask(struct irq_data *d)
160 {
161 	unsigned long flags;
162 	unsigned int hwirq = irqd_to_hwirq(d);
163 	int irq_line;
164 	u32 mask;
165 
166 	irq_line = fpga_irqs[hwirq].irq_line;
167 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
168 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
169 		& SOCRATES_FPGA_IRQ_MASK;
170 	mask |= (1 << hwirq);
171 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
172 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
173 }
174 
175 static void socrates_fpga_pic_eoi(struct irq_data *d)
176 {
177 	unsigned long flags;
178 	unsigned int hwirq = irqd_to_hwirq(d);
179 	int irq_line;
180 	u32 mask;
181 
182 	irq_line = fpga_irqs[hwirq].irq_line;
183 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
184 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
185 		& SOCRATES_FPGA_IRQ_MASK;
186 	mask |= (1 << (hwirq + 16));
187 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
188 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
189 }
190 
191 static int socrates_fpga_pic_set_type(struct irq_data *d,
192 		unsigned int flow_type)
193 {
194 	unsigned long flags;
195 	unsigned int hwirq = irqd_to_hwirq(d);
196 	int polarity;
197 	u32 mask;
198 
199 	if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
200 		return -EINVAL;
201 
202 	switch (flow_type & IRQ_TYPE_SENSE_MASK) {
203 	case IRQ_TYPE_LEVEL_HIGH:
204 		polarity = 1;
205 		break;
206 	case IRQ_TYPE_LEVEL_LOW:
207 		polarity = 0;
208 		break;
209 	default:
210 		return -EINVAL;
211 	}
212 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
213 	mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
214 	if (polarity)
215 		mask |= (1 << hwirq);
216 	else
217 		mask &= ~(1 << hwirq);
218 	socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
219 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
220 	return 0;
221 }
222 
223 static struct irq_chip socrates_fpga_pic_chip = {
224 	.name		= "FPGA-PIC",
225 	.irq_ack	= socrates_fpga_pic_ack,
226 	.irq_mask	= socrates_fpga_pic_mask,
227 	.irq_mask_ack	= socrates_fpga_pic_mask_ack,
228 	.irq_unmask	= socrates_fpga_pic_unmask,
229 	.irq_eoi	= socrates_fpga_pic_eoi,
230 	.irq_set_type	= socrates_fpga_pic_set_type,
231 };
232 
233 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
234 		irq_hw_number_t hwirq)
235 {
236 	/* All interrupts are LEVEL sensitive */
237 	irq_set_status_flags(virq, IRQ_LEVEL);
238 	irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
239 				 handle_fasteoi_irq);
240 
241 	return 0;
242 }
243 
244 static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
245 		struct device_node *ct,	const u32 *intspec, unsigned int intsize,
246 		irq_hw_number_t *out_hwirq, unsigned int *out_flags)
247 {
248 	struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
249 
250 	*out_hwirq = intspec[0];
251 	if  (fpga_irq->type == IRQ_TYPE_NONE) {
252 		/* type is configurable */
253 		if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
254 		    intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
255 			pr_warning("FPGA PIC: invalid irq type, "
256 				   "setting default active low\n");
257 			*out_flags = IRQ_TYPE_LEVEL_LOW;
258 		} else {
259 			*out_flags = intspec[1];
260 		}
261 	} else {
262 		/* type is fixed */
263 		*out_flags = fpga_irq->type;
264 	}
265 
266 	/* Use specified interrupt routing */
267 	if (intspec[2] <= 2)
268 		fpga_irq->irq_line = intspec[2];
269 	else
270 		pr_warning("FPGA PIC: invalid irq routing\n");
271 
272 	return 0;
273 }
274 
275 static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
276 	.map    = socrates_fpga_pic_host_map,
277 	.xlate  = socrates_fpga_pic_host_xlate,
278 };
279 
280 void socrates_fpga_pic_init(struct device_node *pic)
281 {
282 	unsigned long flags;
283 	int i;
284 
285 	/* Setup an irq_domain structure */
286 	socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
287 		    SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
288 	if (socrates_fpga_pic_irq_host == NULL) {
289 		pr_err("FPGA PIC: Unable to allocate host\n");
290 		return;
291 	}
292 
293 	for (i = 0; i < 3; i++) {
294 		socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
295 		if (socrates_fpga_irqs[i] == NO_IRQ) {
296 			pr_warning("FPGA PIC: can't get irq%d.\n", i);
297 			continue;
298 		}
299 		irq_set_chained_handler(socrates_fpga_irqs[i],
300 					socrates_fpga_pic_cascade);
301 	}
302 
303 	socrates_fpga_pic_iobase = of_iomap(pic, 0);
304 
305 	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
306 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
307 			SOCRATES_FPGA_IRQ_MASK << 16);
308 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
309 			SOCRATES_FPGA_IRQ_MASK << 16);
310 	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
311 			SOCRATES_FPGA_IRQ_MASK << 16);
312 	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
313 
314 	pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
315 }
316