Linux-2.6.12-rc2
[linux-2.6/kvm.git] / arch / ppc / syslib / cpc700_pic.c
blob774709807538d593d6bc637040e112ce93fbbadc
1 /*
2 * arch/ppc/syslib/cpc700_pic.c
4 * Interrupt controller support for IBM Spruce
6 * Authors: Mark Greer, Matt Porter, and Johnnie Peters
7 * mgreer@mvista.com
8 * mporter@mvista.com
9 * jpeters@mvista.com
11 * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
12 * the terms of the GNU General Public License version 2. This program
13 * is licensed "as is" without any warranty of any kind, whether express
14 * or implied.
17 #include <linux/stddef.h>
18 #include <linux/init.h>
19 #include <linux/sched.h>
20 #include <linux/signal.h>
21 #include <linux/irq.h>
23 #include <asm/io.h>
24 #include <asm/system.h>
25 #include <asm/irq.h>
27 #include "cpc700.h"
29 static void
30 cpc700_unmask_irq(unsigned int irq)
32 unsigned int tr_bits;
35 * IRQ 31 is largest IRQ supported.
36 * IRQs 17-19 are reserved.
38 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
39 tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
41 if ((tr_bits & (1 << (31 - irq))) == 0) {
42 /* level trigger interrupt, clear bit in status
43 * register */
44 CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
47 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
48 ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
50 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
52 return;
55 static void
56 cpc700_mask_irq(unsigned int irq)
59 * IRQ 31 is largest IRQ supported.
60 * IRQs 17-19 are reserved.
62 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
63 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
64 ppc_cached_irq_mask[0] &=
65 ~CPC700_UIC_IRQ_BIT(irq);
67 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
69 return;
72 static void
73 cpc700_mask_and_ack_irq(unsigned int irq)
75 u_int bit;
78 * IRQ 31 is largest IRQ supported.
79 * IRQs 17-19 are reserved.
81 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
82 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
83 bit = CPC700_UIC_IRQ_BIT(irq);
85 ppc_cached_irq_mask[0] &= ~bit;
86 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
87 CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
89 return;
92 static struct hw_interrupt_type cpc700_pic = {
93 "CPC700 PIC",
94 NULL,
95 NULL,
96 cpc700_unmask_irq,
97 cpc700_mask_irq,
98 cpc700_mask_and_ack_irq,
99 NULL,
100 NULL
103 __init static void
104 cpc700_pic_init_irq(unsigned int irq)
106 unsigned int tmp;
108 /* Set interrupt sense */
109 tmp = CPC700_IN_32(CPC700_UIC_UICTR);
110 if (cpc700_irq_assigns[irq][0] == 0) {
111 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
112 } else {
113 tmp |= CPC700_UIC_IRQ_BIT(irq);
115 CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
117 /* Set interrupt polarity */
118 tmp = CPC700_IN_32(CPC700_UIC_UICPR);
119 if (cpc700_irq_assigns[irq][1]) {
120 tmp |= CPC700_UIC_IRQ_BIT(irq);
121 } else {
122 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
124 CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
126 /* Set interrupt critical */
127 tmp = CPC700_IN_32(CPC700_UIC_UICCR);
128 tmp |= CPC700_UIC_IRQ_BIT(irq);
129 CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
131 return;
134 __init void
135 cpc700_init_IRQ(void)
137 int i;
139 ppc_cached_irq_mask[0] = 0;
140 CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */
141 CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */
142 CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */
143 CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */
144 CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */
145 CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
146 /* IRQ 0 is highest */
148 for (i = 0; i < 17; i++) {
149 irq_desc[i].handler = &cpc700_pic;
150 cpc700_pic_init_irq(i);
153 for (i = 20; i < 32; i++) {
154 irq_desc[i].handler = &cpc700_pic;
155 cpc700_pic_init_irq(i);
158 return;
164 * Find the highest IRQ that generating an interrupt, if any.
167 cpc700_get_irq(struct pt_regs *regs)
169 int irq = 0;
170 u_int irq_status, irq_test = 1;
172 irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
176 if (irq_status & irq_test)
177 break;
178 irq++;
179 irq_test <<= 1;
180 } while (irq < NR_IRQS);
183 if (irq == NR_IRQS)
184 irq = 33;
186 return (31 - irq);