17f5df8d4SBin Meng /* 27f5df8d4SBin Meng * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> 37f5df8d4SBin Meng * 47f5df8d4SBin Meng * Adapted from coreboot src/arch/x86/boot/mpspec.c 57f5df8d4SBin Meng * 67f5df8d4SBin Meng * SPDX-License-Identifier: GPL-2.0+ 77f5df8d4SBin Meng */ 87f5df8d4SBin Meng 97f5df8d4SBin Meng #include <common.h> 107f5df8d4SBin Meng #include <cpu.h> 117f5df8d4SBin Meng #include <dm.h> 1207545d86SBin Meng #include <errno.h> 1307545d86SBin Meng #include <fdtdec.h> 147f5df8d4SBin Meng #include <asm/cpu.h> 1507545d86SBin Meng #include <asm/irq.h> 167f5df8d4SBin Meng #include <asm/ioapic.h> 177f5df8d4SBin Meng #include <asm/lapic.h> 187f5df8d4SBin Meng #include <asm/mpspec.h> 197f5df8d4SBin Meng #include <asm/tables.h> 207f5df8d4SBin Meng #include <dm/uclass-internal.h> 217f5df8d4SBin Meng 2207545d86SBin Meng DECLARE_GLOBAL_DATA_PTR; 2307545d86SBin Meng 2453832bb8SBin Meng static bool isa_irq_occupied[16]; 2553832bb8SBin Meng 267f5df8d4SBin Meng struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) 277f5df8d4SBin Meng { 287f5df8d4SBin Meng u32 mc; 297f5df8d4SBin Meng 307f5df8d4SBin Meng memcpy(mf->mpf_signature, MPF_SIGNATURE, 4); 317f5df8d4SBin Meng mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table); 327f5df8d4SBin Meng mf->mpf_length = 1; 337f5df8d4SBin Meng mf->mpf_spec = MPSPEC_V14; 347f5df8d4SBin Meng mf->mpf_checksum = 0; 357f5df8d4SBin Meng /* We don't use the default configuration table */ 367f5df8d4SBin Meng mf->mpf_feature1 = 0; 377f5df8d4SBin Meng /* Indicate that virtual wire mode is always implemented */ 387f5df8d4SBin Meng mf->mpf_feature2 = 0; 397f5df8d4SBin Meng mf->mpf_feature3 = 0; 407f5df8d4SBin Meng mf->mpf_feature4 = 0; 417f5df8d4SBin Meng mf->mpf_feature5 = 0; 427f5df8d4SBin Meng mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16); 437f5df8d4SBin Meng 447f5df8d4SBin Meng mc = (u32)mf + sizeof(struct mp_floating_table); 457f5df8d4SBin Meng return (struct mp_config_table *)mc; 467f5df8d4SBin Meng } 477f5df8d4SBin Meng 487f5df8d4SBin Meng void mp_config_table_init(struct mp_config_table *mc) 497f5df8d4SBin Meng { 507f5df8d4SBin Meng memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); 517f5df8d4SBin Meng mc->mpc_length = sizeof(struct mp_config_table); 527f5df8d4SBin Meng mc->mpc_spec = MPSPEC_V14; 537f5df8d4SBin Meng mc->mpc_checksum = 0; 547f5df8d4SBin Meng mc->mpc_oemptr = 0; 557f5df8d4SBin Meng mc->mpc_oemsize = 0; 567f5df8d4SBin Meng mc->mpc_entry_count = 0; 577f5df8d4SBin Meng mc->mpc_lapic = LAPIC_DEFAULT_BASE; 587f5df8d4SBin Meng mc->mpe_length = 0; 597f5df8d4SBin Meng mc->mpe_checksum = 0; 607f5df8d4SBin Meng mc->reserved = 0; 617f5df8d4SBin Meng 627f5df8d4SBin Meng /* The oem/product id fields are exactly 8/12 bytes long */ 637f5df8d4SBin Meng table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' '); 647f5df8d4SBin Meng table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' '); 657f5df8d4SBin Meng } 667f5df8d4SBin Meng 677f5df8d4SBin Meng void mp_write_processor(struct mp_config_table *mc) 687f5df8d4SBin Meng { 697f5df8d4SBin Meng struct mpc_config_processor *mpc; 707f5df8d4SBin Meng struct udevice *dev; 717f5df8d4SBin Meng u8 boot_apicid, apicver; 727f5df8d4SBin Meng u32 cpusignature, cpufeature; 737f5df8d4SBin Meng struct cpuid_result result; 747f5df8d4SBin Meng 757f5df8d4SBin Meng boot_apicid = lapicid(); 767f5df8d4SBin Meng apicver = lapic_read(LAPIC_LVR) & 0xff; 777f5df8d4SBin Meng result = cpuid(1); 787f5df8d4SBin Meng cpusignature = result.eax; 797f5df8d4SBin Meng cpufeature = result.edx; 807f5df8d4SBin Meng 817f5df8d4SBin Meng for (uclass_find_first_device(UCLASS_CPU, &dev); 827f5df8d4SBin Meng dev; 837f5df8d4SBin Meng uclass_find_next_device(&dev)) { 847f5df8d4SBin Meng struct cpu_platdata *plat = dev_get_parent_platdata(dev); 857f5df8d4SBin Meng u8 cpuflag = MPC_CPU_EN; 867f5df8d4SBin Meng 877f5df8d4SBin Meng if (!device_active(dev)) 887f5df8d4SBin Meng continue; 897f5df8d4SBin Meng 907f5df8d4SBin Meng mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc); 917f5df8d4SBin Meng mpc->mpc_type = MP_PROCESSOR; 927f5df8d4SBin Meng mpc->mpc_apicid = plat->cpu_id; 937f5df8d4SBin Meng mpc->mpc_apicver = apicver; 947f5df8d4SBin Meng if (boot_apicid == plat->cpu_id) 957f5df8d4SBin Meng cpuflag |= MPC_CPU_BP; 967f5df8d4SBin Meng mpc->mpc_cpuflag = cpuflag; 977f5df8d4SBin Meng mpc->mpc_cpusignature = cpusignature; 987f5df8d4SBin Meng mpc->mpc_cpufeature = cpufeature; 997f5df8d4SBin Meng mpc->mpc_reserved[0] = 0; 1007f5df8d4SBin Meng mpc->mpc_reserved[1] = 0; 1017f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 1027f5df8d4SBin Meng } 1037f5df8d4SBin Meng } 1047f5df8d4SBin Meng 1057f5df8d4SBin Meng void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype) 1067f5df8d4SBin Meng { 1077f5df8d4SBin Meng struct mpc_config_bus *mpc; 1087f5df8d4SBin Meng 1097f5df8d4SBin Meng mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc); 1107f5df8d4SBin Meng mpc->mpc_type = MP_BUS; 1117f5df8d4SBin Meng mpc->mpc_busid = id; 1127f5df8d4SBin Meng memcpy(mpc->mpc_bustype, bustype, 6); 1137f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 1147f5df8d4SBin Meng } 1157f5df8d4SBin Meng 1167f5df8d4SBin Meng void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr) 1177f5df8d4SBin Meng { 1187f5df8d4SBin Meng struct mpc_config_ioapic *mpc; 1197f5df8d4SBin Meng 1207f5df8d4SBin Meng mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc); 1217f5df8d4SBin Meng mpc->mpc_type = MP_IOAPIC; 1227f5df8d4SBin Meng mpc->mpc_apicid = id; 1237f5df8d4SBin Meng mpc->mpc_apicver = ver; 1247f5df8d4SBin Meng mpc->mpc_flags = MPC_APIC_USABLE; 1257f5df8d4SBin Meng mpc->mpc_apicaddr = apicaddr; 1267f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 1277f5df8d4SBin Meng } 1287f5df8d4SBin Meng 1297f5df8d4SBin Meng void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, 1307f5df8d4SBin Meng int srcbus, int srcbusirq, int dstapic, int dstirq) 1317f5df8d4SBin Meng { 1327f5df8d4SBin Meng struct mpc_config_intsrc *mpc; 1337f5df8d4SBin Meng 1347f5df8d4SBin Meng mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); 1357f5df8d4SBin Meng mpc->mpc_type = MP_INTSRC; 1367f5df8d4SBin Meng mpc->mpc_irqtype = irqtype; 1377f5df8d4SBin Meng mpc->mpc_irqflag = irqflag; 1387f5df8d4SBin Meng mpc->mpc_srcbus = srcbus; 1397f5df8d4SBin Meng mpc->mpc_srcbusirq = srcbusirq; 1407f5df8d4SBin Meng mpc->mpc_dstapic = dstapic; 1417f5df8d4SBin Meng mpc->mpc_dstirq = dstirq; 1427f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 1437f5df8d4SBin Meng } 1447f5df8d4SBin Meng 1457f5df8d4SBin Meng void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, 1467f5df8d4SBin Meng int srcbus, int dev, int pin, int dstapic, int dstirq) 1477f5df8d4SBin Meng { 1487f5df8d4SBin Meng u8 srcbusirq = (dev << 2) | (pin - 1); 1497f5df8d4SBin Meng 1507f5df8d4SBin Meng mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 1517f5df8d4SBin Meng srcbus, srcbusirq, dstapic, dstirq); 1527f5df8d4SBin Meng } 1537f5df8d4SBin Meng 1547f5df8d4SBin Meng void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, 1557f5df8d4SBin Meng int srcbus, int srcbusirq, int destapic, int destlint) 1567f5df8d4SBin Meng { 1577f5df8d4SBin Meng struct mpc_config_lintsrc *mpc; 1587f5df8d4SBin Meng 1597f5df8d4SBin Meng mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc); 1607f5df8d4SBin Meng mpc->mpc_type = MP_LINTSRC; 1617f5df8d4SBin Meng mpc->mpc_irqtype = irqtype; 1627f5df8d4SBin Meng mpc->mpc_irqflag = irqflag; 1637f5df8d4SBin Meng mpc->mpc_srcbusid = srcbus; 1647f5df8d4SBin Meng mpc->mpc_srcbusirq = srcbusirq; 1657f5df8d4SBin Meng mpc->mpc_destapic = destapic; 1667f5df8d4SBin Meng mpc->mpc_destlint = destlint; 1677f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 1687f5df8d4SBin Meng } 1697f5df8d4SBin Meng 1707f5df8d4SBin Meng void mp_write_address_space(struct mp_config_table *mc, 1717f5df8d4SBin Meng int busid, int addr_type, 1727f5df8d4SBin Meng u32 addr_base_low, u32 addr_base_high, 1737f5df8d4SBin Meng u32 addr_length_low, u32 addr_length_high) 1747f5df8d4SBin Meng { 1757f5df8d4SBin Meng struct mp_ext_system_address_space *mpe; 1767f5df8d4SBin Meng 1777f5df8d4SBin Meng mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc); 1787f5df8d4SBin Meng mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; 1797f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe); 1807f5df8d4SBin Meng mpe->mpe_busid = busid; 1817f5df8d4SBin Meng mpe->mpe_addr_type = addr_type; 1827f5df8d4SBin Meng mpe->mpe_addr_base_low = addr_base_low; 1837f5df8d4SBin Meng mpe->mpe_addr_base_high = addr_base_high; 1847f5df8d4SBin Meng mpe->mpe_addr_length_low = addr_length_low; 1857f5df8d4SBin Meng mpe->mpe_addr_length_high = addr_length_high; 1867f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 1877f5df8d4SBin Meng } 1887f5df8d4SBin Meng 1897f5df8d4SBin Meng void mp_write_bus_hierarchy(struct mp_config_table *mc, 1907f5df8d4SBin Meng int busid, int bus_info, int parent_busid) 1917f5df8d4SBin Meng { 1927f5df8d4SBin Meng struct mp_ext_bus_hierarchy *mpe; 1937f5df8d4SBin Meng 1947f5df8d4SBin Meng mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc); 1957f5df8d4SBin Meng mpe->mpe_type = MPE_BUS_HIERARCHY; 1967f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe); 1977f5df8d4SBin Meng mpe->mpe_busid = busid; 1987f5df8d4SBin Meng mpe->mpe_bus_info = bus_info; 1997f5df8d4SBin Meng mpe->mpe_parent_busid = parent_busid; 2007f5df8d4SBin Meng mpe->reserved[0] = 0; 2017f5df8d4SBin Meng mpe->reserved[1] = 0; 2027f5df8d4SBin Meng mpe->reserved[2] = 0; 2037f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 2047f5df8d4SBin Meng } 2057f5df8d4SBin Meng 2067f5df8d4SBin Meng void mp_write_compat_address_space(struct mp_config_table *mc, int busid, 2077f5df8d4SBin Meng int addr_modifier, u32 range_list) 2087f5df8d4SBin Meng { 2097f5df8d4SBin Meng struct mp_ext_compat_address_space *mpe; 2107f5df8d4SBin Meng 2117f5df8d4SBin Meng mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc); 2127f5df8d4SBin Meng mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE; 2137f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe); 2147f5df8d4SBin Meng mpe->mpe_busid = busid; 2157f5df8d4SBin Meng mpe->mpe_addr_modifier = addr_modifier; 2167f5df8d4SBin Meng mpe->mpe_range_list = range_list; 2177f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 2187f5df8d4SBin Meng } 2197f5df8d4SBin Meng 2207f5df8d4SBin Meng u32 mptable_finalize(struct mp_config_table *mc) 2217f5df8d4SBin Meng { 2227f5df8d4SBin Meng u32 end; 2237f5df8d4SBin Meng 2247f5df8d4SBin Meng mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc), 2257f5df8d4SBin Meng mc->mpe_length); 2267f5df8d4SBin Meng mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length); 2277f5df8d4SBin Meng end = mp_next_mpe_entry(mc); 2287f5df8d4SBin Meng 2297f5df8d4SBin Meng debug("Write the MP table at: %x - %x\n", (u32)mc, end); 2307f5df8d4SBin Meng 2317f5df8d4SBin Meng return end; 2327f5df8d4SBin Meng } 23307545d86SBin Meng 23407545d86SBin Meng static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa, 23507545d86SBin Meng int apicid, int external_int2) 23607545d86SBin Meng { 23707545d86SBin Meng int i; 23807545d86SBin Meng 23907545d86SBin Meng mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT, 24007545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 24107545d86SBin Meng bus_isa, 0, apicid, 0); 24207545d86SBin Meng mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 24307545d86SBin Meng bus_isa, 1, apicid, 1); 24407545d86SBin Meng mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT, 24507545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 24607545d86SBin Meng bus_isa, 0, apicid, 2); 24707545d86SBin Meng 24853832bb8SBin Meng for (i = 3; i < 16; i++) { 24953832bb8SBin Meng /* 25053832bb8SBin Meng * Do not write ISA interrupt entry if it is already occupied 25153832bb8SBin Meng * by the platform devices. 25253832bb8SBin Meng */ 25353832bb8SBin Meng if (isa_irq_occupied[i]) 25453832bb8SBin Meng continue; 25553832bb8SBin Meng 25607545d86SBin Meng mp_write_intsrc(mc, MP_INT, 25707545d86SBin Meng MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 25807545d86SBin Meng bus_isa, i, apicid, i); 25907545d86SBin Meng } 26053832bb8SBin Meng } 26107545d86SBin Meng 26207545d86SBin Meng /* 26307545d86SBin Meng * Check duplicated I/O interrupt assignment table entry, to make sure 26407545d86SBin Meng * there is only one entry with the given bus, device and interrupt pin. 26507545d86SBin Meng */ 26607545d86SBin Meng static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base, 26707545d86SBin Meng int entry_num, int bus, int device, int pin) 26807545d86SBin Meng { 26907545d86SBin Meng struct mpc_config_intsrc *intsrc = intsrc_base; 27007545d86SBin Meng int i; 27107545d86SBin Meng 27207545d86SBin Meng for (i = 0; i < entry_num; i++) { 27307545d86SBin Meng if (intsrc->mpc_srcbus == bus && 27407545d86SBin Meng intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1))) 27507545d86SBin Meng break; 27607545d86SBin Meng intsrc++; 27707545d86SBin Meng } 27807545d86SBin Meng 27907545d86SBin Meng return (i == entry_num) ? false : true; 28007545d86SBin Meng } 28107545d86SBin Meng 282abab9128SBin Meng /* TODO: move this to driver model */ 283abab9128SBin Meng __weak int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq) 284abab9128SBin Meng { 285abab9128SBin Meng /* PIRQ[A-H] are connected to I/O APIC INTPIN#16-23 */ 286abab9128SBin Meng return pirq + 16; 287abab9128SBin Meng } 288abab9128SBin Meng 28907545d86SBin Meng static int mptable_add_intsrc(struct mp_config_table *mc, 29007545d86SBin Meng int bus_isa, int apicid) 29107545d86SBin Meng { 29207545d86SBin Meng struct mpc_config_intsrc *intsrc_base; 29307545d86SBin Meng int intsrc_entries = 0; 29407545d86SBin Meng const void *blob = gd->fdt_blob; 295b565d66dSSimon Glass struct udevice *dev; 29607545d86SBin Meng int len, count; 29707545d86SBin Meng const u32 *cell; 298b565d66dSSimon Glass int i, ret; 29907545d86SBin Meng 3003f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_IRQ, &dev); 301b565d66dSSimon Glass if (ret && ret != -ENODEV) { 30207545d86SBin Meng debug("%s: Cannot find irq router node\n", __func__); 303b565d66dSSimon Glass return ret; 30407545d86SBin Meng } 30507545d86SBin Meng 306b565d66dSSimon Glass /* Get I/O interrupt information from device tree */ 307b565d66dSSimon Glass cell = fdt_getprop(blob, dev->of_offset, "intel,pirq-routing", &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 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 368*42fd8c19SSimon 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; 37407545d86SBin Meng u32 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