1 /* SPDX-License-Identifier: GPL-2.0-only */
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",
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
)
37 reg
= io_apic_read(ioapic_base
, 0x01);
38 count
= (reg
>> 16) & 0xff;
44 printk(BIOS_DEBUG
, "IOAPIC: %d interrupts\n", 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
)
56 reg
= io_apic_read(ioapic_base
, 0x01);
57 count
= (reg
>> 16) & 0xff;
59 count
= mre_count
- 1;
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
)
75 printk(BIOS_DEBUG
, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base
);
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");
89 static void route_i8259_irq0(void *ioapic_base
)
91 u32 bsp_lapicid
= lapicid();
94 ASSERT(bsp_lapicid
< 255);
96 printk(BIOS_DEBUG
, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
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");
111 void set_ioapic_id(void *ioapic_base
, u8 ioapic_id
)
115 printk(BIOS_DEBUG
, "IOAPIC: Initializing IOAPIC at %p\n",
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) |
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
)
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));
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
);