blob: 75fe8eb1069359c3d52cbc3445d0ebd5b2658f26 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/ppc/syslib/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/system.h>
25#include <asm/irq.h>
26
27#include "cpc700.h"
28
29static void
30cpc700_unmask_irq(unsigned int irq)
31{
32 unsigned int tr_bits;
33
34 /*
35 * IRQ 31 is largest IRQ supported.
36 * IRQs 17-19 are reserved.
37 */
38 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
39 tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
40
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));
45 }
46
47 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
48 ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
49
50 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
51 }
52 return;
53}
54
55static void
56cpc700_mask_irq(unsigned int irq)
57{
58 /*
59 * IRQ 31 is largest IRQ supported.
60 * IRQs 17-19 are reserved.
61 */
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);
66
67 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
68 }
69 return;
70}
71
72static void
73cpc700_mask_and_ack_irq(unsigned int irq)
74{
75 u_int bit;
76
77 /*
78 * IRQ 31 is largest IRQ supported.
79 * IRQs 17-19 are reserved.
80 */
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);
84
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 */
88 }
89 return;
90}
91
92static struct hw_interrupt_type cpc700_pic = {
Thomas Gleixner2830e212005-09-10 00:26:40 -070093 .typename = "CPC700 PIC",
94 .enable = cpc700_unmask_irq,
95 .disable = cpc700_mask_irq,
96 .ack = cpc700_mask_and_ack_irq,
Linus Torvalds1da177e2005-04-16 15:20:36 -070097};
98
99__init static void
100cpc700_pic_init_irq(unsigned int irq)
101{
102 unsigned int tmp;
103
104 /* Set interrupt sense */
105 tmp = CPC700_IN_32(CPC700_UIC_UICTR);
106 if (cpc700_irq_assigns[irq][0] == 0) {
107 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
108 } else {
109 tmp |= CPC700_UIC_IRQ_BIT(irq);
110 }
111 CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
112
113 /* Set interrupt polarity */
114 tmp = CPC700_IN_32(CPC700_UIC_UICPR);
115 if (cpc700_irq_assigns[irq][1]) {
116 tmp |= CPC700_UIC_IRQ_BIT(irq);
117 } else {
118 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
119 }
120 CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
121
122 /* Set interrupt critical */
123 tmp = CPC700_IN_32(CPC700_UIC_UICCR);
124 tmp |= CPC700_UIC_IRQ_BIT(irq);
125 CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
126
127 return;
128}
129
130__init void
131cpc700_init_IRQ(void)
132{
133 int i;
134
135 ppc_cached_irq_mask[0] = 0;
136 CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */
137 CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */
138 CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */
139 CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */
140 CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */
141 CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
142 /* IRQ 0 is highest */
143
144 for (i = 0; i < 17; i++) {
145 irq_desc[i].handler = &cpc700_pic;
146 cpc700_pic_init_irq(i);
147 }
148
149 for (i = 20; i < 32; i++) {
150 irq_desc[i].handler = &cpc700_pic;
151 cpc700_pic_init_irq(i);
152 }
153
154 return;
155}
156
157
158
159/*
160 * Find the highest IRQ that generating an interrupt, if any.
161 */
162int
163cpc700_get_irq(struct pt_regs *regs)
164{
165 int irq = 0;
166 u_int irq_status, irq_test = 1;
167
168 irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
169
170 do
171 {
172 if (irq_status & irq_test)
173 break;
174 irq++;
175 irq_test <<= 1;
176 } while (irq < NR_IRQS);
177
178
179 if (irq == NR_IRQS)
180 irq = 33;
181
182 return (31 - irq);
183}