diff options
author | Felix Held <felix-coreboot@felixheld.de> | 2023-03-06 23:31:40 +0100 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2023-03-08 12:00:11 +0000 |
commit | d3b077e2b6329ea1d6e36d8abc56b8740a9e79d7 (patch) | |
tree | fb7eb741d1eb6324e944a537e82487a58ed8b5d7 /src | |
parent | e930360bbe2239723ea9f7c493860053a069e71f (diff) |
soc/amd/common/block/acpi/cpu_power_state: add get_cstate_info helper
Introduce the get_cstate_info helper function that populates the caller-
provided cstate_values array with the data returned by the SoC-specific
get_cstate_config_data function. From the array get_cstate_config_data
returns, only the ctype, latency and power fields are used, so the rest
can be left uninitialized. Those 3 fields are compile-time constants.
For each entry, write_cstate_entry will generate the corresponding
resource information from the given data. In the C1 case where ctype is
1, the state is entered via a MWAIT instruction, while the higher C
states are entered by doing an IO read from a specific IO address. This
IO address is x - 1 bytes into the IO region starting at
MSR_CSTATE_ADDRESS for the Cx state. So for example C2 is entered by
reading from the C state IO base address + 1. This resource information
is generated during runtime, since the contents of MSR_CSTATE_ADDRESS
aren't necessarily known at compile-time.
MAX_CSTATE_COUNT is introduced so that the caller can allocate and pass
a buffer with space for the maximum number of C state entries. This
maximum number corresponds to the number of IO addresses the CPU traps
beginning from MSR_CSTATE_ADDRESS. In practice, it's unlikely that more
than 3 or maybe 4 C states will be available though.
Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Change-Id: I2c36c1d604ced349c609882b9d9fe84d5f726a8d
Reviewed-on: https://review.coreboot.org/c/coreboot/+/73428
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Fred Reitberger <reitbergerfred@gmail.com>
Reviewed-by: Eric Lai <eric_lai@quanta.corp-partner.google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/amd/common/block/acpi/Kconfig | 3 | ||||
-rw-r--r-- | src/soc/amd/common/block/acpi/Makefile.inc | 1 | ||||
-rw-r--r-- | src/soc/amd/common/block/acpi/cpu_power_state.c | 65 | ||||
-rw-r--r-- | src/soc/amd/common/block/include/amdblocks/cpu.h | 8 |
4 files changed, 77 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/acpi/Kconfig b/src/soc/amd/common/block/acpi/Kconfig index 46251d6c40..039fed8868 100644 --- a/src/soc/amd/common/block/acpi/Kconfig +++ b/src/soc/amd/common/block/acpi/Kconfig @@ -18,6 +18,9 @@ config SOC_AMD_COMMON_BLOCK_ACPI_DPTC config SOC_AMD_COMMON_BLOCK_ACPI_CPPC bool +config SOC_AMD_COMMON_BLOCK_ACPI_CPU_POWER_STATE + bool + config SOC_AMD_COMMON_BLOCK_ACPI_GPIO bool diff --git a/src/soc/amd/common/block/acpi/Makefile.inc b/src/soc/amd/common/block/acpi/Makefile.inc index 2c8f391889..cf1e9c1a14 100644 --- a/src/soc/amd/common/block/acpi/Makefile.inc +++ b/src/soc/amd/common/block/acpi/Makefile.inc @@ -13,6 +13,7 @@ ramstage-y += tables.c ramstage-$(CONFIG_ACPI_BERT) += bert.c ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_ACPI_ALIB) += alib.c ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_ACPI_CPPC) += cppc.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_ACPI_CPU_POWER_STATE) += cpu_power_state.c ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_ACPI_GPIO) += gpio.c ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_ACPI_IVRS) += ivrs.c diff --git a/src/soc/amd/common/block/acpi/cpu_power_state.c b/src/soc/amd/common/block/acpi/cpu_power_state.c new file mode 100644 index 0000000000..d8af0c9244 --- /dev/null +++ b/src/soc/amd/common/block/acpi/cpu_power_state.c @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <acpi/acpigen.h> +#include <amdblocks/cpu.h> +#include <console/console.h> +#include <cpu/amd/msr.h> +#include <cpu/x86/msr.h> +#include <types.h> + +static void write_cstate_entry(acpi_cstate_t *entry, const acpi_cstate_t *data, + uint32_t cstate_io_base_address) +{ + if (!data->ctype) { + printk(BIOS_WARNING, "Invalid C-state data; skipping entry.\n"); + return; + } + + entry->ctype = data->ctype; + entry->latency = data->latency; + entry->power = data->power; + + if (data->ctype == 1) { + entry->resource = (acpi_addr_t){ + .space_id = ACPI_ADDRESS_SPACE_FIXED, + .bit_width = 2, + .bit_offset = 2, + .addrl = 0, + .addrh = 0, + }; + } else { + entry->resource = (acpi_addr_t){ + .space_id = ACPI_ADDRESS_SPACE_IO, + .bit_width = 8, + .bit_offset = 0, + /* ctype is 1-indexed while the offset into cstate_io_base_address is + 0-indexed */ + .addrl = cstate_io_base_address + data->ctype - 1, + .addrh = 0, + .access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS, + }; + } +} + +size_t get_cstate_info(acpi_cstate_t *cstate_values) +{ + size_t i; + size_t cstate_count; + uint32_t cstate_io_base_address = + rdmsr(MSR_CSTATE_ADDRESS).lo & MSR_CSTATE_ADDRESS_MASK; + const acpi_cstate_t *cstate_config = get_cstate_config_data(&cstate_count); + + if (cstate_count > MAX_CSTATE_COUNT) { + printk(BIOS_WARNING, "cstate_info array has too many entries. " + "Skipping last %zu entries.\n", + cstate_count - MAX_CSTATE_COUNT); + cstate_count = MAX_CSTATE_COUNT; + } + + for (i = 0; i < cstate_count; i++) { + write_cstate_entry(&cstate_values[i], &cstate_config[i], cstate_io_base_address); + } + + return i; +} diff --git a/src/soc/amd/common/block/include/amdblocks/cpu.h b/src/soc/amd/common/block/include/amdblocks/cpu.h index de3fb84d12..a380a2df93 100644 --- a/src/soc/amd/common/block/include/amdblocks/cpu.h +++ b/src/soc/amd/common/block/include/amdblocks/cpu.h @@ -3,10 +3,18 @@ #ifndef AMD_BLOCK_CPU_H #define AMD_BLOCK_CPU_H +#include <acpi/acpi.h> +#include <types.h> + +#define MAX_CSTATE_COUNT 8 + void early_cache_setup(void); int get_cpu_count(void); unsigned int get_threads_per_core(void); void set_cstate_io_addr(void); void write_resume_eip(void); +size_t get_cstate_info(acpi_cstate_t *cstate_values); +const acpi_cstate_t *get_cstate_config_data(size_t *size); + #endif /* AMD_BLOCK_CPU_H */ |