]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/x86/lib/pcat_interrupts.c
Merge branch 'master' of git://git.denx.de/u-boot-mpc83xx
[karo-tx-uboot.git] / arch / x86 / lib / pcat_interrupts.c
1 /*
2  * (C) Copyright 2009
3  * Graeme Russ, <graeme.russ@gmail.com>
4  *
5  * (C) Copyright 2002
6  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 /*
28  * This file provides the interrupt handling functionality for systems
29  * based on the standard PC/AT architecture using two cascaded i8259
30  * Programmable Interrupt Controllers.
31  */
32
33 #include <common.h>
34 #include <asm/io.h>
35 #include <asm/i8259.h>
36 #include <asm/ibmpc.h>
37 #include <asm/interrupt.h>
38
39 #if CONFIG_SYS_NUM_IRQS != 16
40 #error "CONFIG_SYS_NUM_IRQS must equal 16 if CONFIG_SYS_NUM_IRQS is defined"
41 #endif
42
43 int interrupt_init(void)
44 {
45         u8 i;
46
47         disable_interrupts();
48
49         /* Mask all interrupts */
50         outb(0xff, MASTER_PIC + IMR);
51         outb(0xff, SLAVE_PIC + IMR);
52
53         /* Master PIC */
54         /* Place master PIC interrupts at INT20 */
55         /* ICW3, One slave PIC is present */
56         outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);
57         outb(0x20, MASTER_PIC + ICW2);
58         outb(IR2, MASTER_PIC + ICW3);
59         outb(ICW4_PM, MASTER_PIC + ICW4);
60
61         for (i = 0; i < 8; i++)
62                 outb(OCW2_SEOI | i, MASTER_PIC + OCW2);
63
64         /* Slave PIC */
65         /* Place slave PIC interrupts at INT28 */
66         /* Slave ID */
67         outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);
68         outb(0x28, SLAVE_PIC + ICW2);
69         outb(0x02, SLAVE_PIC + ICW3);
70         outb(ICW4_PM, SLAVE_PIC + ICW4);
71
72         for (i = 0; i < 8; i++)
73                 outb(OCW2_SEOI | i, SLAVE_PIC + OCW2);
74
75         /*
76          * Enable cascaded interrupts by unmasking the cascade IRQ pin of
77          * the master PIC
78          */
79         unmask_irq(2);
80
81         enable_interrupts();
82
83         return 0;
84 }
85
86 void mask_irq(int irq)
87 {
88         int imr_port;
89
90         if (irq >= CONFIG_SYS_NUM_IRQS)
91                 return;
92
93         if (irq > 7)
94                 imr_port = SLAVE_PIC + IMR;
95         else
96                 imr_port = MASTER_PIC + IMR;
97
98         outb(inb(imr_port) | (1 << (irq & 7)), imr_port);
99 }
100
101 void unmask_irq(int irq)
102 {
103         int imr_port;
104
105         if (irq >= CONFIG_SYS_NUM_IRQS)
106                 return;
107
108         if (irq > 7)
109                 imr_port = SLAVE_PIC + IMR;
110         else
111                 imr_port = MASTER_PIC + IMR;
112
113         outb(inb(imr_port) & ~(1 << (irq & 7)), imr_port);
114 }
115
116 void specific_eoi(int irq)
117 {
118         if (irq >= CONFIG_SYS_NUM_IRQS)
119                 return;
120
121         if (irq > 7) {
122                 /*
123                  *  IRQ is on the slave - Issue a corresponding EOI to the
124                  *  slave PIC and an EOI for IRQ2 (the cascade interrupt)
125                  *  on the master PIC
126                  */
127                 outb(OCW2_SEOI | (irq & 7), SLAVE_PIC + OCW2);
128                 irq = SEOI_IR2;
129         }
130
131         outb(OCW2_SEOI | irq, MASTER_PIC + OCW2);
132 }