blob: c8be60645887f44a4ed4a734fc3a51d5062c369b [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Martin Rothcddd6002019-09-23 17:38:27 -06003
Sven Schnelleaa03af72012-06-22 11:04:22 +02004#include <console/console.h>
5#include <device/device.h>
Sven Schnelleaa03af72012-06-22 11:04:22 +02006#include "chip.h"
7#include <arch/ioapic.h>
Sven Schnelleaa03af72012-06-22 11:04:22 +02008#include <cpu/x86/lapic.h>
9
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110010static void ioapic_init(struct device *dev)
Sven Schnelleaa03af72012-06-22 11:04:22 +020011{
12 struct drivers_generic_ioapic_config *config = dev->chip_info;
13 u32 bsp_lapicid = lapicid();
14 u32 low, high;
15 u32 i, ioapic_interrupts;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080016 void *ioapic_base;
Sven Schnelleaa03af72012-06-22 11:04:22 +020017 u8 ioapic_id;
Edward O'Callaghan0d84a2c2014-11-07 12:43:49 +110018
Sven Schnelleaa03af72012-06-22 11:04:22 +020019 if (!dev->enabled || !config)
20 return;
21
22 ioapic_base = config->base;
23 ioapic_id = config->apicid;
24
Julius Werner540a9802019-12-09 13:03:29 -080025 printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at %p\n",
Sven Schnelleaa03af72012-06-22 11:04:22 +020026 ioapic_base);
27 printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
28 bsp_lapicid);
29
30 if (ioapic_id) {
31 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
32 /* Set IOAPIC ID if it has been specified. */
33 io_apic_write(ioapic_base, 0x00,
34 (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
35 (ioapic_id << 24));
36 }
37
38 /* Read the available number of interrupts. */
39 ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
40 if (!ioapic_interrupts || ioapic_interrupts == 0xff)
41 ioapic_interrupts = 24;
42 printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
43
44 if (config->irq_on_fsb) {
45 /*
46 * For the Pentium 4 and above APICs deliver their interrupts
47 * on the front side bus, enable that.
48 */
49 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
50 io_apic_write(ioapic_base, 0x03,
51 io_apic_read(ioapic_base, 0x03) | (1 << 0));
52 } else {
53 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
54 io_apic_write(ioapic_base, 0x03, 0);
55 }
56
57 if (config->enable_virtual_wire) {
58 /* Enable Virtual Wire Mode. */
Marc Jonesf7dc9722018-03-31 22:45:35 -060059 low = INT_ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
Sven Schnelleaa03af72012-06-22 11:04:22 +020060 high = bsp_lapicid << (56 - 32);
61
62 io_apic_write(ioapic_base, 0x10, low);
63 io_apic_write(ioapic_base, 0x11, high);
64
65 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
66 printk(BIOS_WARNING, "IOAPIC not responding.\n");
67 return;
68 }
69
70 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", 0,
71 high, low);
72 }
Marc Jonesf7dc9722018-03-31 22:45:35 -060073 low = INT_DISABLED;
Sven Schnelleaa03af72012-06-22 11:04:22 +020074 high = NONE;
75
76 for (i = 1; i < ioapic_interrupts; i++) {
77 io_apic_write(ioapic_base, i * 2 + 0x10, low);
78 io_apic_write(ioapic_base, i * 2 + 0x11, high);
79
80 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
81 i, high, low);
82 }
83}
84
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110085static void ioapic_read_resources(struct device *dev)
Sven Schnelleaa03af72012-06-22 11:04:22 +020086{
87 struct drivers_generic_ioapic_config *config = (struct drivers_generic_ioapic_config *)dev->chip_info;
88 struct resource *res;
89
90 res = new_resource(dev, 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080091 res->base = (resource_t)(uintptr_t)config->base;
Sven Schnelleaa03af72012-06-22 11:04:22 +020092 res->size = 0x1000;
93 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
94}
95
96static struct device_operations ioapic_operations = {
Edward O'Callaghan0d84a2c2014-11-07 12:43:49 +110097 .read_resources = ioapic_read_resources,
Nico Huber2f8ba692020-04-05 14:05:24 +020098 .set_resources = noop_set_resources,
Edward O'Callaghan0d84a2c2014-11-07 12:43:49 +110099 .init = ioapic_init,
Sven Schnelleaa03af72012-06-22 11:04:22 +0200100};
101
102static void enable_dev(struct device *dev)
103{
104 dev->ops = &ioapic_operations;
105}
106
107struct chip_operations drivers_generic_ioapic_ops = {
108 CHIP_NAME("IOAPIC")
109 .enable_dev = enable_dev,
110};