Two hda_verb.h files: Add more comments.
[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 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) & 0xfff0ffff) |
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 // 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         /*
102          * For the Pentium 4 and above APICs deliver their interrupts
103          * on the front side bus, enable that.
104          */
105         printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
106         io_apic_write(ioapic_base, 0x03,
107                       io_apic_read(ioapic_base, 0x03) | (1 << 0));
108 #endif
109 #ifdef IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
110         printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
111         io_apic_write(ioapic_base, 0x03, 0);
112 #endif
113
114         /* Enable Virtual Wire Mode. */
115         low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
116         high = bsp_lapicid << (56 - 32);
117
118         io_apic_write(ioapic_base, 0x10, low);
119         io_apic_write(ioapic_base, 0x11, high);
120
121         if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
122                 printk(BIOS_WARNING, "IOAPIC not responding.\n");
123                 return;
124         }
125
126         printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
127                0, high, low);
128
129         low = DISABLED;
130         high = NONE;
131
132         for (i = 1; i < ioapic_interrupts; i++) {
133                 io_apic_write(ioapic_base, i * 2 + 0x10, low);
134                 io_apic_write(ioapic_base, i * 2 + 0x11, high);
135
136                 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
137                        i, high, low);
138         }
139 }