diff options
Diffstat (limited to 'src/cpu/amd')
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/fidvid.c | 170 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/init_cpus.c | 81 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/powernow_acpi.c | 135 |
3 files changed, 290 insertions, 96 deletions
diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c b/src/cpu/amd/family_10h-family_15h/fidvid.c index 5eb7980514..3af18bd06b 100644 --- a/src/cpu/amd/family_10h-family_15h/fidvid.c +++ b/src/cpu/amd/family_10h-family_15h/fidvid.c @@ -165,87 +165,87 @@ static void applyBoostFIDOffset(device_t dev, uint32_t nodeid) { } static void enableNbPState1( device_t dev ) { - uint64_t cpuRev = mctGetLogicalCPUID(0xFF); - if (cpuRev & AMD_FAM10_C3) { - u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK); - if ( nbPState){ - u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & NB_VID1_MASK) >> NB_VID1_SHIFT; - u32 i; - for (i = nbPState; i < NM_PS_REG; i++) { - msr_t msr = rdmsr(PS_REG_BASE + i); - if (msr.hi & PS_EN_MASK ) { - msr.hi |= NB_DID_M_ON; - msr.lo &= NB_VID_MASK_OFF; - msr.lo |= ( nbVid1 << NB_VID_POS); - wrmsr(PS_REG_BASE + i, msr); - } - } - } - } + uint64_t cpuRev = mctGetLogicalCPUID(0xFF); + if (cpuRev & AMD_FAM10_C3) { + u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK); + if ( nbPState){ + u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & NB_VID1_MASK) >> NB_VID1_SHIFT; + u32 i; + for (i = nbPState; i < NM_PS_REG; i++) { + msr_t msr = rdmsr(PS_REG_BASE + i); + if (msr.hi & PS_EN_MASK ) { + msr.hi |= NB_DID_M_ON; + msr.lo &= NB_VID_MASK_OFF; + msr.lo |= ( nbVid1 << NB_VID_POS); + wrmsr(PS_REG_BASE + i, msr); + } + } + } + } } -static u8 setPStateMaxVal( device_t dev ) { - u8 i,maxpstate=0; - for (i = 0; i < NM_PS_REG; i++) { - msr_t msr = rdmsr(PS_REG_BASE + i); - if (msr.hi & PS_IDD_VALUE_MASK) { - msr.hi |= PS_EN_MASK ; - wrmsr(PS_REG_BASE + i, msr); - } - if (msr.hi & PS_EN_MASK) { - maxpstate = i; - } - } - //FIXME: CPTC2 and HTC_REG should get max per node, not per core ? - u32 reg = pci_read_config32(dev, CPTC2); - reg &= PS_MAX_VAL_MASK; - reg |= (maxpstate << PS_MAX_VAL_POS); - pci_write_config32(dev, CPTC2,reg); - return maxpstate; +static u8 setPStateMaxVal(device_t dev) { + u8 i, maxpstate=0; + for (i = 0; i < NM_PS_REG; i++) { + msr_t msr = rdmsr(PS_REG_BASE + i); + if (msr.hi & PS_IDD_VALUE_MASK) { + msr.hi |= PS_EN_MASK ; + wrmsr(PS_REG_BASE + i, msr); + } + if (msr.hi & PS_EN_MASK) { + maxpstate = i; + } + } + //FIXME: CPTC2 and HTC_REG should get max per node, not per core ? + u32 reg = pci_read_config32(dev, CPTC2); + reg &= PS_MAX_VAL_MASK; + reg |= (maxpstate << PS_MAX_VAL_POS); + pci_write_config32(dev, CPTC2,reg); + return maxpstate; } static void dualPlaneOnly( device_t dev ) { - // BKDG 2.4.2.7 - - uint64_t cpuRev = mctGetLogicalCPUID(0xFF); - if ((mctGetProcessorPackageType() == AMD_PKGTYPE_AM3_2r2) - && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no constant for E - if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK) - && (pci_read_config32(dev, 0xA0) & PVI_MODE) ){ - if (cpuid_edx(0x80000007) & CPB_MASK) { - // revision E only, but E is apparently not supported yet, therefore untested - msr_t minPstate = rdmsr(0xC0010065); - wrmsr(0xC0010065, rdmsr(0xC0010068) ); - wrmsr(0xC0010068,minPstate); - } else { - msr_t msr; - msr.lo=0; msr.hi=0; - wrmsr(0xC0010064, rdmsr(0xC0010068) ); - wrmsr(0xC0010068, msr ); - } - - //FIXME: CPTC2 and HTC_REG should get max per node, not per core ? - u8 maxpstate = setPStateMaxVal(dev); - - u32 reg = pci_read_config32(dev, HTC_REG); - reg &= HTC_PS_LMT_MASK; - reg |= (maxpstate << PS_LIMIT_POS); - pci_write_config32(dev, HTC_REG,reg); - - } - } + // BKDG 2.4.2.7 + + uint64_t cpuRev = mctGetLogicalCPUID(0xFF); + if ((mctGetProcessorPackageType() == AMD_PKGTYPE_AM3_2r2) + && (cpuRev & (AMD_DR_Cx | AMD_DR_Ex))) { + if ((pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK) + && (pci_read_config32(dev, 0xA0) & PVI_MODE)) { + if (cpuid_edx(0x80000007) & CPB_MASK) { + // revision E only, but E is apparently not supported yet, therefore untested + msr_t minPstate = rdmsr(0xC0010065); + wrmsr(0xC0010065, rdmsr(0xC0010068)); + wrmsr(0xC0010068, minPstate); + } else { + msr_t msr; + msr.lo=0; msr.hi=0; + wrmsr(0xC0010064, rdmsr(0xC0010068) ); + wrmsr(0xC0010068, msr); + } + + //FIXME: CPTC2 and HTC_REG should get max per node, not per core ? + u8 maxpstate = setPStateMaxVal(dev); + + u32 reg = pci_read_config32(dev, HTC_REG); + reg &= HTC_PS_LMT_MASK; + reg |= (maxpstate << PS_LIMIT_POS); + pci_write_config32(dev, HTC_REG,reg); + } + } } static int vidTo100uV(u8 vid) -{// returns voltage corresponding to vid in tenths of mV, i.e. hundreds of uV - // BKDG #31116 rev 3.48 2.4.1.6 - int voltage; - if (vid >= 0x7c) { - voltage = 0; - } else { - voltage = (15500 - (125*vid)); - } - return voltage; +{ + // returns voltage corresponding to vid in tenths of mV, i.e. hundreds of uV + // BKDG #31116 rev 3.48 2.4.1.6 + int voltage; + if (vid >= 0x7c) { + voltage = 0; + } else { + voltage = (15500 - (125*vid)); + } + return voltage; } static void setVSRamp(device_t dev) { @@ -344,7 +344,7 @@ static void recalculateVsSlamTimeSettingOnCorePre(device_t dev) } /* Get AltVID */ - dtemp = pci_read_config32(dev, 0xDC); + dtemp = pci_read_config32(dev, 0xdc); bValue = (u8) (dtemp & BIT_MASK_7); /* Use the VID with the lowest voltage (higher VID) */ @@ -508,15 +508,15 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 cpuRev) { values (min latency) */ u32 nbPstate = pci_read_config32(dev,0x1f0) & NB_PSTATE_MASK; u8 nbSynPtrAdj; - if ((cpuRev & (AMD_DR_Bx|AMD_DA_Cx) ) - || ( (cpuRev & AMD_RB_C3) && (nbPstate!=0))) { - nbSynPtrAdj = 5; + if ((cpuRev & (AMD_DR_Bx | AMD_DA_Cx | AMD_FAM15_ALL) ) + || ((cpuRev & AMD_RB_C3) && (nbPstate != 0))) { + nbSynPtrAdj = 5; } else { - nbSynPtrAdj = 6; + nbSynPtrAdj = 6; } - u32 dword = pci_read_config32(dev, 0xDc); - dword &= ~ NB_SYN_PTR_ADJ_MASK; + u32 dword = pci_read_config32(dev, 0xdc); + dword &= ~NB_SYN_PTR_ADJ_MASK; dword |= nbSynPtrAdj << NB_SYN_PTR_ADJ_POS; /* NbsynPtrAdj set to 5 or 6 per BKDG (needs reset) */ pci_write_config32(dev, 0xdc, dword); @@ -548,7 +548,7 @@ static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 procPkg } } else { // rev C or later // same doubt as cache scrubbing: ok to check current state ? - dword = pci_read_config32(dev, 0xDC); + dword = pci_read_config32(dev, 0xdc); u32 cacheFlushOnHalt = dword & (7 << 16); if (!cacheFlushOnHalt) { c1 = 0x80; @@ -619,11 +619,11 @@ static void prep_fid_change(void) printk(BIOS_DEBUG, " F3x80: %08x\n", dword); dword = pci_read_config32(dev, 0x84); printk(BIOS_DEBUG, " F3x84: %08x\n", dword); - dword = pci_read_config32(dev, 0xD4); + dword = pci_read_config32(dev, 0xd4); printk(BIOS_DEBUG, " F3xD4: %08x\n", dword); - dword = pci_read_config32(dev, 0xD8); + dword = pci_read_config32(dev, 0xd8); printk(BIOS_DEBUG, " F3xD8: %08x\n", dword); - dword = pci_read_config32(dev, 0xDC); + dword = pci_read_config32(dev, 0xdc); printk(BIOS_DEBUG, " F3xDC: %08x\n", dword); } } @@ -752,7 +752,7 @@ static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid, u32 dev, u8 pviMode) * synchronization between cores and we don't think * PstatMaxVal is going to be 0 on cold reset anyway ? */ - if ( ! (pci_read_config32(dev, 0xDC) & (~ PS_MAX_VAL_MASK)) ) { + if (!(pci_read_config32(dev, 0xdc) & (~PS_MAX_VAL_MASK))) { printk(BIOS_ERR,"F3xDC[PstateMaxVal] is zero. Northbridge voltage setting will fail. fixPsNbVidBeforeWR in fidvid.c needs fixing. See AMD # 31116 rev 3.48 BKDG 2.4.2.9.1 \n"); }; diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c b/src/cpu/amd/family_10h-family_15h/init_cpus.c index 85eb931ce9..c9dca765c4 100644 --- a/src/cpu/amd/family_10h-family_15h/init_cpus.c +++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c @@ -26,6 +26,14 @@ #include <northbridge/amd/amdfam10/raminit_amdmct.c> #include <reset.h> +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) +#include <southbridge/amd/sb700/sb700.h> +#endif + +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800) +#include <southbridge/amd/sb800/sb800.h> +#endif + #if IS_ENABLED(CONFIG_SET_FIDVID) static void prep_fid_change(void); static void init_fidvid_stage2(u32 apicid, u32 nodeid); @@ -870,6 +878,7 @@ void cpuSetAMDMSR(uint8_t node_id) u8 i; u32 platform; uint64_t revision; + uint8_t enable_c_states; printk(BIOS_DEBUG, "cpuSetAMDMSR "); @@ -932,6 +941,44 @@ void cpuSetAMDMSR(uint8_t node_id) wrmsr(FP_CFG, msr); } +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800) + uint8_t nvram; + + if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) { + /* Set up message triggered C1E */ + msr = rdmsr(0xc0010055); + msr.lo &= ~0xffff; /* IOMsgAddr = ACPI_PM_EVT_BLK */ + msr.lo |= ACPI_PM_EVT_BLK & 0xffff; + msr.lo |= (0x1 << 29); /* BmStsClrOnHltEn = 1 */ + if (revision & AMD_DR_GT_D0) { + msr.lo &= ~(0x1 << 28); /* C1eOnCmpHalt = 0 */ + msr.lo &= ~(0x1 << 27); /* SmiOnCmpHalt = 0 */ + } + wrmsr(0xc0010055, msr); + + msr = rdmsr(0xc0010015); + msr.lo |= (0x1 << 12); /* HltXSpCycEn = 1 */ + wrmsr(0xc0010015, msr); + } + + if (revision & (AMD_DR_Ex | AMD_FAM15_ALL)) { + enable_c_states = 0; + if (IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)) + if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS) + enable_c_states = !!nvram; + + if (enable_c_states) { + /* Set up the C-state base address */ + msr_t c_state_addr_msr; + c_state_addr_msr = rdmsr(0xc0010073); + c_state_addr_msr.lo = ACPI_CPU_P_LVL2; /* CstateAddr = ACPI_CPU_P_LVL2 */ + wrmsr(0xc0010073, c_state_addr_msr); + } + } +#else + enable_c_states = 0; +#endif + printk(BIOS_DEBUG, " done\n"); } @@ -946,6 +993,7 @@ static void cpuSetAMDPCI(u8 node) u32 platform; u32 val; u8 offset; + uint32_t dword; uint64_t revision; printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node); @@ -1004,6 +1052,39 @@ static void cpuSetAMDPCI(u8 node) if (revision & (AMD_DR_B2 | AMD_DR_B3)) dctPhyDiag(); */ + if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) { + /* Set up message triggered C1E */ + dword = pci_read_config32(NODE_PCI(node, 3), 0xd4); + dword &= ~(0x1 << 14); /* CacheFlushImmOnAllHalt = !is_fam15h() */ + dword |= (is_fam15h()?0:1) << 14; + pci_write_config32(NODE_PCI(node, 3), 0xd4, dword); + + dword = pci_read_config32(NODE_PCI(node, 3), 0xdc); + dword |= 0x1 << 26; /* IgnCpuPrbEn = 1 */ + dword &= ~(0x7f << 19); /* CacheFlushOnHaltTmr = 0x28 */ + dword |= 0x28 << 19; + dword |= 0x7 << 16; /* CacheFlushOnHaltCtl = 0x7 */ + pci_write_config32(NODE_PCI(node, 3), 0xdc, dword); + + dword = pci_read_config32(NODE_PCI(node, 3), 0xa0); + dword |= 0x1 << 10; /* IdleExitEn = 1 */ + pci_write_config32(NODE_PCI(node, 3), 0xa0, dword); + + if (revision & AMD_DR_GT_D0) { + dword = pci_read_config32(NODE_PCI(node, 3), 0x188); + dword |= 0x1 << 4; /* EnStpGntOnFlushMaskWakeup = 1 */ + pci_write_config32(NODE_PCI(node, 3), 0x188, dword); + } else { + dword = pci_read_config32(NODE_PCI(node, 4), 0x128); + dword &= ~(0x1 << 31); /* CstateMsgDis = 0 */ + pci_write_config32(NODE_PCI(node, 4), 0x128, dword); + } + + dword = pci_read_config32(NODE_PCI(node, 3), 0xd4); + dword |= 0x1 << 13; /* MTC1eEn = 1 */ + pci_write_config32(NODE_PCI(node, 3), 0xd4, dword); + } + printk(BIOS_DEBUG, " done\n"); } 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; +} |