blob: 6a0f0d222f823eedddb68b3ef5d6406ff21cffeb [file] [log] [blame]
Yinghai Lu70093f72004-07-01 03:55:03 +00001#include <console/console.h>
2#include <device/device.h>
3#include <device/pci.h>
4#include <device/pci_ids.h>
5#include <device/pci_ops.h>
6#include <pc80/mc146818rtc.h>
Steven J. Magnani09e4ef62005-09-14 13:56:25 +00007#include <assert.h>
Yinghai Lu70093f72004-07-01 03:55:03 +00008#include "82870.h"
9
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000010static int num_p64h2_ioapics = 0;
Yinghai Lu70093f72004-07-01 03:55:03 +000011
12static void p64h2_ioapic_enable(device_t dev)
13{
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000014 /* We have to enable MEM and Bus Master for IOAPIC */
15 uint16_t command = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
Yinghai Lu70093f72004-07-01 03:55:03 +000016
17
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000018 pci_write_config16(dev, PCI_COMMAND, command);
Yinghai Lu70093f72004-07-01 03:55:03 +000019}
20
Uwe Hermannb69cb5a2010-10-26 22:46:43 +000021/**
22 * Configure one of the IOAPICs in a P64H2.
23 *
24 * Note that a PCI bus scan will detect both IOAPICs, so this function
25 * will be called twice for each P64H2 in the system.
26 *
27 * @param dev PCI bus/device/function of P64H2 IOAPIC.
28 * NOTE: There are two IOAPICs per P64H2, at D28:F0 and D30:F0.
29 */
Yinghai Lu70093f72004-07-01 03:55:03 +000030static void p64h2_ioapic_init(device_t dev)
31{
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000032 uint32_t memoryBase;
33 int apic_index, apic_id;
Yinghai Lu70093f72004-07-01 03:55:03 +000034
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000035 volatile uint32_t* pIndexRegister; /* io apic io memory space command address */
36 volatile uint32_t* pWindowRegister; /* io apic io memory space data address */
Yinghai Lu70093f72004-07-01 03:55:03 +000037
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000038 apic_index = num_p64h2_ioapics;
39 num_p64h2_ioapics++;
Yinghai Lu70093f72004-07-01 03:55:03 +000040
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000041 // A note on IOAPIC addresses:
Stefan Reinauer14e22772010-04-27 06:56:47 +000042 // 0 and 1 are used for the local APICs of the dual virtual
Uwe Hermann607614d2010-11-18 20:12:13 +000043 // (hyper-threaded) CPUs of physical CPU 0 (devicetree.cb).
Stefan Reinauer14e22772010-04-27 06:56:47 +000044 // 6 and 7 are used for the local APICs of the dual virtual
Uwe Hermann607614d2010-11-18 20:12:13 +000045 // (hyper-threaded) CPUs of physical CPU 1 (devicetree.cb).
46 // 2 is used for the IOAPIC in the 82801 southbridge (hard-coded in i82801xx_lpc.c)
Yinghai Lu70093f72004-07-01 03:55:03 +000047
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000048 // Map APIC index into APIC ID
49 // IDs 3, 4, 5, and 8+ are available (see above note)
Yinghai Lu70093f72004-07-01 03:55:03 +000050
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000051 if (apic_index < 3)
52 apic_id = apic_index + 3;
53 else
54 apic_id = apic_index + 5;
Yinghai Lu70093f72004-07-01 03:55:03 +000055
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000056 ASSERT(apic_id < 16); // ID is only 4 bits
Yinghai Lu70093f72004-07-01 03:55:03 +000057
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000058 // Read the MBAR address for setting up the IOAPIC in memory space
59 // NOTE: this address was assigned during enumeration of the bus
60
61 memoryBase = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
62 pIndexRegister = (volatile uint32_t*) memoryBase;
63 pWindowRegister = (volatile uint32_t*)(memoryBase + 0x10);
64
Myles Watson08e0fb82010-03-22 16:33:25 +000065 printk(BIOS_DEBUG, "IOAPIC %d at %02x:%02x.%01x MBAR = %p DataAddr = %p\n",
Stefan Reinauer14e22772010-04-27 06:56:47 +000066 apic_id, dev->bus->secondary, PCI_SLOT(dev->path.pci.devfn),
Stefan Reinauer2b34db82009-02-28 20:10:20 +000067 PCI_FUNC(dev->path.pci.devfn), pIndexRegister, pWindowRegister);
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000068
69 apic_id <<= 24; // Convert ID to bitmask
70
71 *pIndexRegister = 0; // Select APIC ID register
72 *pWindowRegister = (*pWindowRegister & ~(0xF<<24)) | apic_id; // Set the ID
73
74 if ((*pWindowRegister & (0xF<<24)) != apic_id)
Stefan Reinauer14e22772010-04-27 06:56:47 +000075 die("p64h2_ioapic_init failed");
Steven J. Magnani09e4ef62005-09-14 13:56:25 +000076
77 *pIndexRegister = 3; // Select Boot Configuration register
78 *pWindowRegister |= 1; // Use Processor System Bus to deliver interrupts
79
80 if (!(*pWindowRegister & 1))
Stefan Reinauer14e22772010-04-27 06:56:47 +000081 die("p64h2_ioapic_init failed");
Yinghai Lu70093f72004-07-01 03:55:03 +000082}
83
84static struct device_operations ioapic_ops = {
85 .read_resources = pci_dev_read_resources,
86 .set_resources = pci_dev_set_resources,
87 .enable_resources = pci_dev_enable_resources,
88 .init = p64h2_ioapic_init,
89 .scan_bus = 0,
90 .enable = p64h2_ioapic_enable,
91};
92
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +000093static const struct pci_driver ioapic_driver __pci_driver = {
Yinghai Lu70093f72004-07-01 03:55:03 +000094 .ops = &ioapic_ops,
95 .vendor = PCI_VENDOR_ID_INTEL,
96 .device = PCI_DEVICE_ID_INTEL_82870_1E0,
97
98};