blob: 25fc84c620f1e2989e43684e6eb52796e4d5ae1a [file] [log] [blame]
Stefan Reinauer0401bd82010-01-16 18:31:34 +00001/*
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.
Eric Biederman5899fd82003-04-24 06:25:08 +000014 */
Eric Biederman5899fd82003-04-24 06:25:08 +000015
Stefan Reinauer0401bd82010-01-16 18:31:34 +000016#include <arch/io.h>
17#include <arch/ioapic.h>
18#include <console/console.h>
19#include <cpu/x86/lapic.h>
20
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080021u32 io_apic_read(void *ioapic_base, u32 reg)
Eric Biederman5899fd82003-04-24 06:25:08 +000022{
Stefan Reinauer0401bd82010-01-16 18:31:34 +000023 write32(ioapic_base, reg);
24 return read32(ioapic_base + 0x10);
25}
Eric Biederman5899fd82003-04-24 06:25:08 +000026
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080027void io_apic_write(void *ioapic_base, u32 reg, u32 value)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000028{
29 write32(ioapic_base, reg);
30 write32(ioapic_base + 0x10, value);
31}
32
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080033static int ioapic_interrupt_count(void *ioapic_base)
Patrick Georgid1de45e2013-01-23 13:45:23 +010034{
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
41 minus 1. */
42 printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
43
44 return ioapic_interrupts;
45}
46
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080047void clear_ioapic(void *ioapic_base)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000048{
49 u32 low, high;
50 u32 i, ioapic_interrupts;
51
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080052 printk(BIOS_DEBUG, "IOAPIC: Clearing IOAPIC at %p\n", ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000053
Patrick Georgid1de45e2013-01-23 13:45:23 +010054 ioapic_interrupts = ioapic_interrupt_count(ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000055
56 low = DISABLED;
57 high = NONE;
58
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);
62
Uwe Hermanne49903652010-10-14 23:40:10 +000063 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
64 i, high, low);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000065 }
66
67 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
Uwe Hermanne49903652010-10-14 23:40:10 +000068 printk(BIOS_WARNING, "IOAPIC not responding.\n");
Stefan Reinauer0401bd82010-01-16 18:31:34 +000069 return;
70 }
71}
72
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080073void set_ioapic_id(void *ioapic_base, u8 ioapic_id)
Stefan Reinauer0401bd82010-01-16 18:31:34 +000074{
75 u32 bsp_lapicid = lapicid();
Paul Menzel1b3e1762013-04-23 14:49:41 +020076 int i;
Stefan Reinauer0401bd82010-01-16 18:31:34 +000077
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080078 printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%p\n",
Uwe Hermanne49903652010-10-14 23:40:10 +000079 ioapic_base);
80 printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
81 bsp_lapicid);
Stefan Reinauer0401bd82010-01-16 18:31:34 +000082
83 if (ioapic_id) {
Stefan Reinauer14e22772010-04-27 06:56:47 +000084 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
Uwe Hermanne49903652010-10-14 23:40:10 +000085 /* Set IOAPIC ID if it has been specified. */
Stefan Reinauer14e22772010-04-27 06:56:47 +000086 io_apic_write(ioapic_base, 0x00,
Kyösti Mälkki939103c2011-10-19 07:23:51 +030087 (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
Uwe Hermanne49903652010-10-14 23:40:10 +000088 (ioapic_id << 24));
Stefan Reinauer0401bd82010-01-16 18:31:34 +000089 }
Paul Menzel1b3e1762013-04-23 14:49:41 +020090
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));
95
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +020096}
97
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080098static void load_vectors(void *ioapic_base)
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +020099{
100 u32 bsp_lapicid = lapicid();
101 u32 low, high;
102 u32 i, ioapic_interrupts;
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000103
Patrick Georgid1de45e2013-01-23 13:45:23 +0100104 ioapic_interrupts = ioapic_interrupt_count(ioapic_base);
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000105
Rudolf Marekeeb8a062012-04-22 23:52:23 +0200106#if CONFIG_IOAPIC_INTERRUPTS_ON_FSB
Uwe Hermanne49903652010-10-14 23:40:10 +0000107 /*
108 * For the Pentium 4 and above APICs deliver their interrupts
Eric Biederman5899fd82003-04-24 06:25:08 +0000109 * on the front side bus, enable that.
110 */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000111 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
Uwe Hermanne49903652010-10-14 23:40:10 +0000112 io_apic_write(ioapic_base, 0x03,
113 io_apic_read(ioapic_base, 0x03) | (1 << 0));
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000114#endif
Rudolf Marekeeb8a062012-04-22 23:52:23 +0200115#if CONFIG_IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS
Stefan Reinauer14e22772010-04-27 06:56:47 +0000116 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000117 io_apic_write(ioapic_base, 0x03, 0);
118#endif
119
Uwe Hermanne49903652010-10-14 23:40:10 +0000120 /* Enable Virtual Wire Mode. */
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000121 low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
122 high = bsp_lapicid << (56 - 32);
123
124 io_apic_write(ioapic_base, 0x10, low);
125 io_apic_write(ioapic_base, 0x11, high);
126
127 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
Uwe Hermanne49903652010-10-14 23:40:10 +0000128 printk(BIOS_WARNING, "IOAPIC not responding.\n");
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000129 return;
130 }
131
Uwe Hermanne49903652010-10-14 23:40:10 +0000132 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
133 0, high, low);
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000134 low = DISABLED;
135 high = NONE;
Stefan Reinauer0401bd82010-01-16 18:31:34 +0000136 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);
139
Uwe Hermanne49903652010-10-14 23:40:10 +0000140 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
141 i, high, low);
Eric Biederman5899fd82003-04-24 06:25:08 +0000142 }
143}
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200144
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800145void setup_ioapic(void *ioapic_base, u8 ioapic_id)
Kyösti Mälkkidb4f8752012-01-31 17:24:12 +0200146{
147 set_ioapic_id(ioapic_base, ioapic_id);
148 load_vectors(ioapic_base);
149}