mb/google/skyrim: Enable Chrome EC
[coreboot.git] / src / arch / x86 / ioapic.c
blobd65637c662e8107210a899a72c009faef86b2b31
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <assert.h>
4 #include <device/mmio.h>
5 #include <arch/ioapic.h>
6 #include <console/console.h>
7 #include <cpu/x86/lapic.h>
9 u32 io_apic_read(void *ioapic_base, u32 reg)
11 write32(ioapic_base, reg);
12 return read32(ioapic_base + 0x10);
15 void io_apic_write(void *ioapic_base, u32 reg, u32 value)
17 write32(ioapic_base, reg);
18 write32(ioapic_base + 0x10, value);
21 static void write_vector(void *ioapic_base, u8 vector, u32 high, u32 low)
23 io_apic_write(ioapic_base, vector * 2 + 0x10, low);
24 io_apic_write(ioapic_base, vector * 2 + 0x11, high);
26 printk(BIOS_SPEW, "IOAPIC: vector 0x%02x value 0x%08x 0x%08x\n",
27 vector, high, low);
30 /* Bits 23-16 of register 0x01 specify the maximum redirection entry, which
31 * is the number of interrupts minus 1. */
32 unsigned int ioapic_get_max_vectors(void *ioapic_base)
34 u32 reg;
35 u8 count;
37 reg = io_apic_read(ioapic_base, 0x01);
38 count = (reg >> 16) & 0xff;
40 if (count == 0xff)
41 count = 23;
42 count++;
44 printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", count);
45 return count;
48 /* Set maximum number of redirection entries (MRE). It is write-once register
49 * for some chipsets, and a negative mre_count will lock it to the number
50 * of vectors read from the register. */
51 void ioapic_set_max_vectors(void *ioapic_base, int mre_count)
53 u32 reg;
54 u8 count;
56 reg = io_apic_read(ioapic_base, 0x01);
57 count = (reg >> 16) & 0xff;
58 if (mre_count > 0)
59 count = mre_count - 1;
60 reg &= ~(0xff << 16);
61 reg |= count << 16;
62 io_apic_write(ioapic_base, 0x01, reg);
65 void ioapic_lock_max_vectors(void *ioapic_base)
67 ioapic_set_max_vectors(ioapic_base, -1);
70 static void clear_vectors(void *ioapic_base, u8 first, u8 last)
72 u32 low, high;
73 u8 i;
75 printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base);
77 low = INT_DISABLED;
78 high = NONE;
80 for (i = first; i <= last; i++)
81 write_vector(ioapic_base, i, high, low);
83 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
84 printk(BIOS_WARNING, "IOAPIC not responding.\n");
85 return;
89 static void route_i8259_irq0(void *ioapic_base)
91 u32 bsp_lapicid = lapicid();
92 u32 low, high;
94 ASSERT(bsp_lapicid < 255);
96 printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
97 bsp_lapicid);
99 /* Enable Virtual Wire Mode. Should this be LOGICAL_DEST instead? */
100 low = INT_ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
101 high = bsp_lapicid << (56 - 32);
103 write_vector(ioapic_base, 0, high, low);
105 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
106 printk(BIOS_WARNING, "IOAPIC not responding.\n");
107 return;
111 void set_ioapic_id(void *ioapic_base, u8 ioapic_id)
113 int i;
115 printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at %p\n",
116 ioapic_base);
118 if (ioapic_id) {
119 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
120 /* Set IOAPIC ID if it has been specified. */
121 io_apic_write(ioapic_base, 0x00,
122 (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
123 (ioapic_id << 24));
126 printk(BIOS_SPEW, "IOAPIC: Dumping registers\n");
127 for (i = 0; i < 3; i++)
128 printk(BIOS_SPEW, " reg 0x%04x: 0x%08x\n", i,
129 io_apic_read(ioapic_base, i));
133 u8 get_ioapic_id(void *ioapic_base)
135 return (io_apic_read(ioapic_base, 0x00) >> 24) & 0x0f;
138 u8 get_ioapic_version(void *ioapic_base)
140 return io_apic_read(ioapic_base, 0x01) & 0xff;
143 void ioapic_set_boot_config(void *ioapic_base, bool irq_on_fsb)
145 if (irq_on_fsb) {
147 * For the Pentium 4 and above APICs deliver their interrupts
148 * on the front side bus, enable that.
150 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
151 io_apic_write(ioapic_base, 0x03,
152 io_apic_read(ioapic_base, 0x03) | (1 << 0));
153 } else {
154 printk(BIOS_DEBUG,
155 "IOAPIC: Enabling interrupts on APIC serial bus\n");
156 io_apic_write(ioapic_base, 0x03, 0);
160 void setup_ioapic(void *ioapic_base, u8 ioapic_id)
162 set_ioapic_id(ioapic_base, ioapic_id);
163 clear_vectors(ioapic_base, 0, ioapic_get_max_vectors(ioapic_base) - 1);
164 route_i8259_irq0(ioapic_base);