blob: 9c4bc7d6cef5a0a6c6db0ca13e448cc9c65ef16c [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;
21 u32 ioapic_base;
22 u8 ioapic_id;
23 if (!dev->enabled || !config)
24 return;
25
26 ioapic_base = config->base;
27 ioapic_id = config->apicid;
28
29 printk(BIOS_DEBUG, "IOAPIC: Initializing IOAPIC at 0x%08x\n",
30 ioapic_base);
31 printk(BIOS_DEBUG, "IOAPIC: Bootstrap Processor Local APIC = 0x%02x\n",
32 bsp_lapicid);
33
34 if (ioapic_id) {
35 printk(BIOS_DEBUG, "IOAPIC: ID = 0x%02x\n", ioapic_id);
36 /* Set IOAPIC ID if it has been specified. */
37 io_apic_write(ioapic_base, 0x00,
38 (io_apic_read(ioapic_base, 0x00) & 0xf0ffffff) |
39 (ioapic_id << 24));
40 }
41
42 /* Read the available number of interrupts. */
43 ioapic_interrupts = (io_apic_read(ioapic_base, 0x01) >> 16) & 0xff;
44 if (!ioapic_interrupts || ioapic_interrupts == 0xff)
45 ioapic_interrupts = 24;
46 printk(BIOS_DEBUG, "IOAPIC: %d interrupts\n", ioapic_interrupts);
47
48 if (config->irq_on_fsb) {
49 /*
50 * For the Pentium 4 and above APICs deliver their interrupts
51 * on the front side bus, enable that.
52 */
53 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on FSB\n");
54 io_apic_write(ioapic_base, 0x03,
55 io_apic_read(ioapic_base, 0x03) | (1 << 0));
56 } else {
57 printk(BIOS_DEBUG, "IOAPIC: Enabling interrupts on APIC serial bus\n");
58 io_apic_write(ioapic_base, 0x03, 0);
59 }
60
61 if (config->enable_virtual_wire) {
62 /* Enable Virtual Wire Mode. */
63 low = ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT;
64 high = bsp_lapicid << (56 - 32);
65
66 io_apic_write(ioapic_base, 0x10, low);
67 io_apic_write(ioapic_base, 0x11, high);
68
69 if (io_apic_read(ioapic_base, 0x10) == 0xffffffff) {
70 printk(BIOS_WARNING, "IOAPIC not responding.\n");
71 return;
72 }
73
74 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n", 0,
75 high, low);
76 }
77 low = DISABLED;
78 high = NONE;
79
80 for (i = 1; i < ioapic_interrupts; i++) {
81 io_apic_write(ioapic_base, i * 2 + 0x10, low);
82 io_apic_write(ioapic_base, i * 2 + 0x11, high);
83
84 printk(BIOS_SPEW, "IOAPIC: reg 0x%08x value 0x%08x 0x%08x\n",
85 i, high, low);
86 }
87}
88
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110089static void ioapic_enable_resources(struct device *dev)
Sven Schnelleaa03af72012-06-22 11:04:22 +020090{
91}
92
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110093static void ioapic_nop(struct device *dummy)
Sven Schnelleaa03af72012-06-22 11:04:22 +020094{
95}
96
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110097static void ioapic_read_resources(struct device *dev)
Sven Schnelleaa03af72012-06-22 11:04:22 +020098{
99 struct drivers_generic_ioapic_config *config = (struct drivers_generic_ioapic_config *)dev->chip_info;
100 struct resource *res;
101
102 res = new_resource(dev, 0);
103 res->base = config->base;
104 res->size = 0x1000;
105 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
106}
107
108static struct device_operations ioapic_operations = {
109 .read_resources = ioapic_read_resources,
110 .set_resources = ioapic_nop,
111 .enable_resources = ioapic_enable_resources,
112 .init = ioapic_init,
113};
114
115static void enable_dev(struct device *dev)
116{
117 dev->ops = &ioapic_operations;
118}
119
120struct chip_operations drivers_generic_ioapic_ops = {
121 CHIP_NAME("IOAPIC")
122 .enable_dev = enable_dev,
123};