1 /* 2 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> 3 * 4 * Adapted from coreboot src/arch/x86/boot/mpspec.c 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <cpu.h> 11 #include <dm.h> 12 #include <errno.h> 13 #include <fdtdec.h> 14 #include <asm/cpu.h> 15 #include <asm/irq.h> 16 #include <asm/ioapic.h> 17 #include <asm/lapic.h> 18 #include <asm/mpspec.h> 19 #include <asm/tables.h> 20 #include <dm/uclass-internal.h> 21 22 DECLARE_GLOBAL_DATA_PTR; 23 24 struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) 25 { 26 u32 mc; 27 28 memcpy(mf->mpf_signature, MPF_SIGNATURE, 4); 29 mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table); 30 mf->mpf_length = 1; 31 mf->mpf_spec = MPSPEC_V14; 32 mf->mpf_checksum = 0; 33 /* We don't use the default configuration table */ 34 mf->mpf_feature1 = 0; 35 /* Indicate that virtual wire mode is always implemented */ 36 mf->mpf_feature2 = 0; 37 mf->mpf_feature3 = 0; 38 mf->mpf_feature4 = 0; 39 mf->mpf_feature5 = 0; 40 mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16); 41 42 mc = (u32)mf + sizeof(struct mp_floating_table); 43 return (struct mp_config_table *)mc; 44 } 45 46 void mp_config_table_init(struct mp_config_table *mc) 47 { 48 memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); 49 mc->mpc_length = sizeof(struct mp_config_table); 50 mc->mpc_spec = MPSPEC_V14; 51 mc->mpc_checksum = 0; 52 mc->mpc_oemptr = 0; 53 mc->mpc_oemsize = 0; 54 mc->mpc_entry_count = 0; 55 mc->mpc_lapic = LAPIC_DEFAULT_BASE; 56 mc->mpe_length = 0; 57 mc->mpe_checksum = 0; 58 mc->reserved = 0; 59 60 /* The oem/product id fields are exactly 8/12 bytes long */ 61 table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' '); 62 table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' '); 63 } 64 65 void mp_write_processor(struct mp_config_table *mc) 66 { 67 struct mpc_config_processor *mpc; 68 struct udevice *dev; 69 u8 boot_apicid, apicver; 70 u32 cpusignature, cpufeature; 71 struct cpuid_result result; 72 73 boot_apicid = lapicid(); 74 apicver = lapic_read(LAPIC_LVR) & 0xff; 75 result = cpuid(1); 76 cpusignature = result.eax; 77 cpufeature = result.edx; 78 79 for (uclass_find_first_device(UCLASS_CPU, &dev); 80 dev; 81 uclass_find_next_device(&dev)) { 82 struct cpu_platdata *plat = dev_get_parent_platdata(dev); 83 u8 cpuflag = MPC_CPU_EN; 84 85 if (!device_active(dev)) 86 continue; 87 88 mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc); 89 mpc->mpc_type = MP_PROCESSOR; 90 mpc->mpc_apicid = plat->cpu_id; 91 mpc->mpc_apicver = apicver; 92 if (boot_apicid == plat->cpu_id) 93 cpuflag |= MPC_CPU_BP; 94 mpc->mpc_cpuflag = cpuflag; 95 mpc->mpc_cpusignature = cpusignature; 96 mpc->mpc_cpufeature = cpufeature; 97 mpc->mpc_reserved[0] = 0; 98 mpc->mpc_reserved[1] = 0; 99 mp_add_mpc_entry(mc, sizeof(*mpc)); 100 } 101 } 102 103 void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype) 104 { 105 struct mpc_config_bus *mpc; 106 107 mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc); 108 mpc->mpc_type = MP_BUS; 109 mpc->mpc_busid = id; 110 memcpy(mpc->mpc_bustype, bustype, 6); 111 mp_add_mpc_entry(mc, sizeof(*mpc)); 112 } 113 114 void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr) 115 { 116 struct mpc_config_ioapic *mpc; 117 118 mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc); 119 mpc->mpc_type = MP_IOAPIC; 120 mpc->mpc_apicid = id; 121 mpc->mpc_apicver = ver; 122 mpc->mpc_flags = MPC_APIC_USABLE; 123 mpc->mpc_apicaddr = apicaddr; 124 mp_add_mpc_entry(mc, sizeof(*mpc)); 125 } 126 127 void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, 128 int srcbus, int srcbusirq, int dstapic, int dstirq) 129 { 130 struct mpc_config_intsrc *mpc; 131 132 mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); 133 mpc->mpc_type = MP_INTSRC; 134 mpc->mpc_irqtype = irqtype; 135 mpc->mpc_irqflag = irqflag; 136 mpc->mpc_srcbus = srcbus; 137 mpc->mpc_srcbusirq = srcbusirq; 138 mpc->mpc_dstapic = dstapic; 139 mpc->mpc_dstirq = dstirq; 140 mp_add_mpc_entry(mc, sizeof(*mpc)); 141 } 142 143 void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, 144 int srcbus, int dev, int pin, int dstapic, int dstirq) 145 { 146 u8 srcbusirq = (dev << 2) | (pin - 1); 147 148 mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 149 srcbus, srcbusirq, dstapic, dstirq); 150 } 151 152 void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, 153 int srcbus, int srcbusirq, int destapic, int destlint) 154 { 155 struct mpc_config_lintsrc *mpc; 156 157 mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc); 158 mpc->mpc_type = MP_LINTSRC; 159 mpc->mpc_irqtype = irqtype; 160 mpc->mpc_irqflag = irqflag; 161 mpc->mpc_srcbusid = srcbus; 162 mpc->mpc_srcbusirq = srcbusirq; 163 mpc->mpc_destapic = destapic; 164 mpc->mpc_destlint = destlint; 165 mp_add_mpc_entry(mc, sizeof(*mpc)); 166 } 167 168 void mp_write_address_space(struct mp_config_table *mc, 169 int busid, int addr_type, 170 u32 addr_base_low, u32 addr_base_high, 171 u32 addr_length_low, u32 addr_length_high) 172 { 173 struct mp_ext_system_address_space *mpe; 174 175 mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc); 176 mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; 177 mpe->mpe_length = sizeof(*mpe); 178 mpe->mpe_busid = busid; 179 mpe->mpe_addr_type = addr_type; 180 mpe->mpe_addr_base_low = addr_base_low; 181 mpe->mpe_addr_base_high = addr_base_high; 182 mpe->mpe_addr_length_low = addr_length_low; 183 mpe->mpe_addr_length_high = addr_length_high; 184 mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 185 } 186 187 void mp_write_bus_hierarchy(struct mp_config_table *mc, 188 int busid, int bus_info, int parent_busid) 189 { 190 struct mp_ext_bus_hierarchy *mpe; 191 192 mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc); 193 mpe->mpe_type = MPE_BUS_HIERARCHY; 194 mpe->mpe_length = sizeof(*mpe); 195 mpe->mpe_busid = busid; 196 mpe->mpe_bus_info = bus_info; 197 mpe->mpe_parent_busid = parent_busid; 198 mpe->reserved[0] = 0; 199 mpe->reserved[1] = 0; 200 mpe->reserved[2] = 0; 201 mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 202 } 203 204 void mp_write_compat_address_space(struct mp_config_table *mc, int busid, 205 int addr_modifier, u32 range_list) 206 { 207 struct mp_ext_compat_address_space *mpe; 208 209 mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc); 210 mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE; 211 mpe->mpe_length = sizeof(*mpe); 212 mpe->mpe_busid = busid; 213 mpe->mpe_addr_modifier = addr_modifier; 214 mpe->mpe_range_list = range_list; 215 mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 216 } 217 218 u32 mptable_finalize(struct mp_config_table *mc) 219 { 220 u32 end; 221 222 mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc), 223 mc->mpe_length); 224 mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length); 225 end = mp_next_mpe_entry(mc); 226 227 debug("Write the MP table at: %x - %x\n", (u32)mc, end); 228 229 return end; 230 } 231 232 static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa, 233 int apicid, int external_int2) 234 { 235 int i; 236 237 mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT, 238 MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 239 bus_isa, 0, apicid, 0); 240 mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 241 bus_isa, 1, apicid, 1); 242 mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT, 243 MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 244 bus_isa, 0, apicid, 2); 245 246 for (i = 3; i < 16; i++) 247 mp_write_intsrc(mc, MP_INT, 248 MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 249 bus_isa, i, apicid, i); 250 } 251 252 /* 253 * Check duplicated I/O interrupt assignment table entry, to make sure 254 * there is only one entry with the given bus, device and interrupt pin. 255 */ 256 static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base, 257 int entry_num, int bus, int device, int pin) 258 { 259 struct mpc_config_intsrc *intsrc = intsrc_base; 260 int i; 261 262 for (i = 0; i < entry_num; i++) { 263 if (intsrc->mpc_srcbus == bus && 264 intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1))) 265 break; 266 intsrc++; 267 } 268 269 return (i == entry_num) ? false : true; 270 } 271 272 static int mptable_add_intsrc(struct mp_config_table *mc, 273 int bus_isa, int apicid) 274 { 275 struct mpc_config_intsrc *intsrc_base; 276 int intsrc_entries = 0; 277 const void *blob = gd->fdt_blob; 278 int node; 279 int len, count; 280 const u32 *cell; 281 int i; 282 283 /* Legacy Interrupts */ 284 debug("Writing ISA IRQs\n"); 285 mptable_add_isa_interrupts(mc, bus_isa, apicid, 0); 286 287 /* Get I/O interrupt information from device tree */ 288 node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER); 289 if (node < 0) { 290 debug("%s: Cannot find irq router node\n", __func__); 291 return -ENOENT; 292 } 293 294 cell = fdt_getprop(blob, node, "intel,pirq-routing", &len); 295 if (!cell) 296 return -ENOENT; 297 298 if ((len % sizeof(struct pirq_routing)) == 0) 299 count = len / sizeof(struct pirq_routing); 300 else 301 return -EINVAL; 302 303 intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); 304 305 for (i = 0; i < count; i++) { 306 struct pirq_routing pr; 307 308 pr.bdf = fdt_addr_to_cpu(cell[0]); 309 pr.pin = fdt_addr_to_cpu(cell[1]); 310 pr.pirq = fdt_addr_to_cpu(cell[2]); 311 312 if (check_dup_entry(intsrc_base, intsrc_entries, 313 PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) { 314 debug("found entry for bus %d device %d INT%c, skipping\n", 315 PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), 316 'A' + pr.pin - 1); 317 cell += sizeof(struct pirq_routing) / sizeof(u32); 318 continue; 319 } 320 321 /* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */ 322 mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf), 323 PCI_DEV(pr.bdf), pr.pin, apicid, 324 pr.pirq + 16); 325 intsrc_entries++; 326 cell += sizeof(struct pirq_routing) / sizeof(u32); 327 } 328 329 return 0; 330 } 331 332 static void mptable_add_lintsrc(struct mp_config_table *mc, int bus_isa) 333 { 334 mp_write_lintsrc(mc, MP_EXTINT, 335 MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 336 bus_isa, 0, MP_APIC_ALL, 0); 337 mp_write_lintsrc(mc, MP_NMI, 338 MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, 339 bus_isa, 0, MP_APIC_ALL, 1); 340 } 341 342 u32 write_mp_table(u32 addr) 343 { 344 struct mp_config_table *mc; 345 int ioapic_id, ioapic_ver; 346 int bus_isa = 0xff; 347 int ret; 348 u32 end; 349 350 /* 16 byte align the table address */ 351 addr = ALIGN(addr, 16); 352 353 /* Write floating table */ 354 mc = mp_write_floating_table((struct mp_floating_table *)addr); 355 356 /* Write configuration table header */ 357 mp_config_table_init(mc); 358 359 /* Write processor entry */ 360 mp_write_processor(mc); 361 362 /* Write bus entry */ 363 mp_write_bus(mc, bus_isa, BUSTYPE_ISA); 364 365 /* Write I/O APIC entry */ 366 ioapic_id = io_apic_read(IO_APIC_ID) >> 24; 367 ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff; 368 mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR); 369 370 /* Write I/O interrupt assignment entry */ 371 ret = mptable_add_intsrc(mc, bus_isa, ioapic_id); 372 if (ret) 373 debug("Failed to write I/O interrupt assignment table\n"); 374 375 /* Write local interrupt assignment entry */ 376 mptable_add_lintsrc(mc, bus_isa); 377 378 /* Finalize the MP table */ 379 end = mptable_finalize(mc); 380 381 return end; 382 } 383