d6616f5529274ea15e61b1358331109a68de3fe0
[coreboot.git] / src / arch / i386 / lib / ioapic.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2010 coresystems GmbH
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include <arch/io.h>
21 #include <arch/ioapic.h>
22 #include <console/console.h>
23 #include <cpu/x86/lapic.h>
24
25 static u32 io_apic_read(u32 ioapic_base, u32 reg)
26 {
27         write32(ioapic_base, reg);
28         return read32(ioapic_base + 0x10);
29 }
30
31 static void io_apic_write(u32 ioapic_base, u32 reg, u32 value)
32 {
33         write32(ioapic_base, reg);
34         write32(ioapic_base + 0x10, value);
35 }
36
37
38 void clear_ioapic(u32 ioapic_base)
39 {
40         u32 low, high;
41         u32 i, ioapic_interrupts;
42
43         printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at 0x%08x\n", ioapic_base);
44
45         /* Read the available number of interrupts */
46         ioapic_interrupts = (io_apic_read(ioapic_base, 1) >> 16) & 0xff;
47         if (!ioapic_interrupts || ioapic_interrupts == 0xff)
48                 ioapic_interrupts = 24;
49         printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
50
51         low = DISABLED;
52         high = NONE;
53
54         for (i = 0; i < ioapic_interrupts; i++) {
55                 io_apic_write(ioapic_base, i * 2 + 0x10, low);
56                 io_apic_write(ioapic_base, i * 2 + 0x11, high);
57
58                 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", i, high, low);
59         }
60
61         if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
62                 printk(BIOS_WARNING, "IO APIC not responding.\n");
63                 return;
64         }
65 }
66
67 void setup_ioapic(u32 ioapic_base, u8 ioapic_id)
68 {
69         u32 bsp_lapicid = lapicid();
70         u32 low, high;
71         u32 i, ioapic_interrupts;
72
73         printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%08x\n", ioapic_base);
74         printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = %02x\n",
75                         bsp_lapicid);
76
77         if (ioapic_id) {
78                 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
79                 /* Set IOAPIC ID if it has been specified */
80                 io_apic_write(ioapic_base, 0x00,
81                         (io_apic_read(ioapic_base, 0x00) & 0xfff0ffff) |
82                                 (ioapic_id << 24));
83         }
84
85         /* Read the available number of interrupts */
86         ioapic_interrupts = (io_apic_read(ioapic_base, 1) >> 16) & 0xff;
87         if (!ioapic_interrupts || ioapic_interrupts == 0xff)
88                 ioapic_interrupts = 24;
89         printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
90
91
92 // XXX this decision should probably be made elsewhere, and
93 // it's the C3, not the EPIA this depends on.
94 #if defined(CONFIG_EPIA_VT8237R_INIT) && CONFIG_EPIA_VT8237R_INIT
95 #define IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
96 #else
97 #define IOAPIC_INTERRUPTS_ON_FSB
98 #endif
99
100 #ifdef IOAPIC_INTERRUPTS_ON_FSB
101         /* For the Pentium 4 and above APICs deliver their interrupts
102          * on the front side bus, enable that.
103          */
104         printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
105         io_apic_write(ioapic_base, 0x03, io_apic_read(ioapic_base, 0x03) | (1 << 0));
106 #endif
107 #ifdef IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
108         printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
109         io_apic_write(ioapic_base, 0x03, 0);
110 #endif
111
112         /* Enable Virtual Wire Mode */
113         low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
114         high = bsp_lapicid << (56 - 32);
115
116         io_apic_write(ioapic_base, 0x10, low);
117         io_apic_write(ioapic_base, 0x11, high);
118
119         if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
120                 printk(BIOS_WARNING, "IO APIC not responding.\n");
121                 return;
122         }
123
124         printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", 0, high, low);
125
126         low = DISABLED;
127         high = NONE;
128
129         for (i = 1; i < ioapic_interrupts; i++) {
130                 io_apic_write(ioapic_base, i * 2 + 0x10, low);
131                 io_apic_write(ioapic_base, i * 2 + 0x11, high);
132
133                 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", i, high, low);
134         }
135 }