1*7f5df8d4SBin Meng /* 2*7f5df8d4SBin Meng * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> 3*7f5df8d4SBin Meng * 4*7f5df8d4SBin Meng * Adapted from coreboot src/arch/x86/boot/mpspec.c 5*7f5df8d4SBin Meng * 6*7f5df8d4SBin Meng * SPDX-License-Identifier: GPL-2.0+ 7*7f5df8d4SBin Meng */ 8*7f5df8d4SBin Meng 9*7f5df8d4SBin Meng #include <common.h> 10*7f5df8d4SBin Meng #include <cpu.h> 11*7f5df8d4SBin Meng #include <dm.h> 12*7f5df8d4SBin Meng #include <asm/cpu.h> 13*7f5df8d4SBin Meng #include <asm/ioapic.h> 14*7f5df8d4SBin Meng #include <asm/lapic.h> 15*7f5df8d4SBin Meng #include <asm/mpspec.h> 16*7f5df8d4SBin Meng #include <asm/tables.h> 17*7f5df8d4SBin Meng #include <dm/uclass-internal.h> 18*7f5df8d4SBin Meng 19*7f5df8d4SBin Meng struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf) 20*7f5df8d4SBin Meng { 21*7f5df8d4SBin Meng u32 mc; 22*7f5df8d4SBin Meng 23*7f5df8d4SBin Meng memcpy(mf->mpf_signature, MPF_SIGNATURE, 4); 24*7f5df8d4SBin Meng mf->mpf_physptr = (u32)mf + sizeof(struct mp_floating_table); 25*7f5df8d4SBin Meng mf->mpf_length = 1; 26*7f5df8d4SBin Meng mf->mpf_spec = MPSPEC_V14; 27*7f5df8d4SBin Meng mf->mpf_checksum = 0; 28*7f5df8d4SBin Meng /* We don't use the default configuration table */ 29*7f5df8d4SBin Meng mf->mpf_feature1 = 0; 30*7f5df8d4SBin Meng /* Indicate that virtual wire mode is always implemented */ 31*7f5df8d4SBin Meng mf->mpf_feature2 = 0; 32*7f5df8d4SBin Meng mf->mpf_feature3 = 0; 33*7f5df8d4SBin Meng mf->mpf_feature4 = 0; 34*7f5df8d4SBin Meng mf->mpf_feature5 = 0; 35*7f5df8d4SBin Meng mf->mpf_checksum = table_compute_checksum(mf, mf->mpf_length * 16); 36*7f5df8d4SBin Meng 37*7f5df8d4SBin Meng mc = (u32)mf + sizeof(struct mp_floating_table); 38*7f5df8d4SBin Meng return (struct mp_config_table *)mc; 39*7f5df8d4SBin Meng } 40*7f5df8d4SBin Meng 41*7f5df8d4SBin Meng void mp_config_table_init(struct mp_config_table *mc) 42*7f5df8d4SBin Meng { 43*7f5df8d4SBin Meng memcpy(mc->mpc_signature, MPC_SIGNATURE, 4); 44*7f5df8d4SBin Meng mc->mpc_length = sizeof(struct mp_config_table); 45*7f5df8d4SBin Meng mc->mpc_spec = MPSPEC_V14; 46*7f5df8d4SBin Meng mc->mpc_checksum = 0; 47*7f5df8d4SBin Meng mc->mpc_oemptr = 0; 48*7f5df8d4SBin Meng mc->mpc_oemsize = 0; 49*7f5df8d4SBin Meng mc->mpc_entry_count = 0; 50*7f5df8d4SBin Meng mc->mpc_lapic = LAPIC_DEFAULT_BASE; 51*7f5df8d4SBin Meng mc->mpe_length = 0; 52*7f5df8d4SBin Meng mc->mpe_checksum = 0; 53*7f5df8d4SBin Meng mc->reserved = 0; 54*7f5df8d4SBin Meng 55*7f5df8d4SBin Meng /* The oem/product id fields are exactly 8/12 bytes long */ 56*7f5df8d4SBin Meng table_fill_string(mc->mpc_oem, CONFIG_SYS_VENDOR, 8, ' '); 57*7f5df8d4SBin Meng table_fill_string(mc->mpc_product, CONFIG_SYS_BOARD, 12, ' '); 58*7f5df8d4SBin Meng } 59*7f5df8d4SBin Meng 60*7f5df8d4SBin Meng void mp_write_processor(struct mp_config_table *mc) 61*7f5df8d4SBin Meng { 62*7f5df8d4SBin Meng struct mpc_config_processor *mpc; 63*7f5df8d4SBin Meng struct udevice *dev; 64*7f5df8d4SBin Meng u8 boot_apicid, apicver; 65*7f5df8d4SBin Meng u32 cpusignature, cpufeature; 66*7f5df8d4SBin Meng struct cpuid_result result; 67*7f5df8d4SBin Meng 68*7f5df8d4SBin Meng boot_apicid = lapicid(); 69*7f5df8d4SBin Meng apicver = lapic_read(LAPIC_LVR) & 0xff; 70*7f5df8d4SBin Meng result = cpuid(1); 71*7f5df8d4SBin Meng cpusignature = result.eax; 72*7f5df8d4SBin Meng cpufeature = result.edx; 73*7f5df8d4SBin Meng 74*7f5df8d4SBin Meng for (uclass_find_first_device(UCLASS_CPU, &dev); 75*7f5df8d4SBin Meng dev; 76*7f5df8d4SBin Meng uclass_find_next_device(&dev)) { 77*7f5df8d4SBin Meng struct cpu_platdata *plat = dev_get_parent_platdata(dev); 78*7f5df8d4SBin Meng u8 cpuflag = MPC_CPU_EN; 79*7f5df8d4SBin Meng 80*7f5df8d4SBin Meng if (!device_active(dev)) 81*7f5df8d4SBin Meng continue; 82*7f5df8d4SBin Meng 83*7f5df8d4SBin Meng mpc = (struct mpc_config_processor *)mp_next_mpc_entry(mc); 84*7f5df8d4SBin Meng mpc->mpc_type = MP_PROCESSOR; 85*7f5df8d4SBin Meng mpc->mpc_apicid = plat->cpu_id; 86*7f5df8d4SBin Meng mpc->mpc_apicver = apicver; 87*7f5df8d4SBin Meng if (boot_apicid == plat->cpu_id) 88*7f5df8d4SBin Meng cpuflag |= MPC_CPU_BP; 89*7f5df8d4SBin Meng mpc->mpc_cpuflag = cpuflag; 90*7f5df8d4SBin Meng mpc->mpc_cpusignature = cpusignature; 91*7f5df8d4SBin Meng mpc->mpc_cpufeature = cpufeature; 92*7f5df8d4SBin Meng mpc->mpc_reserved[0] = 0; 93*7f5df8d4SBin Meng mpc->mpc_reserved[1] = 0; 94*7f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 95*7f5df8d4SBin Meng } 96*7f5df8d4SBin Meng } 97*7f5df8d4SBin Meng 98*7f5df8d4SBin Meng void mp_write_bus(struct mp_config_table *mc, int id, const char *bustype) 99*7f5df8d4SBin Meng { 100*7f5df8d4SBin Meng struct mpc_config_bus *mpc; 101*7f5df8d4SBin Meng 102*7f5df8d4SBin Meng mpc = (struct mpc_config_bus *)mp_next_mpc_entry(mc); 103*7f5df8d4SBin Meng mpc->mpc_type = MP_BUS; 104*7f5df8d4SBin Meng mpc->mpc_busid = id; 105*7f5df8d4SBin Meng memcpy(mpc->mpc_bustype, bustype, 6); 106*7f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 107*7f5df8d4SBin Meng } 108*7f5df8d4SBin Meng 109*7f5df8d4SBin Meng void mp_write_ioapic(struct mp_config_table *mc, int id, int ver, u32 apicaddr) 110*7f5df8d4SBin Meng { 111*7f5df8d4SBin Meng struct mpc_config_ioapic *mpc; 112*7f5df8d4SBin Meng 113*7f5df8d4SBin Meng mpc = (struct mpc_config_ioapic *)mp_next_mpc_entry(mc); 114*7f5df8d4SBin Meng mpc->mpc_type = MP_IOAPIC; 115*7f5df8d4SBin Meng mpc->mpc_apicid = id; 116*7f5df8d4SBin Meng mpc->mpc_apicver = ver; 117*7f5df8d4SBin Meng mpc->mpc_flags = MPC_APIC_USABLE; 118*7f5df8d4SBin Meng mpc->mpc_apicaddr = apicaddr; 119*7f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 120*7f5df8d4SBin Meng } 121*7f5df8d4SBin Meng 122*7f5df8d4SBin Meng void mp_write_intsrc(struct mp_config_table *mc, int irqtype, int irqflag, 123*7f5df8d4SBin Meng int srcbus, int srcbusirq, int dstapic, int dstirq) 124*7f5df8d4SBin Meng { 125*7f5df8d4SBin Meng struct mpc_config_intsrc *mpc; 126*7f5df8d4SBin Meng 127*7f5df8d4SBin Meng mpc = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc); 128*7f5df8d4SBin Meng mpc->mpc_type = MP_INTSRC; 129*7f5df8d4SBin Meng mpc->mpc_irqtype = irqtype; 130*7f5df8d4SBin Meng mpc->mpc_irqflag = irqflag; 131*7f5df8d4SBin Meng mpc->mpc_srcbus = srcbus; 132*7f5df8d4SBin Meng mpc->mpc_srcbusirq = srcbusirq; 133*7f5df8d4SBin Meng mpc->mpc_dstapic = dstapic; 134*7f5df8d4SBin Meng mpc->mpc_dstirq = dstirq; 135*7f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 136*7f5df8d4SBin Meng } 137*7f5df8d4SBin Meng 138*7f5df8d4SBin Meng void mp_write_pci_intsrc(struct mp_config_table *mc, int irqtype, 139*7f5df8d4SBin Meng int srcbus, int dev, int pin, int dstapic, int dstirq) 140*7f5df8d4SBin Meng { 141*7f5df8d4SBin Meng u8 srcbusirq = (dev << 2) | (pin - 1); 142*7f5df8d4SBin Meng 143*7f5df8d4SBin Meng mp_write_intsrc(mc, irqtype, MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW, 144*7f5df8d4SBin Meng srcbus, srcbusirq, dstapic, dstirq); 145*7f5df8d4SBin Meng } 146*7f5df8d4SBin Meng 147*7f5df8d4SBin Meng void mp_write_lintsrc(struct mp_config_table *mc, int irqtype, int irqflag, 148*7f5df8d4SBin Meng int srcbus, int srcbusirq, int destapic, int destlint) 149*7f5df8d4SBin Meng { 150*7f5df8d4SBin Meng struct mpc_config_lintsrc *mpc; 151*7f5df8d4SBin Meng 152*7f5df8d4SBin Meng mpc = (struct mpc_config_lintsrc *)mp_next_mpc_entry(mc); 153*7f5df8d4SBin Meng mpc->mpc_type = MP_LINTSRC; 154*7f5df8d4SBin Meng mpc->mpc_irqtype = irqtype; 155*7f5df8d4SBin Meng mpc->mpc_irqflag = irqflag; 156*7f5df8d4SBin Meng mpc->mpc_srcbusid = srcbus; 157*7f5df8d4SBin Meng mpc->mpc_srcbusirq = srcbusirq; 158*7f5df8d4SBin Meng mpc->mpc_destapic = destapic; 159*7f5df8d4SBin Meng mpc->mpc_destlint = destlint; 160*7f5df8d4SBin Meng mp_add_mpc_entry(mc, sizeof(*mpc)); 161*7f5df8d4SBin Meng } 162*7f5df8d4SBin Meng 163*7f5df8d4SBin Meng void mp_write_address_space(struct mp_config_table *mc, 164*7f5df8d4SBin Meng int busid, int addr_type, 165*7f5df8d4SBin Meng u32 addr_base_low, u32 addr_base_high, 166*7f5df8d4SBin Meng u32 addr_length_low, u32 addr_length_high) 167*7f5df8d4SBin Meng { 168*7f5df8d4SBin Meng struct mp_ext_system_address_space *mpe; 169*7f5df8d4SBin Meng 170*7f5df8d4SBin Meng mpe = (struct mp_ext_system_address_space *)mp_next_mpe_entry(mc); 171*7f5df8d4SBin Meng mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE; 172*7f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe); 173*7f5df8d4SBin Meng mpe->mpe_busid = busid; 174*7f5df8d4SBin Meng mpe->mpe_addr_type = addr_type; 175*7f5df8d4SBin Meng mpe->mpe_addr_base_low = addr_base_low; 176*7f5df8d4SBin Meng mpe->mpe_addr_base_high = addr_base_high; 177*7f5df8d4SBin Meng mpe->mpe_addr_length_low = addr_length_low; 178*7f5df8d4SBin Meng mpe->mpe_addr_length_high = addr_length_high; 179*7f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 180*7f5df8d4SBin Meng } 181*7f5df8d4SBin Meng 182*7f5df8d4SBin Meng void mp_write_bus_hierarchy(struct mp_config_table *mc, 183*7f5df8d4SBin Meng int busid, int bus_info, int parent_busid) 184*7f5df8d4SBin Meng { 185*7f5df8d4SBin Meng struct mp_ext_bus_hierarchy *mpe; 186*7f5df8d4SBin Meng 187*7f5df8d4SBin Meng mpe = (struct mp_ext_bus_hierarchy *)mp_next_mpe_entry(mc); 188*7f5df8d4SBin Meng mpe->mpe_type = MPE_BUS_HIERARCHY; 189*7f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe); 190*7f5df8d4SBin Meng mpe->mpe_busid = busid; 191*7f5df8d4SBin Meng mpe->mpe_bus_info = bus_info; 192*7f5df8d4SBin Meng mpe->mpe_parent_busid = parent_busid; 193*7f5df8d4SBin Meng mpe->reserved[0] = 0; 194*7f5df8d4SBin Meng mpe->reserved[1] = 0; 195*7f5df8d4SBin Meng mpe->reserved[2] = 0; 196*7f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 197*7f5df8d4SBin Meng } 198*7f5df8d4SBin Meng 199*7f5df8d4SBin Meng void mp_write_compat_address_space(struct mp_config_table *mc, int busid, 200*7f5df8d4SBin Meng int addr_modifier, u32 range_list) 201*7f5df8d4SBin Meng { 202*7f5df8d4SBin Meng struct mp_ext_compat_address_space *mpe; 203*7f5df8d4SBin Meng 204*7f5df8d4SBin Meng mpe = (struct mp_ext_compat_address_space *)mp_next_mpe_entry(mc); 205*7f5df8d4SBin Meng mpe->mpe_type = MPE_COMPAT_ADDRESS_SPACE; 206*7f5df8d4SBin Meng mpe->mpe_length = sizeof(*mpe); 207*7f5df8d4SBin Meng mpe->mpe_busid = busid; 208*7f5df8d4SBin Meng mpe->mpe_addr_modifier = addr_modifier; 209*7f5df8d4SBin Meng mpe->mpe_range_list = range_list; 210*7f5df8d4SBin Meng mp_add_mpe_entry(mc, (struct mp_ext_config *)mpe); 211*7f5df8d4SBin Meng } 212*7f5df8d4SBin Meng 213*7f5df8d4SBin Meng u32 mptable_finalize(struct mp_config_table *mc) 214*7f5df8d4SBin Meng { 215*7f5df8d4SBin Meng u32 end; 216*7f5df8d4SBin Meng 217*7f5df8d4SBin Meng mc->mpe_checksum = table_compute_checksum((void *)mp_next_mpc_entry(mc), 218*7f5df8d4SBin Meng mc->mpe_length); 219*7f5df8d4SBin Meng mc->mpc_checksum = table_compute_checksum(mc, mc->mpc_length); 220*7f5df8d4SBin Meng end = mp_next_mpe_entry(mc); 221*7f5df8d4SBin Meng 222*7f5df8d4SBin Meng debug("Write the MP table at: %x - %x\n", (u32)mc, end); 223*7f5df8d4SBin Meng 224*7f5df8d4SBin Meng return end; 225*7f5df8d4SBin Meng } 226