Import upstream u-boot 1.1.4
[u-boot.git] / board / MAI / AmigaOneG3SE / i8259.c
1 /*
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
35 static 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
42 static 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
47 static 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  */
68 static char cached_imr[2] = {0xff, 0xff};
69
70 #define cached_imr1     (cached_imr[0])
71 #define cached_imr2     (cached_imr[1])
72
73 void i8259_init(void)
74 {
75         char dummy;
76         PRINTF("Initializing Interrupt controller\n");
77         /* init master interrupt controller */
78         out8(0x20, 0x11); /* 0x19); /###* Start init sequence */
79         out8(0x21, 0x00); /* Vector base */
80         out8(0x21, 0x04); /* edge tiggered, Cascade (slave) on IRQ2 */
81         out8(0x21, 0x11); /* was: 0x01); /###* Select 8086 mode */
82
83         /* init slave interrupt controller */
84         out8(0xA0, 0x11); /* 0x19); /###* Start init sequence */
85         out8(0xA1, 0x08); /* Vector base */
86         out8(0xA1, 0x02); /* edge triggered, Cascade (slave) on IRQ2 */
87         out8(0xA1, 0x11); /* was: 0x01); /###* Select 8086 mode */
88
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
121 static volatile char *pci_intack = (void *)0xFEF00000;
122
123 int 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 }
143 int 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  */
194 void 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
210 void 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
221 void 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 }