1 /*
2  *
3  * Programmable Interrupt Controller functions for the Freescale MPC52xx.
4  *
5  * Copyright (C) 2006 bplan GmbH
6  *
7  * Based on the code from the 2.4 kernel by
8  * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
9  *
10  * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
11  * Copyright (C) 2003 Montavista Software, Inc
12  *
13  * This file is licensed under the terms of the GNU General Public License
14  * version 2. This program is licensed "as is" without any warranty of any
15  * kind, whether express or implied.
16  *
17  */
18 
19 #undef DEBUG
20 
21 #include <linux/irq.h>
22 #include <linux/of.h>
23 #include <asm/io.h>
24 #include <asm/prom.h>
25 #include <asm/mpc52xx.h>
26 #include "mpc52xx_pic.h"
27 
28 /*
29  *
30 */
31 
32 /* MPC5200 device tree match tables */
33 static struct of_device_id mpc52xx_pic_ids[] __initdata = {
34 	{ .compatible = "fsl,mpc5200-pic", },
35 	{ .compatible = "mpc5200-pic", },
36 	{}
37 };
38 static struct of_device_id mpc52xx_sdma_ids[] __initdata = {
39 	{ .compatible = "fsl,mpc5200-bestcomm", },
40 	{ .compatible = "mpc5200-bestcomm", },
41 	{}
42 };
43 
44 static struct mpc52xx_intr __iomem *intr;
45 static struct mpc52xx_sdma __iomem *sdma;
46 static struct irq_host *mpc52xx_irqhost = NULL;
47 
48 static unsigned char mpc52xx_map_senses[4] = {
49 	IRQ_TYPE_LEVEL_HIGH,
50 	IRQ_TYPE_EDGE_RISING,
51 	IRQ_TYPE_EDGE_FALLING,
52 	IRQ_TYPE_LEVEL_LOW,
53 };
54 
55 /*
56  *
57 */
58 
59 static inline void io_be_setbit(u32 __iomem *addr, int bitno)
60 {
61 	out_be32(addr, in_be32(addr) | (1 << bitno));
62 }
63 
64 static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
65 {
66 	out_be32(addr, in_be32(addr) & ~(1 << bitno));
67 }
68 
69 /*
70  * IRQ[0-3] interrupt irq_chip
71 */
72 
73 static void mpc52xx_extirq_mask(unsigned int virq)
74 {
75 	int irq;
76 	int l2irq;
77 
78 	irq = irq_map[virq].hwirq;
79 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
80 
81 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
82 
83 	io_be_clrbit(&intr->ctrl, 11 - l2irq);
84 }
85 
86 static void mpc52xx_extirq_unmask(unsigned int virq)
87 {
88 	int irq;
89 	int l2irq;
90 
91 	irq = irq_map[virq].hwirq;
92 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
93 
94 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
95 
96 	io_be_setbit(&intr->ctrl, 11 - l2irq);
97 }
98 
99 static void mpc52xx_extirq_ack(unsigned int virq)
100 {
101 	int irq;
102 	int l2irq;
103 
104 	irq = irq_map[virq].hwirq;
105 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
106 
107 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
108 
109 	io_be_setbit(&intr->ctrl, 27-l2irq);
110 }
111 
112 static struct irq_chip mpc52xx_extirq_irqchip = {
113 	.typename = " MPC52xx IRQ[0-3] ",
114 	.mask = mpc52xx_extirq_mask,
115 	.unmask = mpc52xx_extirq_unmask,
116 	.ack = mpc52xx_extirq_ack,
117 };
118 
119 /*
120  * Main interrupt irq_chip
121 */
122 
123 static void mpc52xx_main_mask(unsigned int virq)
124 {
125 	int irq;
126 	int l2irq;
127 
128 	irq = irq_map[virq].hwirq;
129 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
130 
131 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
132 
133 	io_be_setbit(&intr->main_mask, 16 - l2irq);
134 }
135 
136 static void mpc52xx_main_unmask(unsigned int virq)
137 {
138 	int irq;
139 	int l2irq;
140 
141 	irq = irq_map[virq].hwirq;
142 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
143 
144 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
145 
146 	io_be_clrbit(&intr->main_mask, 16 - l2irq);
147 }
148 
149 static struct irq_chip mpc52xx_main_irqchip = {
150 	.typename = "MPC52xx Main",
151 	.mask = mpc52xx_main_mask,
152 	.mask_ack = mpc52xx_main_mask,
153 	.unmask = mpc52xx_main_unmask,
154 };
155 
156 /*
157  * Peripherals interrupt irq_chip
158 */
159 
160 static void mpc52xx_periph_mask(unsigned int virq)
161 {
162 	int irq;
163 	int l2irq;
164 
165 	irq = irq_map[virq].hwirq;
166 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
167 
168 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
169 
170 	io_be_setbit(&intr->per_mask, 31 - l2irq);
171 }
172 
173 static void mpc52xx_periph_unmask(unsigned int virq)
174 {
175 	int irq;
176 	int l2irq;
177 
178 	irq = irq_map[virq].hwirq;
179 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
180 
181 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
182 
183 	io_be_clrbit(&intr->per_mask, 31 - l2irq);
184 }
185 
186 static struct irq_chip mpc52xx_periph_irqchip = {
187 	.typename = "MPC52xx Peripherals",
188 	.mask = mpc52xx_periph_mask,
189 	.mask_ack = mpc52xx_periph_mask,
190 	.unmask = mpc52xx_periph_unmask,
191 };
192 
193 /*
194  * SDMA interrupt irq_chip
195 */
196 
197 static void mpc52xx_sdma_mask(unsigned int virq)
198 {
199 	int irq;
200 	int l2irq;
201 
202 	irq = irq_map[virq].hwirq;
203 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
204 
205 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
206 
207 	io_be_setbit(&sdma->IntMask, l2irq);
208 }
209 
210 static void mpc52xx_sdma_unmask(unsigned int virq)
211 {
212 	int irq;
213 	int l2irq;
214 
215 	irq = irq_map[virq].hwirq;
216 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
217 
218 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
219 
220 	io_be_clrbit(&sdma->IntMask, l2irq);
221 }
222 
223 static void mpc52xx_sdma_ack(unsigned int virq)
224 {
225 	int irq;
226 	int l2irq;
227 
228 	irq = irq_map[virq].hwirq;
229 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
230 
231 	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
232 
233 	out_be32(&sdma->IntPend, 1 << l2irq);
234 }
235 
236 static struct irq_chip mpc52xx_sdma_irqchip = {
237 	.typename = "MPC52xx SDMA",
238 	.mask = mpc52xx_sdma_mask,
239 	.unmask = mpc52xx_sdma_unmask,
240 	.ack = mpc52xx_sdma_ack,
241 };
242 
243 /*
244  * irq_host
245 */
246 
247 static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
248 				 u32 * intspec, unsigned int intsize,
249 				 irq_hw_number_t * out_hwirq,
250 				 unsigned int *out_flags)
251 {
252 	int intrvect_l1;
253 	int intrvect_l2;
254 	int intrvect_type;
255 	int intrvect_linux;
256 
257 	if (intsize != 3)
258 		return -1;
259 
260 	intrvect_l1 = (int)intspec[0];
261 	intrvect_l2 = (int)intspec[1];
262 	intrvect_type = (int)intspec[2];
263 
264 	intrvect_linux =
265 	    (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;
266 	intrvect_linux |=
267 	    (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;
268 
269 	pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
270 		 intrvect_l2);
271 
272 	*out_hwirq = intrvect_linux;
273 	*out_flags = mpc52xx_map_senses[intrvect_type];
274 
275 	return 0;
276 }
277 
278 /*
279  * this function retrieves the correct IRQ type out
280  * of the MPC regs
281  * Only externals IRQs needs this
282 */
283 static int mpc52xx_irqx_gettype(int irq)
284 {
285 	int type;
286 	u32 ctrl_reg;
287 
288 	ctrl_reg = in_be32(&intr->ctrl);
289 	type = (ctrl_reg >> (22 - irq * 2)) & 0x3;
290 
291 	return mpc52xx_map_senses[type];
292 }
293 
294 static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
295 			       irq_hw_number_t irq)
296 {
297 	int l1irq;
298 	int l2irq;
299 	struct irq_chip *good_irqchip;
300 	void *good_handle;
301 	int type;
302 
303 	l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
304 	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
305 
306 	/*
307 	 * Most of ours IRQs will be level low
308 	 * Only external IRQs on some platform may be others
309 	 */
310 	type = IRQ_TYPE_LEVEL_LOW;
311 
312 	switch (l1irq) {
313 	case MPC52xx_IRQ_L1_CRIT:
314 		pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);
315 
316 		BUG_ON(l2irq != 0);
317 
318 		type = mpc52xx_irqx_gettype(l2irq);
319 		good_irqchip = &mpc52xx_extirq_irqchip;
320 		break;
321 
322 	case MPC52xx_IRQ_L1_MAIN:
323 		pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
324 
325 		if ((l2irq >= 1) && (l2irq <= 3)) {
326 			type = mpc52xx_irqx_gettype(l2irq);
327 			good_irqchip = &mpc52xx_extirq_irqchip;
328 		} else {
329 			good_irqchip = &mpc52xx_main_irqchip;
330 		}
331 		break;
332 
333 	case MPC52xx_IRQ_L1_PERP:
334 		pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
335 		good_irqchip = &mpc52xx_periph_irqchip;
336 		break;
337 
338 	case MPC52xx_IRQ_L1_SDMA:
339 		pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
340 		good_irqchip = &mpc52xx_sdma_irqchip;
341 		break;
342 
343 	default:
344 		pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);
345 		printk(KERN_ERR "Unknow IRQ!\n");
346 		return -EINVAL;
347 	}
348 
349 	switch (type) {
350 	case IRQ_TYPE_EDGE_FALLING:
351 	case IRQ_TYPE_EDGE_RISING:
352 		good_handle = handle_edge_irq;
353 		break;
354 	default:
355 		good_handle = handle_level_irq;
356 	}
357 
358 	set_irq_chip_and_handler(virq, good_irqchip, good_handle);
359 
360 	pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
361 		 (int)irq, type);
362 
363 	return 0;
364 }
365 
366 static struct irq_host_ops mpc52xx_irqhost_ops = {
367 	.xlate = mpc52xx_irqhost_xlate,
368 	.map = mpc52xx_irqhost_map,
369 };
370 
371 /*
372  * init (public)
373 */
374 
375 void __init mpc52xx_init_irq(void)
376 {
377 	u32 intr_ctrl;
378 	struct device_node *picnode;
379 	struct device_node *np;
380 
381 	/* Remap the necessary zones */
382 	picnode = of_find_matching_node(NULL, mpc52xx_pic_ids);
383 	intr = of_iomap(picnode, 0);
384 	if (!intr)
385 		panic(__FILE__	": find_and_map failed on 'mpc5200-pic'. "
386 				"Check node !");
387 
388 	np = of_find_matching_node(NULL, mpc52xx_sdma_ids);
389 	sdma = of_iomap(np, 0);
390 	of_node_put(np);
391 	if (!sdma)
392 		panic(__FILE__	": find_and_map failed on 'mpc5200-bestcomm'. "
393 				"Check node !");
394 
395 	/* Disable all interrupt sources. */
396 	out_be32(&sdma->IntPend, 0xffffffff);	/* 1 means clear pending */
397 	out_be32(&sdma->IntMask, 0xffffffff);	/* 1 means disabled */
398 	out_be32(&intr->per_mask, 0x7ffffc00);	/* 1 means disabled */
399 	out_be32(&intr->main_mask, 0x00010fff);	/* 1 means disabled */
400 	intr_ctrl = in_be32(&intr->ctrl);
401 	intr_ctrl &= 0x00ff0000;	/* Keeps IRQ[0-3] config */
402 	intr_ctrl |=	0x0f000000 |	/* clear IRQ 0-3 */
403 			0x00001000 |	/* MEE master external enable */
404 			0x00000000 |	/* 0 means disable IRQ 0-3 */
405 			0x00000001;	/* CEb route critical normally */
406 	out_be32(&intr->ctrl, intr_ctrl);
407 
408 	/* Zero a bunch of the priority settings. */
409 	out_be32(&intr->per_pri1, 0);
410 	out_be32(&intr->per_pri2, 0);
411 	out_be32(&intr->per_pri3, 0);
412 	out_be32(&intr->main_pri1, 0);
413 	out_be32(&intr->main_pri2, 0);
414 
415 	/*
416 	 * As last step, add an irq host to translate the real
417 	 * hw irq information provided by the ofw to linux virq
418 	 */
419 
420 	mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR,
421 	                                 MPC52xx_IRQ_HIGHTESTHWIRQ,
422 	                                 &mpc52xx_irqhost_ops, -1);
423 
424 	if (!mpc52xx_irqhost)
425 		panic(__FILE__ ": Cannot allocate the IRQ host\n");
426 
427 	printk(KERN_INFO "MPC52xx PIC is up and running!\n");
428 }
429 
430 /*
431  * get_irq (public)
432 */
433 unsigned int mpc52xx_get_irq(void)
434 {
435 	u32 status;
436 	int irq = NO_IRQ_IGNORE;
437 
438 	status = in_be32(&intr->enc_status);
439 	if (status & 0x00000400) {	/* critical */
440 		irq = (status >> 8) & 0x3;
441 		if (irq == 2)	/* high priority peripheral */
442 			goto peripheral;
443 		irq |=	(MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &
444 			MPC52xx_IRQ_L1_MASK;
445 	} else if (status & 0x00200000) {	/* main */
446 		irq = (status >> 16) & 0x1f;
447 		if (irq == 4)	/* low priority peripheral */
448 			goto peripheral;
449 		irq |=	(MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &
450 			MPC52xx_IRQ_L1_MASK;
451 	} else if (status & 0x20000000) {	/* peripheral */
452 	      peripheral:
453 		irq = (status >> 24) & 0x1f;
454 		if (irq == 0) {	/* bestcomm */
455 			status = in_be32(&sdma->IntPend);
456 			irq = ffs(status) - 1;
457 			irq |=	(MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &
458 				MPC52xx_IRQ_L1_MASK;
459 		} else {
460 			irq |=	(MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &
461 				MPC52xx_IRQ_L1_MASK;
462 		}
463 	}
464 
465 	pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,
466 		 irq_linear_revmap(mpc52xx_irqhost, irq));
467 
468 	return irq_linear_revmap(mpc52xx_irqhost, irq);
469 }
470