2 * include/asm-ppc/ipic.c
4 * IPIC routines implementations.
6 * Copyright 2005 Freescale Semiconductor, Inc.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/errno.h>
16 #include <linux/reboot.h>
17 #include <linux/slab.h>
18 #include <linux/stddef.h>
19 #include <linux/sched.h>
20 #include <linux/signal.h>
21 #include <linux/sysdev.h>
25 #include <asm/mpc83xx.h>
29 static struct ipic p_ipic;
30 static struct ipic * primary_ipic;
32 static struct ipic_info ipic_info[] = {
37 .force = IPIC_SIFCR_H,
45 .force = IPIC_SIFCR_H,
53 .force = IPIC_SIFCR_H,
61 .force = IPIC_SIFCR_H,
69 .force = IPIC_SIFCR_H,
77 .force = IPIC_SIFCR_H,
100 .prio = IPIC_SMPRR_A,
108 .prio = IPIC_SMPRR_B,
116 .prio = IPIC_SMPRR_B,
124 .prio = IPIC_SMPRR_B,
132 .prio = IPIC_SMPRR_B,
138 .pend = IPIC_SIPNR_H,
139 .mask = IPIC_SIMSR_H,
140 .prio = IPIC_SIPRR_A,
141 .force = IPIC_SIFCR_H,
146 .pend = IPIC_SIPNR_H,
147 .mask = IPIC_SIMSR_H,
148 .prio = IPIC_SIPRR_A,
149 .force = IPIC_SIFCR_H,
154 .pend = IPIC_SIPNR_H,
155 .mask = IPIC_SIMSR_H,
156 .prio = IPIC_SIPRR_A,
157 .force = IPIC_SIFCR_H,
162 .pend = IPIC_SIPNR_H,
163 .mask = IPIC_SIMSR_H,
164 .prio = IPIC_SIPRR_A,
165 .force = IPIC_SIFCR_H,
170 .pend = IPIC_SIPNR_H,
171 .mask = IPIC_SIMSR_H,
172 .prio = IPIC_SIPRR_A,
173 .force = IPIC_SIFCR_H,
178 .pend = IPIC_SIPNR_H,
179 .mask = IPIC_SIMSR_H,
180 .prio = IPIC_SIPRR_A,
181 .force = IPIC_SIFCR_H,
186 .pend = IPIC_SIPNR_H,
187 .mask = IPIC_SIMSR_H,
188 .prio = IPIC_SIPRR_A,
189 .force = IPIC_SIFCR_H,
194 .pend = IPIC_SIPNR_H,
195 .mask = IPIC_SIMSR_H,
196 .prio = IPIC_SIPRR_A,
197 .force = IPIC_SIFCR_H,
204 .prio = IPIC_SMPRR_A,
210 .pend = IPIC_SIPNR_H,
211 .mask = IPIC_SIMSR_L,
212 .prio = IPIC_SMPRR_A,
213 .force = IPIC_SIFCR_L,
218 .pend = IPIC_SIPNR_H,
219 .mask = IPIC_SIMSR_L,
220 .prio = IPIC_SMPRR_A,
221 .force = IPIC_SIFCR_L,
226 .pend = IPIC_SIPNR_H,
227 .mask = IPIC_SIMSR_L,
228 .prio = IPIC_SMPRR_A,
229 .force = IPIC_SIFCR_L,
234 .pend = IPIC_SIPNR_H,
235 .mask = IPIC_SIMSR_L,
236 .prio = IPIC_SMPRR_A,
237 .force = IPIC_SIFCR_L,
242 .pend = IPIC_SIPNR_H,
243 .mask = IPIC_SIMSR_L,
244 .prio = IPIC_SMPRR_B,
245 .force = IPIC_SIFCR_L,
250 .pend = IPIC_SIPNR_H,
251 .mask = IPIC_SIMSR_L,
252 .prio = IPIC_SMPRR_B,
253 .force = IPIC_SIFCR_L,
258 .pend = IPIC_SIPNR_H,
259 .mask = IPIC_SIMSR_L,
260 .prio = IPIC_SMPRR_B,
261 .force = IPIC_SIFCR_L,
266 .pend = IPIC_SIPNR_H,
267 .mask = IPIC_SIMSR_L,
268 .prio = IPIC_SMPRR_B,
269 .force = IPIC_SIFCR_L,
274 .pend = IPIC_SIPNR_H,
275 .mask = IPIC_SIMSR_L,
277 .force = IPIC_SIFCR_L,
281 .pend = IPIC_SIPNR_H,
282 .mask = IPIC_SIMSR_L,
284 .force = IPIC_SIFCR_L,
288 .pend = IPIC_SIPNR_H,
289 .mask = IPIC_SIMSR_L,
291 .force = IPIC_SIFCR_L,
295 .pend = IPIC_SIPNR_H,
296 .mask = IPIC_SIMSR_L,
298 .force = IPIC_SIFCR_L,
302 .pend = IPIC_SIPNR_H,
303 .mask = IPIC_SIMSR_L,
305 .force = IPIC_SIFCR_L,
309 .pend = IPIC_SIPNR_H,
310 .mask = IPIC_SIMSR_L,
312 .force = IPIC_SIFCR_L,
316 .pend = IPIC_SIPNR_H,
317 .mask = IPIC_SIMSR_L,
319 .force = IPIC_SIFCR_L,
323 .pend = IPIC_SIPNR_H,
324 .mask = IPIC_SIMSR_L,
326 .force = IPIC_SIFCR_L,
330 .pend = IPIC_SIPNR_H,
331 .mask = IPIC_SIMSR_L,
333 .force = IPIC_SIFCR_L,
337 .pend = IPIC_SIPNR_H,
338 .mask = IPIC_SIMSR_L,
340 .force = IPIC_SIFCR_L,
344 .pend = IPIC_SIPNR_H,
345 .mask = IPIC_SIMSR_L,
347 .force = IPIC_SIFCR_L,
351 .pend = IPIC_SIPNR_H,
352 .mask = IPIC_SIMSR_L,
354 .force = IPIC_SIFCR_L,
358 .pend = IPIC_SIPNR_H,
359 .mask = IPIC_SIMSR_L,
361 .force = IPIC_SIFCR_L,
366 static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg)
368 return in_be32(base + (reg >> 2));
371 static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value)
373 out_be32(base + (reg >> 2), value);
376 static inline struct ipic * ipic_from_irq(unsigned int irq)
381 static void ipic_enable_irq(unsigned int irq)
383 struct ipic *ipic = ipic_from_irq(irq);
384 unsigned int src = irq - ipic->irq_offset;
387 temp = ipic_read(ipic->regs, ipic_info[src].mask);
388 temp |= (1 << (31 - ipic_info[src].bit));
389 ipic_write(ipic->regs, ipic_info[src].mask, temp);
392 static void ipic_disable_irq(unsigned int irq)
394 struct ipic *ipic = ipic_from_irq(irq);
395 unsigned int src = irq - ipic->irq_offset;
398 temp = ipic_read(ipic->regs, ipic_info[src].mask);
399 temp &= ~(1 << (31 - ipic_info[src].bit));
400 ipic_write(ipic->regs, ipic_info[src].mask, temp);
403 static void ipic_disable_irq_and_ack(unsigned int irq)
405 struct ipic *ipic = ipic_from_irq(irq);
406 unsigned int src = irq - ipic->irq_offset;
409 ipic_disable_irq(irq);
411 temp = ipic_read(ipic->regs, ipic_info[src].pend);
412 temp |= (1 << (31 - ipic_info[src].bit));
413 ipic_write(ipic->regs, ipic_info[src].pend, temp);
416 static void ipic_end_irq(unsigned int irq)
418 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
419 ipic_enable_irq(irq);
422 struct hw_interrupt_type ipic = {
423 .typename = " IPIC ",
424 .enable = ipic_enable_irq,
425 .disable = ipic_disable_irq,
426 .ack = ipic_disable_irq_and_ack,
430 void __init ipic_init(phys_addr_t phys_addr,
432 unsigned int irq_offset,
433 unsigned char *senses,
434 unsigned int senses_count)
438 primary_ipic = &p_ipic;
439 primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE);
441 primary_ipic->irq_offset = irq_offset;
443 ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0);
445 /* default priority scheme is grouped. If spread mode is required
446 * configure SICFR accordingly */
447 if (flags & IPIC_SPREADMODE_GRP_A)
449 if (flags & IPIC_SPREADMODE_GRP_D)
451 if (flags & IPIC_SPREADMODE_MIX_A)
453 if (flags & IPIC_SPREADMODE_MIX_B)
456 ipic_write(primary_ipic->regs, IPIC_SICNR, temp);
458 /* handle MCP route */
460 if (flags & IPIC_DISABLE_MCP_OUT)
462 ipic_write(primary_ipic->regs, IPIC_SERCR, temp);
464 /* handle routing of IRQ0 to MCP */
465 temp = ipic_read(primary_ipic->regs, IPIC_SEMSR);
467 if (flags & IPIC_IRQ0_MCP)
470 temp &= ~SEMSR_SIRQ0;
472 ipic_write(primary_ipic->regs, IPIC_SEMSR, temp);
474 for (i = 0 ; i < NR_IPIC_INTS ; i++) {
475 irq_desc[i+irq_offset].chip = &ipic;
476 irq_desc[i+irq_offset].status = IRQ_LEVEL;
480 for (i = 0 ; i < senses_count ; i++) {
481 if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) {
482 temp |= 1 << (15 - i);
484 irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0;
486 irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0;
489 ipic_write(primary_ipic->regs, IPIC_SECNR, temp);
491 printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS,
492 senses_count, primary_ipic->regs);
495 int ipic_set_priority(unsigned int irq, unsigned int priority)
497 struct ipic *ipic = ipic_from_irq(irq);
498 unsigned int src = irq - ipic->irq_offset;
505 if (ipic_info[src].prio == 0)
508 temp = ipic_read(ipic->regs, ipic_info[src].prio);
511 temp &= ~(0x7 << (20 + (3 - priority) * 3));
512 temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3);
514 temp &= ~(0x7 << (4 + (7 - priority) * 3));
515 temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3);
518 ipic_write(ipic->regs, ipic_info[src].prio, temp);
523 void ipic_set_highest_priority(unsigned int irq)
525 struct ipic *ipic = ipic_from_irq(irq);
526 unsigned int src = irq - ipic->irq_offset;
529 temp = ipic_read(ipic->regs, IPIC_SICFR);
531 /* clear and set HPI */
533 temp |= (src & 0x7f) << 24;
535 ipic_write(ipic->regs, IPIC_SICFR, temp);
538 void ipic_set_default_priority(void)
540 ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0);
541 ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1);
542 ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2);
543 ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3);
544 ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4);
545 ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5);
546 ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6);
547 ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7);
549 ipic_set_priority(MPC83xx_IRQ_UART1, 0);
550 ipic_set_priority(MPC83xx_IRQ_UART2, 1);
551 ipic_set_priority(MPC83xx_IRQ_SEC2, 2);
552 ipic_set_priority(MPC83xx_IRQ_IIC1, 5);
553 ipic_set_priority(MPC83xx_IRQ_IIC2, 6);
554 ipic_set_priority(MPC83xx_IRQ_SPI, 7);
555 ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0);
556 ipic_set_priority(MPC83xx_IRQ_PIT, 1);
557 ipic_set_priority(MPC83xx_IRQ_PCI1, 2);
558 ipic_set_priority(MPC83xx_IRQ_PCI2, 3);
559 ipic_set_priority(MPC83xx_IRQ_EXT0, 4);
560 ipic_set_priority(MPC83xx_IRQ_EXT1, 5);
561 ipic_set_priority(MPC83xx_IRQ_EXT2, 6);
562 ipic_set_priority(MPC83xx_IRQ_EXT3, 7);
563 ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0);
564 ipic_set_priority(MPC83xx_IRQ_MU, 1);
565 ipic_set_priority(MPC83xx_IRQ_SBA, 2);
566 ipic_set_priority(MPC83xx_IRQ_DMA, 3);
567 ipic_set_priority(MPC83xx_IRQ_EXT4, 4);
568 ipic_set_priority(MPC83xx_IRQ_EXT5, 5);
569 ipic_set_priority(MPC83xx_IRQ_EXT6, 6);
570 ipic_set_priority(MPC83xx_IRQ_EXT7, 7);
573 void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq)
575 struct ipic *ipic = primary_ipic;
578 temp = ipic_read(ipic->regs, IPIC_SERMR);
579 temp |= (1 << (31 - mcp_irq));
580 ipic_write(ipic->regs, IPIC_SERMR, temp);
583 void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq)
585 struct ipic *ipic = primary_ipic;
588 temp = ipic_read(ipic->regs, IPIC_SERMR);
589 temp &= (1 << (31 - mcp_irq));
590 ipic_write(ipic->regs, IPIC_SERMR, temp);
593 u32 ipic_get_mcp_status(void)
595 return ipic_read(primary_ipic->regs, IPIC_SERMR);
598 void ipic_clear_mcp_status(u32 mask)
600 ipic_write(primary_ipic->regs, IPIC_SERMR, mask);
603 /* Return an interrupt vector or -1 if no interrupt is pending. */
604 int ipic_get_irq(struct pt_regs *regs)
608 irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f;
610 if (irq == 0) /* 0 --> no irq is pending */
616 static struct sysdev_class ipic_sysclass = {
617 set_kset_name("ipic"),
620 static struct sys_device device_ipic = {
622 .cls = &ipic_sysclass,
625 static int __init init_ipic_sysfs(void)
629 if (!primary_ipic->regs)
631 printk(KERN_DEBUG "Registering ipic with sysfs...\n");
633 rc = sysdev_class_register(&ipic_sysclass);
635 printk(KERN_ERR "Failed registering ipic sys class\n");
638 rc = sysdev_register(&device_ipic);
640 printk(KERN_ERR "Failed registering ipic sys device\n");
646 subsys_initcall(init_ipic_sysfs);