blob: 34f489f7c53472e088ac1bcc8fa73ff3dda03e8c [file] [log] [blame]
wdenkc7de8292002-11-19 11:04:11 +00001/*
2 * (C) Copyright 2002
3 * John W. Linville, linville@tuxdriver.com
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include "i8259.h"
26
27#undef IRQ_DEBUG
28
29#ifdef IRQ_DEBUG
30#define PRINTF(fmt,args...) printf (fmt ,##args)
31#else
32#define PRINTF(fmt,args...)
33#endif
34
35static inline unsigned char read_byte(volatile unsigned char* from)
36{
37 int x;
38 asm volatile ("lbz %0,%1\n eieio" : "=r" (x) : "m" (*from));
39 return (unsigned char)x;
40}
41
42static inline void write_byte(volatile unsigned char *to, int x)
43{
44 asm volatile ("stb %1,%0\n eieio" : "=m" (*to) : "r" (x));
45}
46
47static inline unsigned long read_long_little(volatile unsigned long *from)
48{
49 unsigned long x;
50 asm volatile ("lwbrx %0,0,%1\n eieio\n sync" : "=r" (x) : "r" (from), "m"(*from));
51 return (unsigned long)x;
52}
53
54#ifdef out8
55#undef out8
56#endif
57
58#ifdef in8
59#undef in8
60#endif
61
62#define out8(addr, byte) write_byte(0xFE000000 | addr, byte)
63#define in8(addr) read_byte(0xFE000000 | addr)
64
65/*
66 * This contains the irq mask for both 8259A irq controllers,
67 */
68static char cached_imr[2] = {0xff, 0xff};
69
70#define cached_imr1 (cached_imr[0])
71#define cached_imr2 (cached_imr[1])
72
73void i8259_init(void)
74{
75 char dummy;
76 PRINTF("Initializing Interrupt controller\n");
77 /* init master interrupt controller */
wdenk8bde7f72003-06-27 21:31:46 +000078 out8(0x20, 0x11); /* 0x19); /###* Start init sequence */
wdenkc7de8292002-11-19 11:04:11 +000079 out8(0x21, 0x00); /* Vector base */
80 out8(0x21, 0x04); /* edge tiggered, Cascade (slave) on IRQ2 */
wdenk8bde7f72003-06-27 21:31:46 +000081 out8(0x21, 0x11); /* was: 0x01); /###* Select 8086 mode */
wdenkc7de8292002-11-19 11:04:11 +000082
83 /* init slave interrupt controller */
wdenk8bde7f72003-06-27 21:31:46 +000084 out8(0xA0, 0x11); /* 0x19); /###* Start init sequence */
wdenkc7de8292002-11-19 11:04:11 +000085 out8(0xA1, 0x08); /* Vector base */
86 out8(0xA1, 0x02); /* edge triggered, Cascade (slave) on IRQ2 */
wdenk8bde7f72003-06-27 21:31:46 +000087 out8(0xA1, 0x11); /* was: 0x01); /###* Select 8086 mode */
wdenkc7de8292002-11-19 11:04:11 +000088
89 /* always read ISR */
90 out8(0x20, 0x0B);
91 dummy = in8(ISR_1);
92 out8(0xA0, 0x0B);
93 dummy = in8(ISR_2);
94
95/* out8(0x43, 0x30); */
96/* out8(0x40, 0); */
97/* out8(0x40, 0); */
98/* out8(0x43, 0x70); */
99/* out8(0x41, 0); */
100/* out8(0x41, 0); */
101/* out8(0x43, 0xb0); */
102/* out8(0x42, 0); */
103/* out8(0x42, 0); */
104
105 /* Mask all interrupts */
106 out8(IMR_2, cached_imr2);
107 out8(IMR_1, cached_imr1);
108
109 i8259_unmask_irq(2);
110#if 0
111 {
112 int i;
113 for (i=0; i<16; i++)
114 {
115 i8259_unmask_irq(i);
116 }
117 }
118#endif
119}
120
121static volatile char *pci_intack = (void *)0xFEF00000;
122
123int i8259_irq(void)
124{
125 int irq;
126
127 irq = read_long_little(pci_intack) & 0xff;
128 if (irq==7) {
129 /*
130 * This may be a spurious interrupt.
131 *
132 * Read the interrupt status register (ISR). If the most
133 * significant bit is not set then there is no valid
134 * interrupt.
135 */
136 if(~in8(0x20)&0x80) {
137 irq = -1;
138 }
139 }
140
141 return irq;
142}
143int i8259_get_irq(struct pt_regs *regs)
144{
145 unsigned char irq;
146
147 /*
148 * Perform an interrupt acknowledge cycle on controller 1
149 */
150 out8(OCW3_1, 0x0C); /* prepare for poll */
151 irq = in8(IPL_1) & 7;
152 if (irq == 2) {
153 /*
154 * Interrupt is cascaded so perform interrupt
155 * acknowledge on controller 2
156 */
157 out8(OCW3_2, 0x0C); /* prepare for poll */
158 irq = (in8(IPL_2) & 7) + 8;
159 if (irq == 15) {
160 /*
161 * This may be a spurious interrupt
162 *
163 * Read the interrupt status register. If the most
164 * significant bit is not set then there is no valid
165 * interrupt
166 */
167 out8(OCW3_2, 0x0b);
168 if (~(in8(ISR_2) & 0x80)) {
169 return -1;
170 }
171 }
172 } else if (irq == 7) {
173 /*
174 * This may be a spurious interrupt
175 *
176 * Read the interrupt status register. If the most
177 * significant bit is not set then there is no valid
178 * interrupt
179 */
180 out8(OCW3_1, 0x0b);
181 if (~(in8(ISR_1) & 0x80)) {
182 return -1;
183 }
184 }
185 return irq;
186}
187
188/*
189 * Careful! The 8259A is a fragile beast, it pretty
190 * much _has_ to be done exactly like this (mask it
191 * first, _then_ send the EOI, and the order of EOI
192 * to the two 8259s is important!
193 */
194void i8259_mask_and_ack(int irq)
195{
196 if (irq > 7) {
197 cached_imr2 |= (1 << (irq - 8));
198 in8(IMR_2); /* DUMMY */
199 out8(IMR_2, cached_imr2);
200 out8(OCW2_2, 0x20); /* Non-specific EOI */
201 out8(OCW2_1, 0x20); /* Non-specific EOI to cascade */
202 } else {
203 cached_imr1 |= (1 << irq);
204 in8(IMR_1); /* DUMMY */
205 out8(IMR_1, cached_imr1);
206 out8(OCW2_1, 0x20); /* Non-specific EOI */
207 }
208}
209
210void i8259_mask_irq(int irq)
211{
212 if (irq & 8) {
213 cached_imr2 |= (1 << (irq & 7));
214 out8(IMR_2, cached_imr2);
215 } else {
216 cached_imr1 |= (1 << irq);
217 out8(IMR_1, cached_imr1);
218 }
219}
220
221void i8259_unmask_irq(int irq)
222{
223 if (irq & 8) {
224 cached_imr2 &= ~(1 << (irq & 7));
225 out8(IMR_2, cached_imr2);
226 } else {
227 cached_imr1 &= ~(1 << irq);
228 out8(IMR_1, cached_imr1);
229 }
230}