blob: 44f1b0242463273465468097126adfc66a85cc06 [file] [log] [blame]
Sven Schnelleaa03af72012-06-22 11:04:22 +02001#include <console/console.h>
2#include <device/device.h>
3#include <device/smbus.h>
4#include <device/pci.h>
5#include <device/pci_ids.h>
6#include <device/pci_ops.h>
7#include <cpu/x86/msr.h>
8#include <reset.h>
9#include <delay.h>
10#include "chip.h"
11#include <arch/ioapic.h>
12#include <arch/io.h>
13#include <cpu/x86/lapic.h>
14
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110015static void ioapic_init(struct device *dev)
Sven Schnelleaa03af72012-06-22 11:04:22 +020016{
17 struct drivers_generic_ioapic_config *config = dev->chip_info;
18 u32 bsp_lapicid = lapicid();
19 u32 low, high;
20 u32 i, ioapic_interrupts;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080021 void *ioapic_base;
Sven Schnelleaa03af72012-06-22 11:04:22 +020022 u8 ioapic_id;
Edward O'Callaghan0d84a2c2014-11-07 12:43:49 +110023
Sven Schnelleaa03af72012-06-22 11:04:22 +020024 if (!dev->enabled || !config)
25 return;
26
27 ioapic_base = config->base;
28 ioapic_id = config->apicid;
29
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080030 printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%p\n",
Sven Schnelleaa03af72012-06-22 11:04:22 +020031 ioapic_base);
32 printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
33 bsp_lapicid);
34
35 if (ioapic_id) {
36 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
37 /* Set IOAPIC ID if it has been specified. */
38 io_apic_write(ioapic_base, 0x00,
39 (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
40 (ioapic_id << 24));
41 }
42
43 /* Read the available number of interrupts. */
44 ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
45 if (!ioapic_interrupts || ioapic_interrupts == 0xff)
46 ioapic_interrupts = 24;
47 printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
48
49 if (config->irq_on_fsb) {
50 /*
51 * For the Pentium 4 and above APICs deliver their interrupts
52 * on the front side bus, enable that.
53 */
54 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
55 io_apic_write(ioapic_base, 0x03,
56 io_apic_read(ioapic_base, 0x03) | (1 << 0));
57 } else {
58 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
59 io_apic_write(ioapic_base, 0x03, 0);
60 }
61
62 if (config->enable_virtual_wire) {
63 /* Enable Virtual Wire Mode. */
64 low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
65 high = bsp_lapicid << (56 - 32);
66
67 io_apic_write(ioapic_base, 0x10, low);
68 io_apic_write(ioapic_base, 0x11, high);
69
70 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
71 printk(BIOS_WARNING, "IOAPIC not responding.\n");
72 return;
73 }
74
75 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", 0,
76 high, low);
77 }
78 low = DISABLED;
79 high = NONE;
80
81 for (i = 1; i < ioapic_interrupts; i++) {
82 io_apic_write(ioapic_base, i * 2 + 0x10, low);
83 io_apic_write(ioapic_base, i * 2 + 0x11, high);
84
85 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
86 i, high, low);
87 }
88}
89
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110090static void ioapic_read_resources(struct device *dev)
Sven Schnelleaa03af72012-06-22 11:04:22 +020091{
92 struct drivers_generic_ioapic_config *config = (struct drivers_generic_ioapic_config *)dev->chip_info;
93 struct resource *res;
94
95 res = new_resource(dev, 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080096 res->base = (resource_t)(uintptr_t)config->base;
Sven Schnelleaa03af72012-06-22 11:04:22 +020097 res->size = 0x1000;
98 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
99}
100
101static struct device_operations ioapic_operations = {
Edward O'Callaghan0d84a2c2014-11-07 12:43:49 +1100102 .read_resources = ioapic_read_resources,
103 .set_resources = DEVICE_NOOP,
104 .enable_resources = DEVICE_NOOP,
105 .init = ioapic_init,
Sven Schnelleaa03af72012-06-22 11:04:22 +0200106};
107
108static void enable_dev(struct device *dev)
109{
110 dev->ops = &ioapic_operations;
111}
112
113struct chip_operations drivers_generic_ioapic_ops = {
114 CHIP_NAME("IOAPIC")
115 .enable_dev = enable_dev,
116};