1 /*
2 * arch/ppc/platforms/cpc700_pic.c
3 *
4 * Interrupt controller support for IBM Spruce
5 *
6 * Authors: Mark Greer, Matt Porter, and Johnnie Peters
7 * mgreer@mvista.com
8 * mporter@mvista.com
9 * jpeters@mvista.com
10 *
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.
15 */
16
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>
22
23 #include <asm/io.h>
24 #include <asm/processor.h>
25 #include <asm/system.h>
26 #include <asm/irq.h>
27
28 #include "cpc700.h"
29
30 static void
cpc700_unmask_irq(unsigned int irq)31 cpc700_unmask_irq(unsigned int irq)
32 {
33 unsigned int tr_bits;
34
35 /*
36 * IRQ 31 is largest IRQ supported.
37 * IRQs 17-19 are reserved.
38 */
39 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
40 tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
41
42 if ((tr_bits & (1 << (31 - irq))) == 0) {
43 /* level trigger interrupt, clear bit in status
44 * register */
45 CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
46 }
47
48 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
49 ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
50
51 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
52 }
53 return;
54 }
55
56 static void
cpc700_mask_irq(unsigned int irq)57 cpc700_mask_irq(unsigned int irq)
58 {
59 /*
60 * IRQ 31 is largest IRQ supported.
61 * IRQs 17-19 are reserved.
62 */
63 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
64 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
65 ppc_cached_irq_mask[0] &=
66 ~CPC700_UIC_IRQ_BIT(irq);
67
68 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
69 }
70 return;
71 }
72
73 static void
cpc700_mask_and_ack_irq(unsigned int irq)74 cpc700_mask_and_ack_irq(unsigned int irq)
75 {
76 u_int bit;
77
78 /*
79 * IRQ 31 is largest IRQ supported.
80 * IRQs 17-19 are reserved.
81 */
82 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
83 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
84 bit = CPC700_UIC_IRQ_BIT(irq);
85
86 ppc_cached_irq_mask[0] &= ~bit;
87 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
88 CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
89 }
90 return;
91 }
92
93 static struct hw_interrupt_type cpc700_pic = {
94 "CPC700 PIC",
95 NULL,
96 NULL,
97 cpc700_unmask_irq,
98 cpc700_mask_irq,
99 cpc700_mask_and_ack_irq,
100 NULL,
101 NULL
102 };
103
104 __init static void
cpc700_pic_init_irq(unsigned int irq)105 cpc700_pic_init_irq(unsigned int irq)
106 {
107 unsigned int tmp;
108
109 /* Set interrupt sense */
110 tmp = CPC700_IN_32(CPC700_UIC_UICTR);
111 if (cpc700_irq_assigns[irq][0] == 0) {
112 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
113 } else {
114 tmp |= CPC700_UIC_IRQ_BIT(irq);
115 }
116 CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
117
118 /* Set interrupt polarity */
119 tmp = CPC700_IN_32(CPC700_UIC_UICPR);
120 if (cpc700_irq_assigns[irq][1]) {
121 tmp |= CPC700_UIC_IRQ_BIT(irq);
122 } else {
123 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
124 }
125 CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
126
127 /* Set interrupt critical */
128 tmp = CPC700_IN_32(CPC700_UIC_UICCR);
129 tmp |= CPC700_UIC_IRQ_BIT(irq);
130 CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
131
132 return;
133 }
134
135 __init void
cpc700_init_IRQ(void)136 cpc700_init_IRQ(void)
137 {
138 int i;
139
140 ppc_cached_irq_mask[0] = 0;
141 CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */
142 CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */
143 CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */
144 CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */
145 CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */
146 CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
147 /* IRQ 0 is highest */
148
149 for (i = 0; i < 17; i++) {
150 irq_desc[i].handler = &cpc700_pic;
151 cpc700_pic_init_irq(i);
152 }
153
154 for (i = 20; i < 32; i++) {
155 irq_desc[i].handler = &cpc700_pic;
156 cpc700_pic_init_irq(i);
157 }
158
159 return;
160 }
161
162
163
164 /*
165 * Find the highest IRQ that generating an interrupt, if any.
166 */
167 int
cpc700_get_irq(struct pt_regs * regs)168 cpc700_get_irq(struct pt_regs *regs)
169 {
170 int irq = 0;
171 u_int irq_status, irq_test = 1;
172
173 irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
174
175 do
176 {
177 if (irq_status & irq_test)
178 break;
179 irq++;
180 irq_test <<= 1;
181 } while (irq < NR_IRQS);
182
183
184 if (irq == NR_IRQS)
185 irq = 33;
186
187 return (31 - irq);
188 }
189