1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
27f5df8d4SBin Meng /*
37f5df8d4SBin Meng * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
47f5df8d4SBin Meng *
57f5df8d4SBin Meng * Adapted from coreboot src/arch/x86/boot/mpspec.c
67f5df8d4SBin Meng */
77f5df8d4SBin Meng
87f5df8d4SBin Meng #include <common.h>
97f5df8d4SBin Meng #include <cpu.h>
107f5df8d4SBin Meng #include <dm.h>
1107545d86SBin Meng #include <errno.h>
1207545d86SBin Meng #include <fdtdec.h>
137f5df8d4SBin Meng #include <asm/cpu.h>
1407545d86SBin Meng #include <asm/irq.h>
157f5df8d4SBin Meng #include <asm/ioapic.h>
167f5df8d4SBin Meng #include <asm/lapic.h>
177f5df8d4SBin Meng #include <asm/mpspec.h>
187f5df8d4SBin Meng #include <asm/tables.h>
197f5df8d4SBin Meng #include <dm/uclass-internal.h>
207f5df8d4SBin Meng
2107545d86SBin Meng DECLARE_GLOBAL_DATA_PTR;
2207545d86SBin Meng
2353832bb8SBin Meng static bool isa_irq_occupied[16];
2453832bb8SBin Meng
mp_write_floating_table(struct mp_floating_table * mf)257f5df8d4SBin Meng struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf)
267f5df8d4SBin Meng {
27e71ffd09SSimon Glass ulong mc;
287f5df8d4SBin Meng
297f5df8d4SBin Meng memcpy(mf->mpf_signature, MPF_SIGNATURE, 4);
30e71ffd09SSimon Glass mf->mpf_physptr = (ulong)mf + sizeof(struct mp_floating_table);
317f5df8d4SBin Meng mf->mpf_length = 1;
327f5df8d4SBin Meng mf->mpf_spec = MPSPEC_V14;
337f5df8d4SBin Meng mf->mpf_checksum = 0;
347f5df8d4SBin Meng /* We don't use the default configuration table */
357f5df8d4SBin Meng mf->mpf_feature1 = 0;
367f5df8d4SBin Meng /* Indicate that virtual wire mode is always implemented */
377f5df8d4SBin Meng mf->mpf_feature2 = 0;
387f5df8d4SBin Meng mf->mpf_feature3 = 0;
397f5df8d4SBin Meng mf->mpf_feature4 = 0;
407f5df8d4SBin Meng mf->mpf_feature5 = 0;
417f5df8d4SBin Meng mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16);
427f5df8d4SBin Meng
43e71ffd09SSimon Glass mc = (ulong)mf + sizeof(struct mp_floating_table);
447f5df8d4SBin Meng return (struct mp_config_table *)mc;
457f5df8d4SBin Meng }
467f5df8d4SBin Meng
mp_config_table_init(struct mp_config_table * mc)477f5df8d4SBin Meng void mp_config_table_init(struct mp_config_table *mc)
487f5df8d4SBin Meng {
497f5df8d4SBin Meng memcpy(mc->mpc_signature, MPC_SIGNATURE, 4);
507f5df8d4SBin Meng mc->mpc_length = sizeof(struct mp_config_table);
517f5df8d4SBin Meng mc->mpc_spec = MPSPEC_V14;
527f5df8d4SBin Meng mc->mpc_checksum = 0;
537f5df8d4SBin Meng mc->mpc_oemptr = 0;
547f5df8d4SBin Meng mc->mpc_oemsize = 0;
557f5df8d4SBin Meng mc->mpc_entry_count = 0;
567f5df8d4SBin Meng mc->mpc_lapic = LAPIC_DEFAULT_BASE;
577f5df8d4SBin Meng mc->mpe_length = 0;
587f5df8d4SBin Meng mc->mpe_checksum = 0;
597f5df8d4SBin Meng mc->reserved = 0;
607f5df8d4SBin Meng
617f5df8d4SBin Meng /* The oem/product id fields are exactly 8/12 bytes long */
627f5df8d4SBin Meng table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' ');
637f5df8d4SBin Meng table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' ');
647f5df8d4SBin Meng }
657f5df8d4SBin Meng
mp_write_processor(struct mp_config_table * mc)667f5df8d4SBin Meng void mp_write_processor(struct mp_config_table *mc)
677f5df8d4SBin Meng {
687f5df8d4SBin Meng struct mpc_config_processor *mpc;
697f5df8d4SBin Meng struct udevice *dev;
707f5df8d4SBin Meng u8 boot_apicid, apicver;
717f5df8d4SBin Meng u32 cpusignature, cpufeature;
727f5df8d4SBin Meng struct cpuid_result result;
737f5df8d4SBin Meng
747f5df8d4SBin Meng boot_apicid = lapicid();
757f5df8d4SBin Meng apicver = lapic_read(LAPIC_LVR) & 0xff;
767f5df8d4SBin Meng result = cpuid(1);
777f5df8d4SBin Meng cpusignature = result.eax;
787f5df8d4SBin Meng cpufeature = result.edx;
797f5df8d4SBin Meng
807f5df8d4SBin Meng for (uclass_find_first_device(UCLASS_CPU, &dev);
817f5df8d4SBin Meng dev;
827f5df8d4SBin Meng uclass_find_next_device(&dev)) {
837f5df8d4SBin Meng struct cpu_platdata *plat = dev_get_parent_platdata(dev);
847f5df8d4SBin Meng u8 cpuflag = MPC_CPU_EN;
857f5df8d4SBin Meng
867f5df8d4SBin Meng if (!device_active(dev))
877f5df8d4SBin Meng continue;
887f5df8d4SBin Meng
897f5df8d4SBin Meng mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc);
907f5df8d4SBin Meng mpc->mpc_type = MP_PROCESSOR;
917f5df8d4SBin Meng mpc->mpc_apicid = plat->cpu_id;
927f5df8d4SBin Meng mpc->mpc_apicver = apicver;
937f5df8d4SBin Meng if (boot_apicid == plat->cpu_id)
947f5df8d4SBin Meng cpuflag |= MPC_CPU_BP;
957f5df8d4SBin Meng mpc->mpc_cpuflag = cpuflag;
967f5df8d4SBin Meng mpc->mpc_cpusignature = cpusignature;
977f5df8d4SBin Meng mpc->mpc_cpufeature = cpufeature;
987f5df8d4SBin Meng mpc->mpc_reserved[0] = 0;
997f5df8d4SBin Meng mpc->mpc_reserved[1] = 0;
1007f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc));
1017f5df8d4SBin Meng }
1027f5df8d4SBin Meng }
1037f5df8d4SBin Meng
mp_write_bus(struct mp_config_table * mc,int id,const char * bustype)1047f5df8d4SBin Meng void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype)
1057f5df8d4SBin Meng {
1067f5df8d4SBin Meng struct mpc_config_bus *mpc;
1077f5df8d4SBin Meng
1087f5df8d4SBin Meng mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc);
1097f5df8d4SBin Meng mpc->mpc_type = MP_BUS;
1107f5df8d4SBin Meng mpc->mpc_busid = id;
1117f5df8d4SBin Meng memcpy(mpc->mpc_bustype, bustype, 6);
1127f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc));
1137f5df8d4SBin Meng }
1147f5df8d4SBin Meng
mp_write_ioapic(struct mp_config_table * mc,int id,int ver,u32 apicaddr)1157f5df8d4SBin Meng void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr)
1167f5df8d4SBin Meng {
1177f5df8d4SBin Meng struct mpc_config_ioapic *mpc;
1187f5df8d4SBin Meng
1197f5df8d4SBin Meng mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc);
1207f5df8d4SBin Meng mpc->mpc_type = MP_IOAPIC;
1217f5df8d4SBin Meng mpc->mpc_apicid = id;
1227f5df8d4SBin Meng mpc->mpc_apicver = ver;
1237f5df8d4SBin Meng mpc->mpc_flags = MPC_APIC_USABLE;
1247f5df8d4SBin Meng mpc->mpc_apicaddr = apicaddr;
1257f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc));
1267f5df8d4SBin Meng }
1277f5df8d4SBin Meng
mp_write_intsrc(struct mp_config_table * mc,int irqtype,int irqflag,int srcbus,int srcbusirq,int dstapic,int dstirq)1287f5df8d4SBin Meng void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag,
1297f5df8d4SBin Meng int srcbus, int srcbusirq, int dstapic, int dstirq)
1307f5df8d4SBin Meng {
1317f5df8d4SBin Meng struct mpc_config_intsrc *mpc;
1327f5df8d4SBin Meng
1337f5df8d4SBin Meng mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc);
1347f5df8d4SBin Meng mpc->mpc_type = MP_INTSRC;
1357f5df8d4SBin Meng mpc->mpc_irqtype = irqtype;
1367f5df8d4SBin Meng mpc->mpc_irqflag = irqflag;
1377f5df8d4SBin Meng mpc->mpc_srcbus = srcbus;
1387f5df8d4SBin Meng mpc->mpc_srcbusirq = srcbusirq;
1397f5df8d4SBin Meng mpc->mpc_dstapic = dstapic;
1407f5df8d4SBin Meng mpc->mpc_dstirq = dstirq;
1417f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc));
1427f5df8d4SBin Meng }
1437f5df8d4SBin Meng
mp_write_pci_intsrc(struct mp_config_table * mc,int irqtype,int srcbus,int dev,int pin,int dstapic,int dstirq)1447f5df8d4SBin Meng void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype,
1457f5df8d4SBin Meng int srcbus, int dev, int pin, int dstapic, int dstirq)
1467f5df8d4SBin Meng {
1477f5df8d4SBin Meng u8 srcbusirq = (dev << 2) | (pin - 1);
1487f5df8d4SBin Meng
1497f5df8d4SBin Meng mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW,
1507f5df8d4SBin Meng srcbus, srcbusirq, dstapic, dstirq);
1517f5df8d4SBin Meng }
1527f5df8d4SBin Meng
mp_write_lintsrc(struct mp_config_table * mc,int irqtype,int irqflag,int srcbus,int srcbusirq,int destapic,int destlint)1537f5df8d4SBin Meng void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag,
1547f5df8d4SBin Meng int srcbus, int srcbusirq, int destapic, int destlint)
1557f5df8d4SBin Meng {
1567f5df8d4SBin Meng struct mpc_config_lintsrc *mpc;
1577f5df8d4SBin Meng
1587f5df8d4SBin Meng mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc);
1597f5df8d4SBin Meng mpc->mpc_type = MP_LINTSRC;
1607f5df8d4SBin Meng mpc->mpc_irqtype = irqtype;
1617f5df8d4SBin Meng mpc->mpc_irqflag = irqflag;
1627f5df8d4SBin Meng mpc->mpc_srcbusid = srcbus;
1637f5df8d4SBin Meng mpc->mpc_srcbusirq = srcbusirq;
1647f5df8d4SBin Meng mpc->mpc_destapic = destapic;
1657f5df8d4SBin Meng mpc->mpc_destlint = destlint;
1667f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc));
1677f5df8d4SBin Meng }
1687f5df8d4SBin Meng
mp_write_address_space(struct mp_config_table * mc,int busid,int addr_type,u32 addr_base_low,u32 addr_base_high,u32 addr_length_low,u32 addr_length_high)1697f5df8d4SBin Meng void mp_write_address_space(struct mp_config_table *mc,
1707f5df8d4SBin Meng int busid, int addr_type,
1717f5df8d4SBin Meng u32 addr_base_low, u32 addr_base_high,
1727f5df8d4SBin Meng u32 addr_length_low, u32 addr_length_high)
1737f5df8d4SBin Meng {
1747f5df8d4SBin Meng struct mp_ext_system_address_space *mpe;
1757f5df8d4SBin Meng
1767f5df8d4SBin Meng mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc);
1777f5df8d4SBin Meng mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
1787f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe);
1797f5df8d4SBin Meng mpe->mpe_busid = busid;
1807f5df8d4SBin Meng mpe->mpe_addr_type = addr_type;
1817f5df8d4SBin Meng mpe->mpe_addr_base_low = addr_base_low;
1827f5df8d4SBin Meng mpe->mpe_addr_base_high = addr_base_high;
1837f5df8d4SBin Meng mpe->mpe_addr_length_low = addr_length_low;
1847f5df8d4SBin Meng mpe->mpe_addr_length_high = addr_length_high;
1857f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe);
1867f5df8d4SBin Meng }
1877f5df8d4SBin Meng
mp_write_bus_hierarchy(struct mp_config_table * mc,int busid,int bus_info,int parent_busid)1887f5df8d4SBin Meng void mp_write_bus_hierarchy(struct mp_config_table *mc,
1897f5df8d4SBin Meng int busid, int bus_info, int parent_busid)
1907f5df8d4SBin Meng {
1917f5df8d4SBin Meng struct mp_ext_bus_hierarchy *mpe;
1927f5df8d4SBin Meng
1937f5df8d4SBin Meng mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc);
1947f5df8d4SBin Meng mpe->mpe_type = MPE_BUS_HIERARCHY;
1957f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe);
1967f5df8d4SBin Meng mpe->mpe_busid = busid;
1977f5df8d4SBin Meng mpe->mpe_bus_info = bus_info;
1987f5df8d4SBin Meng mpe->mpe_parent_busid = parent_busid;
1997f5df8d4SBin Meng mpe->reserved[0] = 0;
2007f5df8d4SBin Meng mpe->reserved[1] = 0;
2017f5df8d4SBin Meng mpe->reserved[2] = 0;
2027f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe);
2037f5df8d4SBin Meng }
2047f5df8d4SBin Meng
mp_write_compat_address_space(struct mp_config_table * mc,int busid,int addr_modifier,u32 range_list)2057f5df8d4SBin Meng void mp_write_compat_address_space(struct mp_config_table *mc, int busid,
2067f5df8d4SBin Meng int addr_modifier, u32 range_list)
2077f5df8d4SBin Meng {
2087f5df8d4SBin Meng struct mp_ext_compat_address_space *mpe;
2097f5df8d4SBin Meng
2107f5df8d4SBin Meng mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc);
2117f5df8d4SBin Meng mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE;
2127f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe);
2137f5df8d4SBin Meng mpe->mpe_busid = busid;
2147f5df8d4SBin Meng mpe->mpe_addr_modifier = addr_modifier;
2157f5df8d4SBin Meng mpe->mpe_range_list = range_list;
2167f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe);
2177f5df8d4SBin Meng }
2187f5df8d4SBin Meng
mptable_finalize(struct mp_config_table * mc)2197f5df8d4SBin Meng u32 mptable_finalize(struct mp_config_table *mc)
2207f5df8d4SBin Meng {
221e71ffd09SSimon Glass ulong end;
2227f5df8d4SBin Meng
2237f5df8d4SBin Meng mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc),
2247f5df8d4SBin Meng mc->mpe_length);
2257f5df8d4SBin Meng mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length);
2267f5df8d4SBin Meng end = mp_next_mpe_entry(mc);
2277f5df8d4SBin Meng
228e71ffd09SSimon Glass debug("Write the MP table at: %lx - %lx\n", (ulong)mc, end);
2297f5df8d4SBin Meng
2307f5df8d4SBin Meng return end;
2317f5df8d4SBin Meng }
23207545d86SBin Meng
mptable_add_isa_interrupts(struct mp_config_table * mc,int bus_isa,int apicid,int external_int2)23307545d86SBin Meng static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa,
23407545d86SBin Meng int apicid, int external_int2)
23507545d86SBin Meng {
23607545d86SBin Meng int i;
23707545d86SBin Meng
23807545d86SBin Meng mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT,
23907545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
24007545d86SBin Meng bus_isa, 0, apicid, 0);
24107545d86SBin Meng mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
24207545d86SBin Meng bus_isa, 1, apicid, 1);
24307545d86SBin Meng mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT,
24407545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
24507545d86SBin Meng bus_isa, 0, apicid, 2);
24607545d86SBin Meng
24753832bb8SBin Meng for (i = 3; i < 16; i++) {
24853832bb8SBin Meng /*
24953832bb8SBin Meng * Do not write ISA interrupt entry if it is already occupied
25053832bb8SBin Meng * by the platform devices.
25153832bb8SBin Meng */
25253832bb8SBin Meng if (isa_irq_occupied[i])
25353832bb8SBin Meng continue;
25453832bb8SBin Meng
25507545d86SBin Meng mp_write_intsrc(mc, MP_INT,
25607545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
25707545d86SBin Meng bus_isa, i, apicid, i);
25807545d86SBin Meng }
25953832bb8SBin Meng }
26007545d86SBin Meng
26107545d86SBin Meng /*
26207545d86SBin Meng * Check duplicated I/O interrupt assignment table entry, to make sure
26307545d86SBin Meng * there is only one entry with the given bus, device and interrupt pin.
26407545d86SBin Meng */
check_dup_entry(struct mpc_config_intsrc * intsrc_base,int entry_num,int bus,int device,int pin)26507545d86SBin Meng static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base,
26607545d86SBin Meng int entry_num, int bus, int device, int pin)
26707545d86SBin Meng {
26807545d86SBin Meng struct mpc_config_intsrc *intsrc = intsrc_base;
26907545d86SBin Meng int i;
27007545d86SBin Meng
27107545d86SBin Meng for (i = 0; i < entry_num; i++) {
27207545d86SBin Meng if (intsrc->mpc_srcbus == bus &&
27307545d86SBin Meng intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1)))
27407545d86SBin Meng break;
27507545d86SBin Meng intsrc++;
27607545d86SBin Meng }
27707545d86SBin Meng
27807545d86SBin Meng return (i == entry_num) ? false : true;
27907545d86SBin Meng }
28007545d86SBin Meng
281abab9128SBin Meng /* TODO: move this to driver model */
mp_determine_pci_dstirq(int bus,int dev,int func,int pirq)282abab9128SBin Meng __weak int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq)
283abab9128SBin Meng {
284abab9128SBin Meng /* PIRQ[A-H] are connected to I/O APIC INTPIN#16-23 */
285abab9128SBin Meng return pirq + 16;
286abab9128SBin Meng }
287abab9128SBin Meng
mptable_add_intsrc(struct mp_config_table * mc,int bus_isa,int apicid)28807545d86SBin Meng static int mptable_add_intsrc(struct mp_config_table *mc,
28907545d86SBin Meng int bus_isa, int apicid)
29007545d86SBin Meng {
29107545d86SBin Meng struct mpc_config_intsrc *intsrc_base;
29207545d86SBin Meng int intsrc_entries = 0;
29307545d86SBin Meng const void *blob = gd->fdt_blob;
294b565d66dSSimon Glass struct udevice *dev;
29507545d86SBin Meng int len, count;
29607545d86SBin Meng const u32 *cell;
297b565d66dSSimon Glass int i, ret;
29807545d86SBin Meng
2993f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_IRQ, &dev);
300b565d66dSSimon Glass if (ret && ret != -ENODEV) {
30107545d86SBin Meng debug("%s: Cannot find irq router node\n", __func__);
302b565d66dSSimon Glass return ret;
30307545d86SBin Meng }
30407545d86SBin Meng
305b565d66dSSimon Glass /* Get I/O interrupt information from device tree */
306e160f7d4SSimon Glass cell = fdt_getprop(blob, dev_of_offset(dev), "intel,pirq-routing",
307e160f7d4SSimon Glass &len);
30807545d86SBin Meng if (!cell)
30907545d86SBin Meng return -ENOENT;
31007545d86SBin Meng
31107545d86SBin Meng if ((len % sizeof(struct pirq_routing)) == 0)
31207545d86SBin Meng count = len / sizeof(struct pirq_routing);
31307545d86SBin Meng else
31407545d86SBin Meng return -EINVAL;
31507545d86SBin Meng
31607545d86SBin Meng intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc);
31707545d86SBin Meng
31807545d86SBin Meng for (i = 0; i < count; i++) {
31907545d86SBin Meng struct pirq_routing pr;
320abab9128SBin Meng int bus, dev, func;
321abab9128SBin Meng int dstirq;
32207545d86SBin Meng
32307545d86SBin Meng pr.bdf = fdt_addr_to_cpu(cell[0]);
32407545d86SBin Meng pr.pin = fdt_addr_to_cpu(cell[1]);
32507545d86SBin Meng pr.pirq = fdt_addr_to_cpu(cell[2]);
326abab9128SBin Meng bus = PCI_BUS(pr.bdf);
327abab9128SBin Meng dev = PCI_DEV(pr.bdf);
328abab9128SBin Meng func = PCI_FUNC(pr.bdf);
32907545d86SBin Meng
33007545d86SBin Meng if (check_dup_entry(intsrc_base, intsrc_entries,
331abab9128SBin Meng bus, dev, pr.pin)) {
33207545d86SBin Meng debug("found entry for bus %d device %d INT%c, skipping\n",
333abab9128SBin Meng bus, dev, 'A' + pr.pin - 1);
33407545d86SBin Meng cell += sizeof(struct pirq_routing) / sizeof(u32);
33507545d86SBin Meng continue;
33607545d86SBin Meng }
33707545d86SBin Meng
338abab9128SBin Meng dstirq = mp_determine_pci_dstirq(bus, dev, func, pr.pirq);
33953832bb8SBin Meng /*
34053832bb8SBin Meng * For PIRQ which is connected to I/O APIC interrupt pin#0-15,
34153832bb8SBin Meng * mark it as occupied so that we can skip it later.
34253832bb8SBin Meng */
34353832bb8SBin Meng if (dstirq < 16)
34453832bb8SBin Meng isa_irq_occupied[dstirq] = true;
345abab9128SBin Meng mp_write_pci_intsrc(mc, MP_INT, bus, dev, pr.pin,
346abab9128SBin Meng apicid, dstirq);
34707545d86SBin Meng intsrc_entries++;
34807545d86SBin Meng cell += sizeof(struct pirq_routing) / sizeof(u32);
34907545d86SBin Meng }
35007545d86SBin Meng
35153832bb8SBin Meng /* Legacy Interrupts */
35253832bb8SBin Meng debug("Writing ISA IRQs\n");
35353832bb8SBin Meng mptable_add_isa_interrupts(mc, bus_isa, apicid, 0);
35453832bb8SBin Meng
35507545d86SBin Meng return 0;
35607545d86SBin Meng }
35707545d86SBin Meng
mptable_add_lintsrc(struct mp_config_table * mc,int bus_isa)35807545d86SBin Meng static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa)
35907545d86SBin Meng {
36007545d86SBin Meng mp_write_lintsrc(mc, MP_EXTINT,
36107545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
36207545d86SBin Meng bus_isa, 0, MP_APIC_ALL, 0);
36307545d86SBin Meng mp_write_lintsrc(mc, MP_NMI,
36407545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
36507545d86SBin Meng bus_isa, 0, MP_APIC_ALL, 1);
36607545d86SBin Meng }
36707545d86SBin Meng
write_mp_table(ulong addr)36842fd8c19SSimon Glass ulong write_mp_table(ulong addr)
36907545d86SBin Meng {
37007545d86SBin Meng struct mp_config_table *mc;
37107545d86SBin Meng int ioapic_id, ioapic_ver;
37207545d86SBin Meng int bus_isa = 0xff;
37307545d86SBin Meng int ret;
374e71ffd09SSimon Glass ulong end;
37507545d86SBin Meng
37607545d86SBin Meng /* 16 byte align the table address */
37707545d86SBin Meng addr = ALIGN(addr, 16);
37807545d86SBin Meng
37907545d86SBin Meng /* Write floating table */
38007545d86SBin Meng mc = mp_write_floating_table((struct mp_floating_table *)addr);
38107545d86SBin Meng
38207545d86SBin Meng /* Write configuration table header */
38307545d86SBin Meng mp_config_table_init(mc);
38407545d86SBin Meng
38507545d86SBin Meng /* Write processor entry */
38607545d86SBin Meng mp_write_processor(mc);
38707545d86SBin Meng
38807545d86SBin Meng /* Write bus entry */
38907545d86SBin Meng mp_write_bus(mc, bus_isa, BUSTYPE_ISA);
39007545d86SBin Meng
39107545d86SBin Meng /* Write I/O APIC entry */
39207545d86SBin Meng ioapic_id = io_apic_read(IO_APIC_ID) >> 24;
39307545d86SBin Meng ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff;
39407545d86SBin Meng mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR);
39507545d86SBin Meng
39607545d86SBin Meng /* Write I/O interrupt assignment entry */
39707545d86SBin Meng ret = mptable_add_intsrc(mc, bus_isa, ioapic_id);
39807545d86SBin Meng if (ret)
39907545d86SBin Meng debug("Failed to write I/O interrupt assignment table\n");
40007545d86SBin Meng
40107545d86SBin Meng /* Write local interrupt assignment entry */
40207545d86SBin Meng mptable_add_lintsrc(mc, bus_isa);
40307545d86SBin Meng
40407545d86SBin Meng /* Finalize the MP table */
40507545d86SBin Meng end = mptable_finalize(mc);
40607545d86SBin Meng
40707545d86SBin Meng return end;
40807545d86SBin Meng }
409