Via Epia-N and C3: Set ioapic delivery type in Kconfig
[coreboot.git] / src / arch / x86 / 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 void clear_ioapic(u32 ioapic_base)
38 {
39         u32 low, high;
40         u32 i, ioapic_interrupts;
41
42         printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at 0x%08x\n", ioapic_base);
43
44         /* Read the available number of interrupts. */
45         ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
46         if (!ioapic_interrupts || ioapic_interrupts == 0xff)
47                 ioapic_interrupts = 24;
48         printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
49
50         low = DISABLED;
51         high = NONE;
52
53         for (i = 0; i < ioapic_interrupts; i++) {
54                 io_apic_write(ioapic_base, i * 2 + 0x10, low);
55                 io_apic_write(ioapic_base, i * 2 + 0x11, high);
56
57                 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
58                        i, high, low);
59         }
60
61         if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
62                 printk(BIOS_WARNING, "IOAPIC 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",
74                ioapic_base);
75         printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
76                bsp_lapicid);
77
78         if (ioapic_id) {
79                 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
80                 /* Set IOAPIC ID if it has been specified. */
81                 io_apic_write(ioapic_base, 0x00,
82                         (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
83                         (ioapic_id << 24));
84         }
85
86         /* Read the available number of interrupts. */
87         ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
88         if (!ioapic_interrupts || ioapic_interrupts == 0xff)
89                 ioapic_interrupts = 24;
90         printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
91
92 #ifdef CONFIG_IOAPIC_INTERRUPTS_ON_FSB
93         /*
94          * For the Pentium 4 and above APICs deliver their interrupts
95          * on the front side bus, enable that.
96          */
97         printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
98         io_apic_write(ioapic_base, 0x03,
99                       io_apic_read(ioapic_base, 0x03) | (1 << 0));
100 #endif
101 #ifdef CONFIG_IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
102         printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
103         io_apic_write(ioapic_base, 0x03, 0);
104 #endif
105
106         /* Enable Virtual Wire Mode. */
107         low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
108         high = bsp_lapicid << (56 - 32);
109
110         io_apic_write(ioapic_base, 0x10, low);
111         io_apic_write(ioapic_base, 0x11, high);
112
113         if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
114                 printk(BIOS_WARNING, "IOAPIC not responding.\n");
115                 return;
116         }
117
118         printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
119                0, high, low);
120
121         low = DISABLED;
122         high = NONE;
123
124         for (i = 1; i < ioapic_interrupts; i++) {
125                 io_apic_write(ioapic_base, i * 2 + 0x10, low);
126                 io_apic_write(ioapic_base, i * 2 + 0x11, high);
127
128                 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
129                        i, high, low);
130         }
131 }