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