Hello Jason Glenesk,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/45340
to review the following change.
Change subject: /soc/amd/picasso: Generate ACPI pstate and cstate objects in cb ......................................................................
/soc/amd/picasso: Generate ACPI pstate and cstate objects in cb
Add code to generate p-state and c-state SSDT objects to coreboot. Publish objects generated in native coreboot, rather than the ones created by FSP binary.
BUG=b:155307433 TEST=Boot morphius to shell and extract and compare objects created in coreboot with tables generated by FSP. Confirm they are equivalent. BRANCH=Zork
Change-Id: I5f4db3c0c2048ea1d6c6ce55f5e252cb15598514 Signed-off-by: Jason Glenesk jason.glenesk@amd.corp-partner.google.com --- M src/include/cpu/amd/msr.h M src/soc/amd/common/block/include/amdblocks/acpi.h M src/soc/amd/picasso/Kconfig M src/soc/amd/picasso/acpi.c M src/soc/amd/picasso/agesa_acpi.c 5 files changed, 288 insertions(+), 10 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/40/45340/1
diff --git a/src/include/cpu/amd/msr.h b/src/include/cpu/amd/msr.h index 8bc00d1..710ba43 100644 --- a/src/include/cpu/amd/msr.h +++ b/src/include/cpu/amd/msr.h @@ -12,6 +12,9 @@
#define CPUID_EXT_PM 0x80000007 #define CPUID_MODEL 1 +#define CPUID_EBX_CORE_ID 0x8000001E +#define CPUID_EBX_THREADS_SHIFT 8 +#define CPUID_EBX_THREADS_MASK (0xFF << CPUID_EBX_THREADS_SHIFT) #define MC4_MISC0 0x00000413 #define MC4_MISC1 0xC0000408 #define MC4_MISC2 0xC0000409 @@ -43,7 +46,23 @@ #define PSTATE_2_MSR 0xC0010066 #define PSTATE_3_MSR 0xC0010067 #define PSTATE_4_MSR 0xC0010068 +#define PSTATE_DEF_HI_ENABLE_SHIFT 31 +#define PSTATE_DEF_HI_ENABLE_MASK (0x1 << PSTATE_DEF_HI_ENABLE_SHIFT) +#define PSTATE_DEF_LO_CUR_DIV_SHIFT 30 +#define PSTATE_DEF_LO_CUR_DIV_MASK (0x3 << PSTATE_DEF_LO_CUR_DIV_SHIFT) +#define PSTATE_DEF_LO_CUR_VAL_SHIFT 22 +#define PSTATE_DEF_LO_CUR_VAL_MASK (0xFF << PSTATE_DEF_LO_CUR_VAL_SHIFT) +#define PSTATE_DEF_LO_CORE_VID_SHIFT 14 +#define PSTATE_DEF_LO_CORE_VID_MASK (0xFF << PSTATE_DEF_LO_CORE_VID_SHIFT) +#define PSTATE_DEF_LO_FREQ_DIV_SHIFT 8 +#define PSTATE_DEF_LO_FREQ_DIV_MASK (0x3F << PSTATE_DEF_LO_FREQ_DIV_SHIFT) +#define PSTATE_DEF_LO_FREQ_MIN 0x8 +#define PSTATE_DEF_LO_FREQ_MAX 0x30 +#define PSTATE_DEF_LO_FREQ_MUL_SHIFT 0 +#define PSTATE_DEF_LO_FREQ_MUL_MASK (0xFF << PSTATE_DEF_LO_FREQ_MUL_SHIFT) +#define PSTATE_DEF_LO_CORE_FREQ_BASE 25
+#define CORE_VOLTAGE_INCREMENT_UV 6250 #define MSR_PATCH_LOADER 0xC0010020
#define MSR_COFVID_STS 0xC0010071 diff --git a/src/soc/amd/common/block/include/amdblocks/acpi.h b/src/soc/amd/common/block/include/amdblocks/acpi.h index b6244cb..cef3151 100644 --- a/src/soc/amd/common/block/include/amdblocks/acpi.h +++ b/src/soc/amd/common/block/include/amdblocks/acpi.h @@ -5,6 +5,7 @@
#include <types.h> #include <soc/nvs.h> +#include <cpu/amd/msr.h>
/* ACPI MMIO registers 0xfed80800 */ #define MMIO_ACPI_PM1_STS 0x00 @@ -27,6 +28,14 @@ uint16_t aligning_field; };
+/* P-state structure for each state */ +typedef struct sw_pstate_values { + uint32_t p_state_enable; ///< Pstate enable + uint32_t core_freq; ///< MHz + uint32_t power; ///< milliWatts + uint32_t sw_state_number; ///< Software P-state number +} sw_pstate_values_t; + /* Fill object with the ACPI PM and GPE state. */ void acpi_fill_pm_gpe_state(struct acpi_pm_gpe_state *state); /* Save events to eventlog log and also print information on console. */ @@ -36,6 +45,22 @@ /* Fill GNVS object from PM GPE object. */ void acpi_fill_gnvs(struct global_nvs *gnvs, const struct acpi_pm_gpe_state *state);
+void write_pct_object(void); + +uint32_t get_pstate_core_freq(msr_t pstate_def); + +uint32_t get_pstate_core_power(msr_t pstate_def); + +int get_pstate_info( sw_pstate_values_t *pstate_values, int *max_pstate, uint32_t *thread_count); + +void write_pss_object(int pstate_count, int max_pstate, sw_pstate_values_t* new_pstate_values); + +void write_xpss_object(int pstate_count, int max_pstate, sw_pstate_values_t* new_pstate_values); + +void write_ppc_object(void); + +void write_cst_object(void); + /* * If a system reset is about to be requested, modify the PM1 register so it * will never be misinterpreted as an S3 resume. diff --git a/src/soc/amd/picasso/Kconfig b/src/soc/amd/picasso/Kconfig index 642935f..b198acc 100644 --- a/src/soc/amd/picasso/Kconfig +++ b/src/soc/amd/picasso/Kconfig @@ -338,6 +338,14 @@ Specify the amount of DRAM reserved for gathering the data used to generate the ACPI table.
+config ACPI_SSDT_PSD_INDEPENDENT + bool "Allow core p-state independent transitions" + default y + help + AMD recommends the ACPI _PSD object to be configured to cause + cores to transition between p-states independently. A vendor may + choose to generate _PSD object to allow cores to transition together. + config CHROMEOS select CHROMEOS_RAMOOPS_DYNAMIC select ALWAYS_LOAD_OPROM diff --git a/src/soc/amd/picasso/acpi.c b/src/soc/amd/picasso/acpi.c index 1b9c0ca..a92c7bf 100644 --- a/src/soc/amd/picasso/acpi.c +++ b/src/soc/amd/picasso/acpi.c @@ -26,6 +26,7 @@ #include <soc/gpio.h> #include <version.h> #include "chip.h" +#include <cpu/amd/msr.h>
unsigned long acpi_fill_mcfg(unsigned long current) { @@ -166,20 +167,246 @@ fadt->x_gpe0_blk.addrh = 0x0; }
+void write_pct_object(void) +{ + acpi_addr_t perf_ctrl, perf_sts; + + acpigen_write_name("_PCT"); + acpigen_write_package(0x02); + + memset(&perf_ctrl, 0, sizeof(acpi_addr_t)); + perf_ctrl.space_id = ACPI_ADDRESS_SPACE_FIXED; + perf_ctrl.bit_width = 0x40; + perf_ctrl.addrl = PS_CTL_REG; + acpigen_write_register_resource(&perf_ctrl); + + memset(&perf_sts, 0, sizeof(acpi_addr_t)); + perf_sts.space_id = ACPI_ADDRESS_SPACE_FIXED; + perf_sts.bit_width = 0x40; + acpigen_write_register_resource(&perf_sts); + + acpigen_pop_len(); +} + +uint32_t get_pstate_core_freq(msr_t pstate_def) +{ + uint32_t core_freq, core_freq_mul, core_freq_div; + + /* Core frequency multiplier */ + core_freq_mul = pstate_def.lo & PSTATE_DEF_LO_FREQ_MUL_MASK; + + /* Core frequency divisor ID */ + core_freq_div = (pstate_def.lo & PSTATE_DEF_LO_FREQ_DIV_MASK) + >> PSTATE_DEF_LO_FREQ_DIV_SHIFT; + + if (core_freq_div == 0) { + core_freq = 0; + } else if ((core_freq_div >= PSTATE_DEF_LO_FREQ_MIN) && + (core_freq_div <= PSTATE_DEF_LO_FREQ_MAX)) { + core_freq = ((200 * core_freq_mul) /(core_freq_div)); + } else { + printk (BIOS_WARNING, "Undefined core_freq_div %x used. Force to 1.\n", core_freq_div); + core_freq = (PSTATE_DEF_LO_CORE_FREQ_BASE * core_freq_mul); + } + return core_freq; +} + +uint32_t get_pstate_core_power(msr_t pstate_def) +{ + uint32_t voltage_in_uvolts, core_vid, current_value, current_divisor, power_in_mw; + + /* Core voltage ID */ + core_vid = (pstate_def.lo & PSTATE_DEF_LO_CORE_VID_MASK) + >> PSTATE_DEF_LO_CORE_VID_SHIFT; + + /* Current value in amps */ + current_value = (pstate_def.lo & PSTATE_DEF_LO_CUR_VAL_MASK) + >> PSTATE_DEF_LO_CUR_VAL_SHIFT; + + /* Current divisor */ + current_divisor = (pstate_def.lo & PSTATE_DEF_LO_CUR_DIV_MASK) + >> PSTATE_DEF_LO_CUR_DIV_SHIFT; + + /* Voltage */ + if ((core_vid >= 0xF8) && (core_vid <= 0xFF)) { + /* Voltage off for VID codes 0xF8 to 0xFF */ + voltage_in_uvolts = 0; + } else { + voltage_in_uvolts = 1550000L - (CORE_VOLTAGE_INCREMENT_UV * core_vid); + } + + /* Power in mW */ + power_in_mw = (voltage_in_uvolts) / 10 * current_value; + switch (current_divisor) { + case 0: + power_in_mw= power_in_mw / 100L; + break; + case 1: + power_in_mw = power_in_mw / 1000L; + break; + case 2: + power_in_mw = power_in_mw / 10000L; + break; + default: + /* current_divisor is set to an undefined value.*/ + power_in_mw = 0; + break; + } + return power_in_mw; +} + +int get_pstate_info( sw_pstate_values_t *pstate_values, int *max_pstate, uint32_t *thread_count) +{ + msr_t pstate_def; + int pstate_count, pstate; + + pstate_count = 0; + + *max_pstate = (rdmsr(PS_LIM_REG).lo >> PS_MAX_VAL_SHFT) & 0x3; + + *thread_count = (cpuid_ebx(CPUID_EBX_CORE_ID) & CPUID_EBX_THREADS_MASK) ? 2:1; + + for(pstate = 0; pstate <= *max_pstate; pstate++){ + pstate_def = rdmsr(PSTATE_0_MSR + pstate); + pstate_values[pstate].p_state_enable = (pstate_def.hi & PSTATE_DEF_HI_ENABLE_MASK) + >> PSTATE_DEF_HI_ENABLE_SHIFT; + pstate_values[pstate].core_freq = get_pstate_core_freq(pstate_def); + pstate_values[pstate].power = get_pstate_core_power(pstate_def); + pstate_values[pstate].sw_state_number = pstate; + + if(pstate_values[pstate].p_state_enable){ + pstate_count++; + } + } + + return pstate_count; +} + +void write_pss_object(int pstate_count, int max_pstate, sw_pstate_values_t* pstate_values) +{ + int pstate; + + acpigen_write_name("_PSS"); + acpigen_write_package(pstate_count); + for(pstate = 0; pstate <= max_pstate; pstate++){ + if(pstate_values->p_state_enable){ + acpigen_write_PSS_package(pstate_values->core_freq, + pstate_values->power,0, 0, pstate_values->sw_state_number, + pstate_values->sw_state_number); + } + pstate_values++; + } + acpigen_pop_len(); +} + +void write_xpss_object(int pstate_count, int max_pstate, sw_pstate_values_t* pstate_values) +{ + int pstate; + uint64_t bytes; + + acpigen_write_name("XPSS"); + acpigen_write_package(pstate_count); + for(pstate = 0; pstate <= max_pstate; pstate++){ + acpigen_write_package(0x08); + acpigen_write_dword(pstate_values->core_freq); + acpigen_write_dword( pstate_values->power); + acpigen_write_dword(0); + acpigen_write_dword(0); + + bytes = pstate_values->sw_state_number; + acpigen_write_byte_buffer((uint8_t*)&bytes,8); + acpigen_write_byte_buffer((uint8_t*)&bytes,8); + + bytes=0; + acpigen_write_byte_buffer((uint8_t*)&bytes,8); + acpigen_write_byte_buffer((uint8_t*)&bytes,8); + + acpigen_pop_len(); + pstate_values++; + } + acpigen_pop_len(); +} + +void write_ppc_object(void) +{ + acpigen_write_name("PPCV"); + acpigen_write_byte(0); + + acpigen_write_method("_PPC", 0); + acpigen_emit_byte(RETURN_OP); + acpigen_emit_namestring("PPCV"); + acpigen_pop_len(); +} + +void write_cst_object(void) +{ + acpi_cstate_t cstate_info[3]; + acpi_addr_t cstate_addr; + + cstate_addr.space_id = ACPI_ADDRESS_SPACE_FIXED; + cstate_addr.bit_width = 0x2; + cstate_addr.bit_offset = 0x2; + cstate_addr.access_size = 0; + cstate_addr.addrl = 0; + cstate_addr.addrh = 0; + + cstate_info[0].ctype = 1; + cstate_info[0].latency = 1; + cstate_info[0].power = 0; + cstate_info[0].resource = cstate_addr; + + cstate_addr.space_id = ACPI_ADDRESS_SPACE_IO; + cstate_addr.bit_width = 0x8; + cstate_addr.bit_offset = 0x0; + cstate_addr.access_size = 1; + cstate_addr.addrl = 0x414; + cstate_addr.addrh = 0; + + cstate_info[1].ctype = 2; + cstate_info[1].latency = 400; + cstate_info[1].power = 0; + cstate_info[1].resource = cstate_addr; + acpigen_write_CST_package(cstate_info, 2); +} + void generate_cpu_entries(const struct device *device) { - int cores, cpu; + int logical_cores , pstate_count, max_pstate, cpu; + sw_pstate_values_t pstate_values[7]; + uint32_t thread_count;
- cores = get_cpu_count(); - printk(BIOS_DEBUG, "ACPI \_SB report %d core(s)\n", cores); + pstate_count = get_pstate_info(pstate_values, &max_pstate, &thread_count); + logical_cores = get_cpu_count();
- /* Generate BSP _SB.P000 */ - acpigen_write_processor(0, ACPI_GPE0_BLK, 6); - acpigen_pop_len(); + for (cpu = 0; cpu < logical_cores; cpu++) {
- /* Generate AP _SB.Pxxx */ - for (cpu = 1; cpu < cores; cpu++) { - acpigen_write_processor(cpu, 0, 0); + if(cpu == 0){ + /* Generate BSP _SB.P000 */ + acpigen_write_processor(0, ACPI_GPE0_BLK, 6); + + }else{ + /* Generate AP _SB.Pxxx */ + acpigen_write_processor(cpu, 0, 0); + } + + write_pct_object(); + + write_pss_object(pstate_count, max_pstate, &pstate_values[0]); + + write_xpss_object(pstate_count, max_pstate, &pstate_values[0]); + + if(CONFIG(ACPI_SSDT_PSD_INDEPENDENT)){ + acpigen_write_PSD_package(cpu /thread_count, thread_count, HW_ALL); + }else{ + acpigen_write_PSD_package(0, logical_cores, SW_ALL); + } + + write_ppc_object(); + + write_cst_object(); + + acpigen_write_CSD_package(cpu >> 1,thread_count, HW_ALL,0 ); + acpigen_pop_len(); } } diff --git a/src/soc/amd/picasso/agesa_acpi.c b/src/soc/amd/picasso/agesa_acpi.c index a651d6e..7ddd31e 100644 --- a/src/soc/amd/picasso/agesa_acpi.c +++ b/src/soc/amd/picasso/agesa_acpi.c @@ -508,7 +508,6 @@
printk(BIOS_DEBUG, "Searching for AGESA FSP ACPI Tables\n");
- current = add_agesa_acpi_table(AMD_FSP_ACPI_SSDT_HOB_GUID, "SSDT", rsdp, current); current = add_agesa_acpi_table(AMD_FSP_ACPI_CRAT_HOB_GUID, "CRAT", rsdp, current); current = add_agesa_acpi_table(AMD_FSP_ACPI_ALIB_HOB_GUID, "ALIB", rsdp, current);