blob: d48e8f45c05058d4412843faa6967d7d58234cc3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * Interrupt controller support for IBM Spruce
3 *
4 * Authors: Mark Greer, Matt Porter, and Johnnie Peters
5 * mgreer@mvista.com
6 * mporter@mvista.com
7 * jpeters@mvista.com
8 *
9 * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14
15#include <linux/stddef.h>
16#include <linux/init.h>
17#include <linux/sched.h>
18#include <linux/signal.h>
19#include <linux/irq.h>
20
21#include <asm/io.h>
22#include <asm/system.h>
23#include <asm/irq.h>
24
25#include "cpc700.h"
26
27static void
28cpc700_unmask_irq(unsigned int irq)
29{
30 unsigned int tr_bits;
31
32 /*
33 * IRQ 31 is largest IRQ supported.
34 * IRQs 17-19 are reserved.
35 */
36 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
37 tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
38
39 if ((tr_bits & (1 << (31 - irq))) == 0) {
40 /* level trigger interrupt, clear bit in status
41 * register */
42 CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
43 }
44
45 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
46 ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
47
48 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
49 }
50 return;
51}
52
53static void
54cpc700_mask_irq(unsigned int irq)
55{
56 /*
57 * IRQ 31 is largest IRQ supported.
58 * IRQs 17-19 are reserved.
59 */
60 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
61 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
62 ppc_cached_irq_mask[0] &=
63 ~CPC700_UIC_IRQ_BIT(irq);
64
65 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
66 }
67 return;
68}
69
70static void
71cpc700_mask_and_ack_irq(unsigned int irq)
72{
73 u_int bit;
74
75 /*
76 * IRQ 31 is largest IRQ supported.
77 * IRQs 17-19 are reserved.
78 */
79 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
80 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
81 bit = CPC700_UIC_IRQ_BIT(irq);
82
83 ppc_cached_irq_mask[0] &= ~bit;
84 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
85 CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
86 }
87 return;
88}
89
90static struct hw_interrupt_type cpc700_pic = {
Thomas Gleixner2830e212005-09-10 00:26:40 -070091 .typename = "CPC700 PIC",
92 .enable = cpc700_unmask_irq,
93 .disable = cpc700_mask_irq,
94 .ack = cpc700_mask_and_ack_irq,
Linus Torvalds1da177e2005-04-16 15:20:36 -070095};
96
97__init static void
98cpc700_pic_init_irq(unsigned int irq)
99{
100 unsigned int tmp;
101
102 /* Set interrupt sense */
103 tmp = CPC700_IN_32(CPC700_UIC_UICTR);
104 if (cpc700_irq_assigns[irq][0] == 0) {
105 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
106 } else {
107 tmp |= CPC700_UIC_IRQ_BIT(irq);
108 }
109 CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
110
111 /* Set interrupt polarity */
112 tmp = CPC700_IN_32(CPC700_UIC_UICPR);
113 if (cpc700_irq_assigns[irq][1]) {
114 tmp |= CPC700_UIC_IRQ_BIT(irq);
115 } else {
116 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
117 }
118 CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
119
120 /* Set interrupt critical */
121 tmp = CPC700_IN_32(CPC700_UIC_UICCR);
122 tmp |= CPC700_UIC_IRQ_BIT(irq);
123 CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
124
125 return;
126}
127
128__init void
129cpc700_init_IRQ(void)
130{
131 int i;
132
133 ppc_cached_irq_mask[0] = 0;
134 CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */
135 CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */
136 CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */
137 CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */
138 CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */
139 CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
140 /* IRQ 0 is highest */
141
142 for (i = 0; i < 17; i++) {
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700143 irq_desc[i].chip = &cpc700_pic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 cpc700_pic_init_irq(i);
145 }
146
147 for (i = 20; i < 32; i++) {
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700148 irq_desc[i].chip = &cpc700_pic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 cpc700_pic_init_irq(i);
150 }
151
152 return;
153}
154
155
156
157/*
158 * Find the highest IRQ that generating an interrupt, if any.
159 */
160int
Al Viro39e3eb72006-10-09 12:48:42 +0100161cpc700_get_irq(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 int irq = 0;
164 u_int irq_status, irq_test = 1;
165
166 irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
167
168 do
169 {
170 if (irq_status & irq_test)
171 break;
172 irq++;
173 irq_test <<= 1;
174 } while (irq < NR_IRQS);
175
176
177 if (irq == NR_IRQS)
178 irq = 33;
179
180 return (31 - irq);
181}