diff options
Diffstat (limited to 'src/soc/intel/xeon_sp/spr/cpu.c')
-rw-r--r-- | src/soc/intel/xeon_sp/spr/cpu.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/soc/intel/xeon_sp/spr/cpu.c b/src/soc/intel/xeon_sp/spr/cpu.c new file mode 100644 index 0000000000..eb35f3e3c8 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/cpu.c @@ -0,0 +1,281 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpigen.h> +#include <acpi/acpi.h> +#include <console/console.h> +#include <console/debug.h> +#include <cpu/cpu.h> +#include <cpu/intel/cpu_ids.h> +#include <cpu/intel/common/common.h> +#include <cpu/intel/em64t101_save_state.h> +#include <cpu/intel/microcode.h> +#include <cpu/intel/smm_reloc.h> +#include <cpu/intel/turbo.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/mp.h> +#include <cpu/x86/mtrr.h> +#include <device/pci_mmio_cfg.h> +#include <intelblocks/cpulib.h> +#include <intelblocks/mp_init.h> +#include <intelpch/lockdown.h> +#include <soc/msr.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_util.h> +#include <soc/smmrelocate.h> +#include <soc/util.h> + +#include "chip.h" + +static const void *microcode_patch; + +static const config_t *chip_config = NULL; + +bool cpu_soc_is_in_untrusted_mode(void) +{ + return false; +} + +void cpu_soc_bios_done(void) +{ +} + +static void xeon_configure_mca(void) +{ + msr_t msr; + struct cpuid_result cpuid_regs; + + /* + * Check feature flag in CPUID.(EAX=1):EDX[7]==1 MCE + * and CPUID.(EAX=1):EDX[14]==1 MCA + */ + cpuid_regs = cpuid(1); + if ((cpuid_regs.edx & (1 << 7 | 1 << 14)) != (1 << 7 | 1 << 14)) + return; + + msr = rdmsr(IA32_MCG_CAP); + if (msr.lo & IA32_MCG_CAP_CTL_P_MASK) { + /* Enable all error logging */ + msr.lo = msr.hi = 0xffffffff; + wrmsr(IA32_MCG_CTL, msr); + } + + mca_configure(); +} + +/* + * On server platforms the FIT mechanism only updates the microcode on + * the BSP. Loading MCU on AP in parallel seems to fail in 10% of the cases + * so do it serialized. + */ +void get_microcode_info(const void **microcode, int *parallel) +{ + *microcode = intel_microcode_find(); + *parallel = 0; +} + +static void each_cpu_init(struct device *cpu) +{ + msr_t msr; + + printk(BIOS_SPEW, "%s dev: %s, cpu: %lu, apic_id: 0x%x\n", __func__, dev_path(cpu), + cpu_index(), cpu->path.apic.apic_id); + + /* + * Enable PWR_PERF_PLTFRM_OVR and PROCHOT_LOCK. + * The value set by FSP is 20_005f, we set it to 1a_00a4_005b. + */ + msr = rdmsr(MSR_POWER_CTL); + msr.lo |= (0x16 << RESERVED1_SHIFT) | PWR_PERF_PLTFRM_OVR | PROCHOT_LOCK; + msr.hi = 0x1a; + wrmsr(MSR_POWER_CTL, msr); + + /* Set static, idle, dynamic load line impedance */ + msr = rdmsr(MSR_VR_MISC_CONFIG); + msr.lo = 0x1a1a1a; + wrmsr(MSR_VR_MISC_CONFIG, msr); + + /* Set current limitation */ + msr = rdmsr(MSR_VR_CURRENT_CONFIG); + msr.lo = 0x1130; + msr.lo |= CURRENT_LIMIT_LOCK; + wrmsr(MSR_VR_CURRENT_CONFIG, msr); + + /* Set Turbo Ratio Limits */ + msr.lo = chip_config->turbo_ratio_limit & 0xffffffff; + msr.hi = (chip_config->turbo_ratio_limit >> 32) & 0xffffffff; + wrmsr(MSR_TURBO_RATIO_LIMIT, msr); + + /* Set Turbo Ratio Limit Cores */ + msr.lo = chip_config->turbo_ratio_limit_cores & 0xffffffff; + msr.hi = (chip_config->turbo_ratio_limit_cores >> 32) & 0xffffffff; + wrmsr(MSR_TURBO_RATIO_LIMIT_CORES, msr); + + /* Set energy policy */ + msr = rdmsr(MSR_ENERGY_PERF_BIAS_CONFIG); + msr.lo = 0x178fa038; + wrmsr(MSR_ENERGY_PERF_BIAS_CONFIG, msr); + + msr.hi = 0x158d20; + msr.lo = 0x00158af0; + wrmsr(PACKAGE_RAPL_LIMIT, msr); + + /* + * Set HWP base feature, EPP reg enumeration, lock thermal and msr + * This is package level MSR. Need to check if it updates correctly on + * multi-socket platform. + */ + msr = rdmsr(MSR_MISC_PWR_MGMT); + if (!(msr.lo & LOCK_MISC_PWR_MGMT_MSR)) { /* if already locked skip update */ + msr.lo = (HWP_ENUM_ENABLE | HWP_EPP_ENUM_ENABLE | LOCK_MISC_PWR_MGMT_MSR + | LOCK_THERM_INT); + wrmsr(MSR_MISC_PWR_MGMT, msr); + } + + /* Enable Fast Strings */ + msr = rdmsr(IA32_MISC_ENABLE); + msr.lo |= FAST_STRINGS_ENABLE_BIT; + wrmsr(IA32_MISC_ENABLE, msr); + /* Enable Turbo */ + enable_turbo(); + + /* Enable speed step. */ + if (get_turbo_state() == TURBO_ENABLED) { + msr = rdmsr(IA32_MISC_ENABLE); + msr.lo |= SPEED_STEP_ENABLE_BIT; + wrmsr(IA32_MISC_ENABLE, msr); + } + + /* Lock the supported Cstates */ + msr = rdmsr(MSR_PKG_CST_CONFIG_CONTROL); + msr.lo |= CST_CFG_LOCK_MASK; + wrmsr(MSR_PKG_CST_CONFIG_CONTROL, msr); + + /* Disable all writes to overclocking limits MSR */ + msr = rdmsr(MSR_FLEX_RATIO); + msr.lo |= MSR_FLEX_RATIO_OC_LOCK; + wrmsr(MSR_FLEX_RATIO, msr); + + /* Lock Power Plane Limit MSR */ + msr = rdmsr(MSR_DRAM_PLANE_POWER_LIMIT); + msr.hi |= MSR_HI_PP_PWR_LIM_LOCK; + wrmsr(MSR_DRAM_PLANE_POWER_LIMIT, msr); + + /* Clear out pending MCEs */ + xeon_configure_mca(); + + /* Enable Vmx */ + // set_vmx_and_lock(); + /* only lock. let vmx enable by FSP */ + set_feature_ctrl_lock(); +} + +static struct device_operations cpu_dev_ops = { + .init = each_cpu_init, +}; + +static const struct cpu_device_id cpu_table[] = { + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_D}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E0}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E2}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E3}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E4}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_Ex}, + {0, 0}, +}; + +static const struct cpu_driver driver __cpu_driver = { + .ops = &cpu_dev_ops, + .id_table = cpu_table, +}; + +static void set_max_turbo_freq(void) +{ + msr_t msr, perf_ctl; + + FUNC_ENTER(); + perf_ctl.hi = 0; + + /* Check for configurable TDP option */ + if (get_turbo_state() == TURBO_ENABLED) { + msr = rdmsr(MSR_TURBO_RATIO_LIMIT); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else if (cpu_config_tdp_levels()) { + /* Set to nominal TDP ratio */ + msr = rdmsr(MSR_CONFIG_TDP_NOMINAL); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else { + /* Platform Info bits 15:8 give max ratio */ + msr = rdmsr(MSR_PLATFORM_INFO); + perf_ctl.lo = msr.lo & 0xff00; + } + wrmsr(IA32_PERF_CTL, perf_ctl); + + printk(BIOS_DEBUG, "cpu: frequency set to %d\n", + ((perf_ctl.lo >> 8) & 0xff) * CONFIG_CPU_BCLK_MHZ); + FUNC_EXIT(); +} + +/* + * Do essential initialization tasks before APs can be fired up + */ +static void pre_mp_init(void) +{ + x86_setup_mtrrs_with_detect(); + x86_mtrr_check(); +} + +static int get_thread_count(void) +{ + unsigned int num_phys = 0, num_virts = 0; + + cpu_read_topology(&num_phys, &num_virts); + printk(BIOS_SPEW, "Detected %u cores and %u threads\n", num_phys, num_virts); + return num_virts * soc_get_num_cpus(); +} + +static void post_mp_init(void) +{ + /* Set Max Ratio */ + set_max_turbo_freq(); + + if (CONFIG(HAVE_SMI_HANDLER)) { + global_smi_enable(); + if (get_lockdown_config() == CHIPSET_LOCKDOWN_COREBOOT) + pmc_lock_smi(); + } +} + +static const struct mp_ops mp_ops = { + .pre_mp_init = pre_mp_init, + .get_cpu_count = get_thread_count, +#if CONFIG(HAVE_SMI_HANDLER) + .get_smm_info = get_smm_info, + .pre_mp_smm_init = smm_southbridge_clear_state, + .relocation_handler = smm_relocation_handler, +#endif + .get_microcode_info = get_microcode_info, + .post_mp_init = post_mp_init, +}; + +void mp_init_cpus(struct bus *bus) +{ + /* + * chip_config is used in cpu device callback. Other than cpu 0, + * rest of the CPU devices do not have chip_info updated. + */ + chip_config = bus->dev->chip_info; + + microcode_patch = intel_microcode_find(); + + if (!microcode_patch) + printk(BIOS_ERR, "microcode not found in CBFS!\n"); + + intel_microcode_load_unlocked(microcode_patch); + + if (mp_init_with_smm(bus, &mp_ops) < 0) + printk(BIOS_ERR, "MP initialization failure.\n"); + + /* update numa domain for all cpu devices */ + xeonsp_init_cpu_config(); +} |