diff --git a/src/soc/intel/common/block/acpi/Kconfig b/src/soc/intel/common/block/acpi/Kconfig index 07e9bea8d3..e21584c073 100644 --- a/src/soc/intel/common/block/acpi/Kconfig +++ b/src/soc/intel/common/block/acpi/Kconfig @@ -44,4 +44,9 @@ config SOC_INTEL_COMMON_BLOCK_ACPI_CPPC help Generate CPPC entries for Intel SpeedShift +config SOC_INTEL_COMMON_BLOCK_ACPI_CPU_HYBRID + bool + help + Defines hybrid CPU specific ACPI helper functions. + endif diff --git a/src/soc/intel/common/block/acpi/Makefile.inc b/src/soc/intel/common/block/acpi/Makefile.inc index a6eb80db36..0286d942dc 100644 --- a/src/soc/intel/common/block/acpi/Makefile.inc +++ b/src/soc/intel/common/block/acpi/Makefile.inc @@ -5,3 +5,4 @@ ramstage-$(CONFIG_ACPI_BERT) += acpi_bert.c ramstage-$(CONFIG_SOC_INTEL_COMMON_ACPI_WAKE_SOURCE) += acpi_wake_source.c ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI_PEP) += pep.c ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SGX_ENABLE) += sgx.c +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI_CPU_HYBRID) += cpu_hybrid.c diff --git a/src/soc/intel/common/block/acpi/cpu_hybrid.c b/src/soc/intel/common/block/acpi/cpu_hybrid.c new file mode 100644 index 0000000000..cbfaed8fd3 --- /dev/null +++ b/src/soc/intel/common/block/acpi/cpu_hybrid.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_SPIN_LOCK(cpu_lock); +static u8 global_cpu_type[CONFIG_MAX_CPUS]; + +static bool is_big_core(void) +{ + return get_soc_cpu_type() == CPUID_CORE_TYPE_INTEL_CORE; +} + +static u32 get_cpu_index(void) +{ + u32 cpu_index = 0; + struct device *dev; + u32 my_apic_id = lapicid(); + + for (dev = dev_find_lapic(0); dev; dev = dev->next) { + if (my_apic_id > dev->path.apic.apic_id) + cpu_index++; + } + + return cpu_index; +} + +/* + * This function determines the type (big or small) of the CPU that is executing + * it and stores the information (in a thread-safe manner) in an global_cpu_type + * array. + * It requires the SoC to implement a function `get_soc_cpu_type()` which will be + * called in a critical section to determine the type of the executing CPU. + */ +static void set_cpu_type(void *unused) +{ + spin_lock(&cpu_lock); + u8 cpu_index = get_cpu_index(); + + if (is_big_core()) + global_cpu_type[cpu_index] = 1; + + spin_unlock(&cpu_lock); +} + +static void run_set_cpu_type(void *unused) +{ + if (mp_run_on_all_cpus(set_cpu_type, NULL) != CB_SUCCESS) { + printk(BIOS_ERR, "cpu_hybrid: Failed to set global_cpu_type with CPU type info\n"); + return; + } +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, run_set_cpu_type, NULL); diff --git a/src/soc/intel/common/block/include/intelblocks/acpi.h b/src/soc/intel/common/block/include/intelblocks/acpi.h index 2d3136eae6..26341451d0 100644 --- a/src/soc/intel/common/block/include/intelblocks/acpi.h +++ b/src/soc/intel/common/block/include/intelblocks/acpi.h @@ -9,6 +9,15 @@ #include #include +/* CPU Types */ +enum core_type { + CPUID_RESERVED_1 = 0x10, + CPUID_CORE_TYPE_INTEL_ATOM = 0x20, + CPUID_RESERVED_2 = 0x30, + CPUID_CORE_TYPE_INTEL_CORE = 0x40, + CPUID_UNKNOWN = 0xff, +}; + /* Forward declare the power state struct here */ struct chipset_power_state; @@ -108,4 +117,12 @@ void generate_acpi_power_engine_with_lpm(const struct soc_pmc_lpm *lpm); /* Fill SSDT for SGX status, EPC base and length */ void sgx_fill_ssdt(void); +/* + * This function returns the CPU type (big or small) of the CPU that it is executing + * on. It is designed to be called after MP initialization. If the SoC selects + * SOC_INTEL_COMMON_BLOCK_ACPI_CPU_HYBRID, then this function must be implemented, + * and will be called from set_cpu_type(). + */ +enum core_type get_soc_cpu_type(void); + #endif /* _SOC_INTEL_COMMON_BLOCK_ACPI_H_ */