/* SPDX-License-Identifier: GPL-2.0-only */ /* * This file is created based on Intel Alder Lake Processor CPU Datasheet * Document number: 619501 * Chapter number: 14 */ #include <console/console.h> #include <device/pci.h> #include <device/pci_ids.h> #include <cpu/x86/mp.h> #include <cpu/x86/msr.h> #include <cpu/intel/smm_reloc.h> #include <cpu/intel/turbo.h> #include <cpu/intel/common/common.h> #include <fsp/api.h> #include <intelblocks/cpulib.h> #include <intelblocks/mp_init.h> #include <intelblocks/msr.h> #include <intelblocks/acpi.h> #include <soc/cpu.h> #include <soc/msr.h> #include <soc/pci_devs.h> #include <soc/soc_chip.h> #include <types.h> enum alderlake_model { ADL_MODEL_P_M = 0x9A, ADL_MODEL_N = 0xBE, }; bool cpu_soc_is_in_untrusted_mode(void) { msr_t msr; msr = rdmsr(MSR_BIOS_DONE); return !!(msr.lo & ENABLE_IA_UNTRUSTED); } void cpu_soc_bios_done(void) { msr_t msr; msr = rdmsr(MSR_BIOS_DONE); msr.lo |= ENABLE_IA_UNTRUSTED; wrmsr(MSR_BIOS_DONE, msr); } static void soc_fsp_load(void) { fsps_load(); } static void configure_misc(void) { msr_t msr; const config_t *conf = config_of_soc(); msr = rdmsr(IA32_MISC_ENABLE); msr.lo |= (1 << 0); /* Fast String enable */ msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ wrmsr(IA32_MISC_ENABLE, msr); /* Set EIST status */ cpu_set_eist(conf->eist_enable); /* Disable Thermal interrupts */ msr.lo = 0; msr.hi = 0; wrmsr(IA32_THERM_INTERRUPT, msr); /* Enable package critical interrupt only */ msr.lo = 1 << 4; msr.hi = 0; wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr); /* Enable PROCHOT and Energy/Performance Bias control */ msr = rdmsr(MSR_POWER_CTL); msr.lo |= (1 << 0); /* Enable Bi-directional PROCHOT as an input */ msr.lo |= (1 << 23); /* Lock it */ msr.lo |= (1 << 18); /* Energy/Performance Bias control */ wrmsr(MSR_POWER_CTL, msr); } enum core_type get_soc_cpu_type(void) { struct cpuinfo_x86 cpuinfo; if (cpu_is_hybrid_supported()) return cpu_get_cpu_type(); get_fms(&cpuinfo, cpuid_eax(1)); if (cpuinfo.x86 == 0x6 && cpuinfo.x86_model == ADL_MODEL_N) return CPUID_CORE_TYPE_INTEL_ATOM; else return CPUID_CORE_TYPE_INTEL_CORE; } bool soc_is_nominal_freq_supported(void) { return true; } /* All CPUs including BSP will run the following function. */ void soc_core_init(struct device *cpu) { /* Clear out pending MCEs */ /* TODO(adurbin): This should only be done on a cold boot. Also, some * of these banks are core vs package scope. For now every CPU clears * every bank. */ mca_configure(); enable_lapic_tpr(); /* Configure Enhanced SpeedStep and Thermal Sensors */ configure_misc(); enable_pm_timer_emulation(); /* Enable Direct Cache Access */ configure_dca_cap(); /* Set energy policy. The "normal" EPB (6) is not suitable for Alder * Lake or Raptor Lake CPUs, as this results in higher uncore power. */ set_energy_perf_bias(7); const config_t *conf = config_of_soc(); /* Set energy-performance preference */ if (conf->enable_energy_perf_pref) if (check_energy_perf_cap()) set_energy_perf_pref(conf->energy_perf_pref_value); /* Enable Turbo */ enable_turbo(); if (CONFIG(INTEL_TME) && is_tme_supported()) set_tme_core_activate(); } static void per_cpu_smm_trigger(void) { /* Relocate the SMM handler. */ smm_relocate(); } static void pre_mp_init(void) { soc_fsp_load(); const config_t *conf = config_of_soc(); if (conf->enable_energy_perf_pref) { if (check_energy_perf_cap()) enable_energy_perf_pref(); else printk(BIOS_WARNING, "Energy Performance Preference not supported!\n"); } } static void post_mp_init(void) { /* Set Max Ratio */ cpu_set_max_ratio(); /* * 1. Now that all APs have been relocated as well as the BSP let SMIs * start flowing. * 2. Skip enabling power button SMI and enable it after BS_CHIPS_INIT * to avoid shutdown hang due to lack of init on certain IP in FSP-S. */ global_smi_enable_no_pwrbtn(); } static const struct mp_ops mp_ops = { /* * Skip Pre MP init MTRR programming as MTRRs are mirrored from BSP, * that are set prior to ramstage. * Real MTRRs programming are being done after resource allocation. */ .pre_mp_init = pre_mp_init, .get_cpu_count = get_cpu_count, .get_smm_info = smm_info, .get_microcode_info = get_microcode_info, .pre_mp_smm_init = smm_initialize, .per_cpu_smm_trigger = per_cpu_smm_trigger, .relocation_handler = smm_relocation_handler, .post_mp_init = post_mp_init, }; void soc_init_cpus(struct bus *cpu_bus) { /* TODO: Handle mp_init_with_smm failure? */ mp_init_with_smm(cpu_bus, &mp_ops); /* Thermal throttle activation offset */ configure_tcc_thermal_target(); } enum adl_cpu_type get_adl_cpu_type(void) { const uint16_t adl_m_mch_ids[] = { PCI_DID_INTEL_ADL_M_ID_1, PCI_DID_INTEL_ADL_M_ID_2, }; const uint16_t adl_p_mch_ids[] = { PCI_DID_INTEL_ADL_P_ID_1, PCI_DID_INTEL_ADL_P_ID_3, PCI_DID_INTEL_ADL_P_ID_4, PCI_DID_INTEL_ADL_P_ID_5, PCI_DID_INTEL_ADL_P_ID_6, PCI_DID_INTEL_ADL_P_ID_7, PCI_DID_INTEL_ADL_P_ID_8, PCI_DID_INTEL_ADL_P_ID_9, PCI_DID_INTEL_ADL_P_ID_10 }; const uint16_t adl_s_mch_ids[] = { PCI_DID_INTEL_ADL_S_ID_1, PCI_DID_INTEL_ADL_S_ID_2, PCI_DID_INTEL_ADL_S_ID_3, PCI_DID_INTEL_ADL_S_ID_4, PCI_DID_INTEL_ADL_S_ID_5, PCI_DID_INTEL_ADL_S_ID_6, PCI_DID_INTEL_ADL_S_ID_7, PCI_DID_INTEL_ADL_S_ID_8, PCI_DID_INTEL_ADL_S_ID_9, PCI_DID_INTEL_ADL_S_ID_10, PCI_DID_INTEL_ADL_S_ID_11, PCI_DID_INTEL_ADL_S_ID_12, PCI_DID_INTEL_ADL_S_ID_13, PCI_DID_INTEL_ADL_S_ID_14, PCI_DID_INTEL_ADL_S_ID_15, }; const uint16_t adl_n_mch_ids[] = { PCI_DID_INTEL_ADL_N_ID_1, PCI_DID_INTEL_ADL_N_ID_2, PCI_DID_INTEL_ADL_N_ID_3, PCI_DID_INTEL_ADL_N_ID_4, }; const uint16_t rpl_p_mch_ids[] = { PCI_DID_INTEL_RPL_P_ID_1, PCI_DID_INTEL_RPL_P_ID_2, PCI_DID_INTEL_RPL_P_ID_3, PCI_DID_INTEL_RPL_P_ID_4, PCI_DID_INTEL_RPL_P_ID_5, }; const uint16_t mchid = pci_s_read_config16(PCI_DEV(0, PCI_SLOT(SA_DEVFN_ROOT), PCI_FUNC(SA_DEVFN_ROOT)), PCI_DEVICE_ID); for (size_t i = 0; i < ARRAY_SIZE(adl_p_mch_ids); i++) { if (adl_p_mch_ids[i] == mchid) return ADL_P; } for (size_t i = 0; i < ARRAY_SIZE(adl_m_mch_ids); i++) { if (adl_m_mch_ids[i] == mchid) return ADL_M; } for (size_t i = 0; i < ARRAY_SIZE(adl_s_mch_ids); i++) { if (adl_s_mch_ids[i] == mchid) return ADL_S; } for (size_t i = 0; i < ARRAY_SIZE(adl_n_mch_ids); i++) { if (adl_n_mch_ids[i] == mchid) return ADL_N; } for (size_t i = 0; i < ARRAY_SIZE(rpl_p_mch_ids); i++) { if (rpl_p_mch_ids[i] == mchid) return RPL_P; } return ADL_UNKNOWN; } uint8_t get_supported_lpm_mask(void) { enum adl_cpu_type type = get_adl_cpu_type(); switch (type) { case ADL_M: /* fallthrough */ case ADL_N: case ADL_P: case RPL_P: return LPM_S0i2_0 | LPM_S0i3_0; case ADL_S: return LPM_S0i2_0 | LPM_S0i2_1; default: printk(BIOS_ERR, "Unknown ADL CPU type: %d\n", type); return 0; } }