2 * This file is part of the coreboot project.
4 * Copyright (C) 2010 coresystems GmbH
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.
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.
17 #include <arch/ioapic.h>
18 #include <console/console.h>
19 #include <cpu/x86/lapic.h>
21 u32
io_apic_read(void *ioapic_base
, u32 reg
)
23 write32(ioapic_base
, reg
);
24 return read32(ioapic_base
+ 0x10);
27 void io_apic_write(void *ioapic_base
, u32 reg
, u32 value
)
29 write32(ioapic_base
, reg
);
30 write32(ioapic_base
+ 0x10, value
);
33 static int ioapic_interrupt_count(void *ioapic_base
)
35 /* Read the available number of interrupts. */
36 int ioapic_interrupts
= (io_apic_read(ioapic_base
, 0x01) >> 16) & 0xff;
37 if (ioapic_interrupts
== 0xff)
38 ioapic_interrupts
= 23;
39 ioapic_interrupts
+= 1; /* Bits 23-16 specify the maximum redirection
40 entry, which is the number of interrupts
42 printk(BIOS_DEBUG
, "IOAPIC: %d interrupts\n", ioapic_interrupts
);
44 return ioapic_interrupts
;
47 void clear_ioapic(void *ioapic_base
)
50 u32 i
, ioapic_interrupts
;
52 printk(BIOS_DEBUG
, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base
);
54 ioapic_interrupts
= ioapic_interrupt_count(ioapic_base
);
59 for (i
= 0; i
< ioapic_interrupts
; i
++) {
60 io_apic_write(ioapic_base
, i
* 2 + 0x10, low
);
61 io_apic_write(ioapic_base
, i
* 2 + 0x11, high
);
63 printk(BIOS_SPEW
, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
67 if (io_apic_read(ioapic_base
, 0x10) == 0xffffffff) {
68 printk(BIOS_WARNING
, "IOAPIC not responding.\n");
73 void set_ioapic_id(void *ioapic_base
, u8 ioapic_id
)
75 u32 bsp_lapicid
= lapicid();
78 printk(BIOS_DEBUG
, "IOAPIC: Initializing IOAPIC at 0x%p\n",
80 printk(BIOS_DEBUG
, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
84 printk(BIOS_DEBUG
, "IOAPIC: ID = 0x%02x\n", ioapic_id
);
85 /* Set IOAPIC ID if it has been specified. */
86 io_apic_write(ioapic_base
, 0x00,
87 (io_apic_read(ioapic_base
, 0x00) & 0xf0ffffff) |
91 printk(BIOS_SPEW
, "IOAPIC: Dumping registers\n");
92 for (i
= 0; i
< 3; i
++)
93 printk(BIOS_SPEW
, " reg 0x%04x: 0x%08x\n", i
,
94 io_apic_read(ioapic_base
, i
));
98 static void load_vectors(void *ioapic_base
)
100 u32 bsp_lapicid
= lapicid();
102 u32 i
, ioapic_interrupts
;
104 ioapic_interrupts
= ioapic_interrupt_count(ioapic_base
);
106 #if CONFIG_IOAPIC_INTERRUPTS_ON_FSB
108 * For the Pentium 4 and above APICs deliver their interrupts
109 * on the front side bus, enable that.
111 printk(BIOS_DEBUG
, "IOAPIC: Enabling interrupts on FSB\n");
112 io_apic_write(ioapic_base
, 0x03,
113 io_apic_read(ioapic_base
, 0x03) | (1 << 0));
115 #if CONFIG_IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
116 printk(BIOS_DEBUG
, "IOAPIC: Enabling interrupts on APIC serial bus\n");
117 io_apic_write(ioapic_base
, 0x03, 0);
120 /* Enable Virtual Wire Mode. */
121 low
= ENABLED
| TRIGGER_EDGE
| POLARITY_HIGH
| PHYSICAL_DEST
| ExtINT
;
122 high
= bsp_lapicid
<< (56 - 32);
124 io_apic_write(ioapic_base
, 0x10, low
);
125 io_apic_write(ioapic_base
, 0x11, high
);
127 if (io_apic_read(ioapic_base
, 0x10) == 0xffffffff) {
128 printk(BIOS_WARNING
, "IOAPIC not responding.\n");
132 printk(BIOS_SPEW
, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
136 for (i
= 1; i
< ioapic_interrupts
; i
++) {
137 io_apic_write(ioapic_base
, i
* 2 + 0x10, low
);
138 io_apic_write(ioapic_base
, i
* 2 + 0x11, high
);
140 printk(BIOS_SPEW
, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
145 void setup_ioapic(void *ioapic_base
, u8 ioapic_id
)
147 set_ioapic_id(ioapic_base
, ioapic_id
);
148 load_vectors(ioapic_base
);