1dc14d97bSMichael Lotz /*
2dc14d97bSMichael Lotz * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
3dc14d97bSMichael Lotz * Distributed under the terms of the MIT License.
4dc14d97bSMichael Lotz *
5dc14d97bSMichael Lotz * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6dc14d97bSMichael Lotz * Distributed under the terms of the NewOS License.
7dc14d97bSMichael Lotz */
8dc14d97bSMichael Lotz
9dc14d97bSMichael Lotz #include <arch/x86/pic.h>
10dc14d97bSMichael Lotz
11dc14d97bSMichael Lotz #include <arch/cpu.h>
12dc14d97bSMichael Lotz #include <arch/int.h>
13dc14d97bSMichael Lotz
14dc14d97bSMichael Lotz #include <arch/x86/arch_int.h>
15dc14d97bSMichael Lotz
16fc2d7cb0SMichael Lotz #include <int.h>
17fc2d7cb0SMichael Lotz
18dc14d97bSMichael Lotz
19dc14d97bSMichael Lotz //#define TRACE_PIC
20dc14d97bSMichael Lotz #ifdef TRACE_PIC
21dc14d97bSMichael Lotz # define TRACE(x) dprintf x
22dc14d97bSMichael Lotz #else
23dc14d97bSMichael Lotz # define TRACE(x) ;
24dc14d97bSMichael Lotz #endif
25dc14d97bSMichael Lotz
26dc14d97bSMichael Lotz
27dc14d97bSMichael Lotz // Definitions for the PIC 8259 controller
28dc14d97bSMichael Lotz // (this is not a complete list, only what we're actually using)
29dc14d97bSMichael Lotz
30dc14d97bSMichael Lotz #define PIC_MASTER_CONTROL 0x20
31dc14d97bSMichael Lotz #define PIC_MASTER_MASK 0x21
32dc14d97bSMichael Lotz #define PIC_SLAVE_CONTROL 0xa0
33dc14d97bSMichael Lotz #define PIC_SLAVE_MASK 0xa1
34dc14d97bSMichael Lotz #define PIC_MASTER_INIT1 PIC_MASTER_CONTROL
35dc14d97bSMichael Lotz #define PIC_MASTER_INIT2 PIC_MASTER_MASK
36dc14d97bSMichael Lotz #define PIC_MASTER_INIT3 PIC_MASTER_MASK
37dc14d97bSMichael Lotz #define PIC_MASTER_INIT4 PIC_MASTER_MASK
38dc14d97bSMichael Lotz #define PIC_SLAVE_INIT1 PIC_SLAVE_CONTROL
39dc14d97bSMichael Lotz #define PIC_SLAVE_INIT2 PIC_SLAVE_MASK
40dc14d97bSMichael Lotz #define PIC_SLAVE_INIT3 PIC_SLAVE_MASK
41dc14d97bSMichael Lotz #define PIC_SLAVE_INIT4 PIC_SLAVE_MASK
42dc14d97bSMichael Lotz
43dc14d97bSMichael Lotz // the edge/level trigger control registers
44dc14d97bSMichael Lotz #define PIC_MASTER_TRIGGER_MODE 0x4d0
45dc14d97bSMichael Lotz #define PIC_SLAVE_TRIGGER_MODE 0x4d1
46dc14d97bSMichael Lotz
47dc14d97bSMichael Lotz #define PIC_INIT1 0x10
48dc14d97bSMichael Lotz #define PIC_INIT1_SEND_INIT4 0x01
49dc14d97bSMichael Lotz #define PIC_INIT3_IR2_IS_SLAVE 0x04
50dc14d97bSMichael Lotz #define PIC_INIT3_SLAVE_ID2 0x02
51dc14d97bSMichael Lotz #define PIC_INIT4_x86_MODE 0x01
52dc14d97bSMichael Lotz
53dc14d97bSMichael Lotz #define PIC_CONTROL3 0x08
54dc14d97bSMichael Lotz #define PIC_CONTROL3_READ_ISR 0x03
55dc14d97bSMichael Lotz #define PIC_CONTROL3_READ_IRR 0x02
56dc14d97bSMichael Lotz
57dc14d97bSMichael Lotz #define PIC_NON_SPECIFIC_EOI 0x20
58dc14d97bSMichael Lotz
59dc14d97bSMichael Lotz #define PIC_SLAVE_INT_BASE 8
60dc14d97bSMichael Lotz #define PIC_NUM_INTS 0x0f
61dc14d97bSMichael Lotz
62dc14d97bSMichael Lotz
63dc14d97bSMichael Lotz static uint16 sLevelTriggeredInterrupts = 0;
64dc14d97bSMichael Lotz // binary mask: 1 level, 0 edge
65dc14d97bSMichael Lotz
66dc14d97bSMichael Lotz
67dc14d97bSMichael Lotz /*! Tests if the interrupt in-service register of the responsible
68dc14d97bSMichael Lotz PIC is set for interrupts 7 and 15, and if that's not the case,
69dc14d97bSMichael Lotz it must assume it's a spurious interrupt.
70dc14d97bSMichael Lotz */
71dc14d97bSMichael Lotz static bool
pic_is_spurious_interrupt(int32 num)72dc14d97bSMichael Lotz pic_is_spurious_interrupt(int32 num)
73dc14d97bSMichael Lotz {
74dc14d97bSMichael Lotz if (num != 7)
75dc14d97bSMichael Lotz return false;
76dc14d97bSMichael Lotz
77dc14d97bSMichael Lotz // Note, detecting spurious interrupts on line 15 obviously doesn't
78dc14d97bSMichael Lotz // work correctly - and since those are extremely rare, anyway, we
79dc14d97bSMichael Lotz // just ignore them
80dc14d97bSMichael Lotz
81dc14d97bSMichael Lotz out8(PIC_CONTROL3 | PIC_CONTROL3_READ_ISR, PIC_MASTER_CONTROL);
82dc14d97bSMichael Lotz int32 isr = in8(PIC_MASTER_CONTROL);
83dc14d97bSMichael Lotz out8(PIC_CONTROL3 | PIC_CONTROL3_READ_IRR, PIC_MASTER_CONTROL);
84dc14d97bSMichael Lotz
85dc14d97bSMichael Lotz return (isr & 0x80) == 0;
86dc14d97bSMichael Lotz }
87dc14d97bSMichael Lotz
88dc14d97bSMichael Lotz
89dc14d97bSMichael Lotz static bool
pic_is_level_triggered_interrupt(int32 num)90dc14d97bSMichael Lotz pic_is_level_triggered_interrupt(int32 num)
91dc14d97bSMichael Lotz {
92dc14d97bSMichael Lotz if (num < 0 || num > PIC_NUM_INTS)
93dc14d97bSMichael Lotz return false;
94dc14d97bSMichael Lotz
95dc14d97bSMichael Lotz return (sLevelTriggeredInterrupts & (1 << num)) != 0;
96dc14d97bSMichael Lotz }
97dc14d97bSMichael Lotz
98dc14d97bSMichael Lotz
99dc14d97bSMichael Lotz /*! Sends a non-specified EOI (end of interrupt) notice to the PIC in
100dc14d97bSMichael Lotz question (or both of them).
101dc14d97bSMichael Lotz This clears the PIC interrupt in-service bit.
102dc14d97bSMichael Lotz */
103dc14d97bSMichael Lotz static bool
pic_end_of_interrupt(int32 num)104dc14d97bSMichael Lotz pic_end_of_interrupt(int32 num)
105dc14d97bSMichael Lotz {
106dc14d97bSMichael Lotz if (num < 0 || num > PIC_NUM_INTS)
107dc14d97bSMichael Lotz return false;
108dc14d97bSMichael Lotz
109dc14d97bSMichael Lotz // PIC 8259 controlled interrupt
110dc14d97bSMichael Lotz if (num >= PIC_SLAVE_INT_BASE)
111dc14d97bSMichael Lotz out8(PIC_NON_SPECIFIC_EOI, PIC_SLAVE_CONTROL);
112dc14d97bSMichael Lotz
113dc14d97bSMichael Lotz // we always need to acknowledge the master PIC
114dc14d97bSMichael Lotz out8(PIC_NON_SPECIFIC_EOI, PIC_MASTER_CONTROL);
115dc14d97bSMichael Lotz return true;
116dc14d97bSMichael Lotz }
117dc14d97bSMichael Lotz
118dc14d97bSMichael Lotz
119dc14d97bSMichael Lotz static void
pic_enable_io_interrupt(int32 num)120dc14d97bSMichael Lotz pic_enable_io_interrupt(int32 num)
121dc14d97bSMichael Lotz {
122dc14d97bSMichael Lotz // interrupt is specified "normalized"
123dc14d97bSMichael Lotz if (num < 0 || num > PIC_NUM_INTS)
124dc14d97bSMichael Lotz return;
125dc14d97bSMichael Lotz
126dc14d97bSMichael Lotz // enable PIC 8259 controlled interrupt
127dc14d97bSMichael Lotz
128dc14d97bSMichael Lotz TRACE(("pic_enable_io_interrupt: irq %ld\n", num));
129dc14d97bSMichael Lotz
130dc14d97bSMichael Lotz if (num < PIC_SLAVE_INT_BASE)
131dc14d97bSMichael Lotz out8(in8(PIC_MASTER_MASK) & ~(1 << num), PIC_MASTER_MASK);
132dc14d97bSMichael Lotz else
133dc14d97bSMichael Lotz out8(in8(PIC_SLAVE_MASK) & ~(1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK);
134dc14d97bSMichael Lotz }
135dc14d97bSMichael Lotz
136dc14d97bSMichael Lotz
137dc14d97bSMichael Lotz static void
pic_disable_io_interrupt(int32 num)138dc14d97bSMichael Lotz pic_disable_io_interrupt(int32 num)
139dc14d97bSMichael Lotz {
140dc14d97bSMichael Lotz // interrupt is specified "normalized"
141dc14d97bSMichael Lotz // never disable slave pic line IRQ 2
142dc14d97bSMichael Lotz if (num < 0 || num > PIC_NUM_INTS || num == 2)
143dc14d97bSMichael Lotz return;
144dc14d97bSMichael Lotz
145dc14d97bSMichael Lotz // disable PIC 8259 controlled interrupt
146dc14d97bSMichael Lotz
147dc14d97bSMichael Lotz TRACE(("pic_disable_io_interrupt: irq %ld\n", num));
148dc14d97bSMichael Lotz
149dc14d97bSMichael Lotz if (num < PIC_SLAVE_INT_BASE)
150dc14d97bSMichael Lotz out8(in8(PIC_MASTER_MASK) | (1 << num), PIC_MASTER_MASK);
151dc14d97bSMichael Lotz else
152dc14d97bSMichael Lotz out8(in8(PIC_SLAVE_MASK) | (1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK);
153dc14d97bSMichael Lotz }
154dc14d97bSMichael Lotz
155dc14d97bSMichael Lotz
156dc14d97bSMichael Lotz static void
pic_configure_io_interrupt(int32 num,uint32 config)157dc14d97bSMichael Lotz pic_configure_io_interrupt(int32 num, uint32 config)
158dc14d97bSMichael Lotz {
159dc14d97bSMichael Lotz uint8 value;
160dc14d97bSMichael Lotz int32 localBit;
161dc14d97bSMichael Lotz if (num < 0 || num > PIC_NUM_INTS || num == 2)
162dc14d97bSMichael Lotz return;
163dc14d97bSMichael Lotz
164dc14d97bSMichael Lotz TRACE(("pic_configure_io_interrupt: irq %ld; config 0x%08lx\n", num, config));
165dc14d97bSMichael Lotz
166dc14d97bSMichael Lotz if (num < PIC_SLAVE_INT_BASE) {
167dc14d97bSMichael Lotz value = in8(PIC_MASTER_TRIGGER_MODE);
168dc14d97bSMichael Lotz localBit = num;
169dc14d97bSMichael Lotz } else {
170dc14d97bSMichael Lotz value = in8(PIC_SLAVE_TRIGGER_MODE);
171dc14d97bSMichael Lotz localBit = num - PIC_SLAVE_INT_BASE;
172dc14d97bSMichael Lotz }
173dc14d97bSMichael Lotz
174dc14d97bSMichael Lotz if (config & B_LEVEL_TRIGGERED)
175dc14d97bSMichael Lotz value |= 1 << localBit;
176dc14d97bSMichael Lotz else
177dc14d97bSMichael Lotz value &= ~(1 << localBit);
178dc14d97bSMichael Lotz
179dc14d97bSMichael Lotz if (num < PIC_SLAVE_INT_BASE)
180dc14d97bSMichael Lotz out8(value, PIC_MASTER_TRIGGER_MODE);
181dc14d97bSMichael Lotz else
182dc14d97bSMichael Lotz out8(value, PIC_SLAVE_TRIGGER_MODE);
183dc14d97bSMichael Lotz
184dc14d97bSMichael Lotz sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE)
185dc14d97bSMichael Lotz | (in8(PIC_SLAVE_TRIGGER_MODE) << 8);
186dc14d97bSMichael Lotz }
187dc14d97bSMichael Lotz
188dc14d97bSMichael Lotz
189dc14d97bSMichael Lotz void
pic_init()190dc14d97bSMichael Lotz pic_init()
191dc14d97bSMichael Lotz {
192dc14d97bSMichael Lotz static const interrupt_controller picController = {
193dc14d97bSMichael Lotz "8259 PIC",
194dc14d97bSMichael Lotz &pic_enable_io_interrupt,
195dc14d97bSMichael Lotz &pic_disable_io_interrupt,
196dc14d97bSMichael Lotz &pic_configure_io_interrupt,
197dc14d97bSMichael Lotz &pic_is_spurious_interrupt,
198dc14d97bSMichael Lotz &pic_is_level_triggered_interrupt,
199*d897a478SPawel Dziepak &pic_end_of_interrupt,
200*d897a478SPawel Dziepak NULL
201dc14d97bSMichael Lotz };
202dc14d97bSMichael Lotz
203dc14d97bSMichael Lotz // Start initialization sequence for the master and slave PICs
204dc14d97bSMichael Lotz out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_MASTER_INIT1);
205dc14d97bSMichael Lotz out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_SLAVE_INIT1);
206dc14d97bSMichael Lotz
207dc14d97bSMichael Lotz // Set start of interrupts to 0x20 for master, 0x28 for slave
208dc14d97bSMichael Lotz out8(ARCH_INTERRUPT_BASE, PIC_MASTER_INIT2);
209dc14d97bSMichael Lotz out8(ARCH_INTERRUPT_BASE + PIC_SLAVE_INT_BASE, PIC_SLAVE_INIT2);
210dc14d97bSMichael Lotz
211dc14d97bSMichael Lotz // Specify cascading through interrupt 2
212dc14d97bSMichael Lotz out8(PIC_INIT3_IR2_IS_SLAVE, PIC_MASTER_INIT3);
213dc14d97bSMichael Lotz out8(PIC_INIT3_SLAVE_ID2, PIC_SLAVE_INIT3);
214dc14d97bSMichael Lotz
215dc14d97bSMichael Lotz // Set both to operate in 8086 mode
216dc14d97bSMichael Lotz out8(PIC_INIT4_x86_MODE, PIC_MASTER_INIT4);
217dc14d97bSMichael Lotz out8(PIC_INIT4_x86_MODE, PIC_SLAVE_INIT4);
218dc14d97bSMichael Lotz
219dc14d97bSMichael Lotz out8(0xfb, PIC_MASTER_MASK); // Mask off all interrupts (except slave pic line IRQ 2).
220dc14d97bSMichael Lotz out8(0xff, PIC_SLAVE_MASK); // Mask off interrupts on the slave.
221dc14d97bSMichael Lotz
222dc14d97bSMichael Lotz // determine which interrupts are level or edge triggered
223dc14d97bSMichael Lotz
224dc14d97bSMichael Lotz #if 0
225dc14d97bSMichael Lotz // should set everything possible to level triggered
226dc14d97bSMichael Lotz out8(0xf8, PIC_MASTER_TRIGGER_MODE);
227dc14d97bSMichael Lotz out8(0xde, PIC_SLAVE_TRIGGER_MODE);
228dc14d97bSMichael Lotz #endif
229dc14d97bSMichael Lotz
230dc14d97bSMichael Lotz sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE)
231dc14d97bSMichael Lotz | (in8(PIC_SLAVE_TRIGGER_MODE) << 8);
232dc14d97bSMichael Lotz
233dc14d97bSMichael Lotz TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts));
234dc14d97bSMichael Lotz
2356a164daaSPawel Dziepak reserve_io_interrupt_vectors(16, 0, INTERRUPT_TYPE_EXCEPTION);
236fc2d7cb0SMichael Lotz
237dc14d97bSMichael Lotz // make the pic controller the current one
238dc14d97bSMichael Lotz arch_int_set_interrupt_controller(picController);
239dc14d97bSMichael Lotz }
240dc14d97bSMichael Lotz
241dc14d97bSMichael Lotz
242dc14d97bSMichael Lotz void
pic_disable(uint16 & enabledInterrupts)243fb5a1727SMichael Lotz pic_disable(uint16& enabledInterrupts)
244dc14d97bSMichael Lotz {
2452c0d5258SMichael Lotz enabledInterrupts = ~(in8(PIC_MASTER_MASK) | in8(PIC_SLAVE_MASK) << 8);
246fb5a1727SMichael Lotz enabledInterrupts &= 0xfffb; // remove slave PIC from the mask
247fb5a1727SMichael Lotz
248dc14d97bSMichael Lotz // Mask off all interrupts on master and slave
249dc14d97bSMichael Lotz out8(0xff, PIC_MASTER_MASK);
250dc14d97bSMichael Lotz out8(0xff, PIC_SLAVE_MASK);
251fc2d7cb0SMichael Lotz
252fc2d7cb0SMichael Lotz free_io_interrupt_vectors(16, 0);
253dc14d97bSMichael Lotz }
254