summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/amd/common/block/acpi/Kconfig3
-rw-r--r--src/soc/amd/common/block/acpi/Makefile.inc1
-rw-r--r--src/soc/amd/common/block/acpi/cpu_power_state.c65
-rw-r--r--src/soc/amd/common/block/include/amdblocks/cpu.h8
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 */