diff options
Diffstat (limited to 'src/cpu/amd/family_10h-family_15h/powernow_acpi.c')
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/powernow_acpi.c | 135 |
1 files changed, 124 insertions, 11 deletions
diff --git a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c index 0c53e86b4a..a7cc9dad5b 100644 --- a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c +++ b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c @@ -17,6 +17,7 @@ #include <console/console.h> #include <stdint.h> +#include <option.h> #include <cpu/x86/msr.h> #include <arch/acpigen.h> #include <cpu/amd/powernow.h> @@ -30,21 +31,29 @@ #include <northbridge/amd/amdmct/mct/mct.h> #include <northbridge/amd/amdmct/amddefs.h> +static inline uint8_t is_fam15h(void) +{ + uint8_t fam15h = 0; + uint32_t family; + + family = cpuid_eax(0x80000001); + family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8); + + if (family >= 0x6f) + /* Family 15h or later */ + fam15h = 1; + + return fam15h; +} + static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 *pstate_power, u32 *pstate_latency, u32 *pstate_control, u32 *pstate_status, int coreID, - u32 pcontrol_blk, u8 plen, u8 onlyBSP, uint8_t single_link) { int i; struct cpuid_result cpuid1; - if ((onlyBSP) && (coreID != 0)) { - plen = 0; - pcontrol_blk = 0; - } - - acpigen_write_processor(coreID, pcontrol_blk, plen); acpigen_write_empty_PCT(); acpigen_write_name("_PSS"); @@ -88,9 +97,62 @@ static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 *pstate_p if (cpu) acpigen_write_PSD_package(cpu->path.apic.apic_id, 1, SW_ANY); } +} - /* patch the whole Processor token length */ - acpigen_pop_len(); +static void write_cstates_for_core(int coreID) +{ + /* Generate C state entries */ + uint8_t cstate_count = 1; + acpi_cstate_t cstate; + + if (is_fam15h()) { + cstate.ctype = 2; + cstate.latency = 100; + cstate.power = 0; + cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO; + cstate.resource.bit_width = 8; + cstate.resource.bit_offset = 0; + cstate.resource.addrl = rdmsr(0xc0010073).lo + 1; + cstate.resource.addrh = 0; + cstate.resource.resv = 1; + } else { + cstate.ctype = 2; + cstate.latency = 75; + cstate.power = 0; + cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO; + cstate.resource.bit_width = 8; + cstate.resource.bit_offset = 0; + cstate.resource.addrl = rdmsr(0xc0010073).lo; + cstate.resource.addrh = 0; + cstate.resource.resv = 1; + } + + acpigen_write_CST_package(&cstate, cstate_count); + + /* Find the local APIC ID for the specified core ID */ + if (is_fam15h()) { + struct device* cpu; + int cpu_index = 0; + for (cpu = all_devices; cpu; cpu = cpu->next) { + if ((cpu->path.type != DEVICE_PATH_APIC) || + (cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) + continue; + if (!cpu->enabled) + continue; + if (cpu_index == coreID) + break; + cpu_index++; + } + + if (cpu) { + /* TODO + * Detect dual core status and skip CSD generation if dual core is disabled + */ + + /* Generate C state dependency entries */ + acpigen_write_CSD_package((cpu->path.apic.apic_id >> 1) & 0x7f, 2, CSD_HW_ALL, 0); + } + } } /* @@ -121,6 +183,15 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) u8 index; msr_t msr; + uint8_t nvram; + uint8_t enable_c_states; + + enable_c_states = 0; +#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) + if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS) + enable_c_states = !!nvram; +#endif + /* Get the Processor Brand String using cpuid(0x8000000x) command x=2,3,4 */ cpuid1 = cpuid(0x80000002); v = (u32 *) processor_brand; @@ -196,6 +267,10 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) return; } + if (fam15h) + /* Set P_LVL2 P_BLK entry */ + *(((uint8_t *)pcontrol_blk) + 0x04) = (rdmsr(0xc0010073).lo + 1) & 0xff; + uint8_t pviModeFlag; uint8_t Pstate_max; uint8_t cpufid; @@ -314,18 +389,56 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) Pstate_latency[index]); } + /* Enter processor block scope */ char pscope[] = "\\_PR"; - acpigen_write_scope(pscope); + for (index = 0; index < total_core_count; index++) { /* Determine if this is a single-link processor */ node_index = 0x18 + (index / cores_per_node); dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(node_index, 0)), 0x80); single_link = !!(((dtemp & 0xff00) >> 8) == 0); + /* Enter processor core scope */ + uint8_t plen_cur = plen; + uint32_t pcontrol_blk_cur = pcontrol_blk; + if ((onlyBSP) && (index != 0)) { + plen_cur = 0; + pcontrol_blk_cur = 0; + } + acpigen_write_processor(index, pcontrol_blk_cur, plen_cur); + + /* Write P-state status and dependency objects */ write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_power, Pstate_latency, Pstate_control, Pstate_status, - index, pcontrol_blk, plen, onlyBSP, single_link); + index, single_link); + + /* Write C-state status and dependency objects */ + if (fam15h && enable_c_states) + write_cstates_for_core(index); + + /* Exit processor core scope */ + acpigen_pop_len(); } + + /* Exit processor block scope */ acpigen_pop_len(); } + +void amd_powernow_update_fadt(acpi_fadt_t * fadt) +{ + if (is_fam15h()) { + fadt->p_lvl2_lat = 101; /* NOTE: While the BKDG states this should + * be set to 100, there is no way to meet + * the other FADT requirements. I suspect + * there is an error in the BKDG for ACPI + * 1.x support; disable all FADT-based C + * states > 2... */ + fadt->p_lvl3_lat = 1001; + fadt->flags |= 0x1 << 2; /* FLAGS.PROC_C1 = 1 */ + fadt->flags |= 0x1 << 3; /* FLAGS.P_LVL2_UP = 1 */ + } else { + fadt->cst_cnt = 0; + } + fadt->pstate_cnt = 0; +} |