Author: mjones Date: Mon Feb 28 04:49:28 2011 New Revision: 6408 URL: https://tracker.coreboot.org/trac/coreboot/changeset/6408
Log: Improving BKDG implementation of P-states, CPU and northbridge frequency and voltage handling for Fam 10 in SVI mode.
In fact I changed coreDelay before deleting the code in fidvid that called it. But there're still a couple of calls from src/northbridge/amd/amdmct/wrappers/mcti_d.c Since the comment encouraged fixing something, I parametrized it with the delay time in microseconds and paranoically tried to avoid an overflow at pathological moments.
Signed-off-by: Xavi Drudis Ferran xdrudis@tinet.cat Acked-by: Marc Jones marcj303@gmail.com
Modified: trunk/src/cpu/amd/model_10xxx/fidvid.c trunk/src/northbridge/amd/amdht/AsPsDefs.h trunk/src/northbridge/amd/amdmct/wrappers/mcti_d.c
Modified: trunk/src/cpu/amd/model_10xxx/fidvid.c ============================================================================== --- trunk/src/cpu/amd/model_10xxx/fidvid.c Mon Feb 28 04:35:43 2011 (r6407) +++ trunk/src/cpu/amd/model_10xxx/fidvid.c Mon Feb 28 04:49:28 2011 (r6408) @@ -77,9 +77,9 @@ u32 cpuFid = msr.lo & PS_CPU_FID_MASK; cpuFid = cpuFid + asymetricBoostThisCore; msr.lo &= ~PS_CPU_FID_MASK; - msr.lo |= cpuFid ; + msr.lo |= cpuFid ; wrmsr(PS_REG_BASE , msr); - + } }
@@ -104,7 +104,7 @@ }
static u8 setPStateMaxVal( device_t dev ) { - u8 i,maxpstate=0; + 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) { @@ -141,8 +141,8 @@ 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);
@@ -155,15 +155,15 @@ } }
-static int vidTo100uV(u8 vid) +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)); - } + voltage = (15500 - (125*vid)); + } return voltage; }
@@ -193,12 +193,12 @@
/* This function calculates the VsSlamTime using the range of possible * voltages instead of a hardcoded 200us. - * Note: his function is called only from prep_fid_change, - * and that from init_cpus.c finalize_node_setup() + * Note: his function is called only from prep_fid_change, + * and that from init_cpus.c finalize_node_setup() * (after set AMD MSRs and init ht ) */
- /* BKDG r31116 2010-04-22 2.4.1.7 step b F3xD8[VSSlamTime] */ + /* BKDG r31116 2010-04-22 2.4.1.7 step b F3xD8[VSSlamTime] */ /* Calculate Slam Time * Vslam = (mobileCPU?0.2:0.4)us/mV * (Vp0 - (lowest out of Vpmin or Valt)) mV * In our case, we will scale the values by 100 to avoid @@ -222,7 +222,7 @@ highVoltageVid = (u8) ((msr.lo >> PS_CPU_VID_SHFT) & 0x7F); if (!(msr.hi & 0x80000000)) { printk(BIOS_ERR,"P-state info in MSRC001_0064 is invalid !!!\n"); - highVoltageVid = (u8) ((pci_read_config32(dev, 0x1E0) + highVoltageVid = (u8) ((pci_read_config32(dev, 0x1E0) >> PS_CPU_VID_SHFT) & 0x7F); }
@@ -238,13 +238,13 @@ /* Get PSmax's index */ msr = rdmsr(0xC0010061); bValue = (u8) ((msr.lo >> PS_MAX_VAL_SHFT) & BIT_MASK_3); - + /* Get PSmax's VID */ msr = rdmsr(0xC0010064 + bValue); lowVoltageVid = (u8) ((msr.lo >> PS_CPU_VID_SHFT) & 0x7F); if (!(msr.hi & 0x80000000)) { printk(BIOS_ERR,"P-state info in MSR%8x is invalid !!!\n",0xC0010064 + bValue); - lowVoltageVid = (u8) ((pci_read_config32(dev, 0x1E0+(bValue*4)) + lowVoltageVid = (u8) ((pci_read_config32(dev, 0x1E0+(bValue*4)) >> PS_CPU_VID_SHFT) & 0x7F); }
@@ -266,7 +266,7 @@ if (lowVoltageVid < bValue) lowVoltageVid = bValue;
- u8 mobileFlag = get_platform_type() & AMD_PTYPE_MOB; + u8 mobileFlag = get_platform_type() & AMD_PTYPE_MOB; minimumSlamTime = (mobileFlag?2:4) * (vidTo100uV(highVoltageVid) - vidTo100uV(lowVoltageVid)); /* * 0.01 us */
@@ -819,7 +819,7 @@
}
-static void fixPsNbVidAfterWR(u32 newNbVid, u8 NbVidUpdatedAll,u8 pviMode) +static void fixPsNbVidAfterWR(u32 newNbVid, u8 NbVidUpdatedAll,u8 pviMode) { msr_t msr; u8 i; @@ -837,7 +837,7 @@ for (i = 0; i < 5; i++) { msr = rdmsr(0xC0010064 + i); /* NbDid (bit 22 of P-state Reg) == 0 or NbVidUpdatedAll = 1 */ - if ( (msr.hi & PS_IDD_VALUE_MASK) + if ( (msr.hi & PS_IDD_VALUE_MASK) && (msr.hi & PS_EN_MASK) &&(((msr.lo & PS_NB_DID_MASK) == 0) || NbVidUpdatedAll)) { msr.lo &= PS_NB_VID_M_OFF; @@ -855,7 +855,7 @@ /* For each core in the system, transition all cores to StartupPstate */ msr = rdmsr(0xC0010071); StartupPstate = msr.hi & 0x07; - + /* Set and wait for StartupPstate to set. */ set_pstate(StartupPstate);
Modified: trunk/src/northbridge/amd/amdht/AsPsDefs.h ============================================================================== --- trunk/src/northbridge/amd/amdht/AsPsDefs.h Mon Feb 28 04:35:43 2011 (r6407) +++ trunk/src/northbridge/amd/amdht/AsPsDefs.h Mon Feb 28 04:49:28 2011 (r6408) @@ -291,7 +291,10 @@
#define TSC_MSR 0x10 #define CUR_PSTATE_MSR 0xc0010063 +#define TSC_FREQ_SEL_SHIFT 24
+#define TSC_FREQ_SEL_MASK (1 << TSC_FREQ_SEL_SHIFT) + #define WAIT_PSTATE_TIMEOUT 80000000 /* 0.1 s , unit : 1.25 ns */
#endif
Modified: trunk/src/northbridge/amd/amdmct/wrappers/mcti_d.c ============================================================================== --- trunk/src/northbridge/amd/amdmct/wrappers/mcti_d.c Mon Feb 28 04:35:43 2011 (r6407) +++ trunk/src/northbridge/amd/amdmct/wrappers/mcti_d.c Mon Feb 28 04:49:28 2011 (r6408) @@ -340,6 +340,39 @@ }
#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */ +static void coreDelay(u32 microseconds) +{ + msr_t now; + msr_t end; + u32 cycles; + + /* delay ~40us + This seems like a hack to me... + It would be nice to have a central delay function. */ + + cycles = (microseconds * 100) << 3; /* x8 (number of 1.25ns ticks) */ + + if (!(rdmsr(HWCR).lo & TSC_FREQ_SEL_MASK)) { + msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR); + if (!(rdmsr(0xC0010064+pstate_msr.lo).lo & NB_DID_M_ON)) { + cycles = cycles <<1; // half freq, double cycles + } + } // else should we keep p0 freq at the time of setting TSC_FREQ_SEL_MASK somewhere and check it here ? + + now = rdmsr(TSC_MSR); + // avoid overflow when called near 2^32 ticks ~ 5.3 s boundaries + if (0xffffffff - cycles >= now.lo ) { + end.hi = now.hi; + end.lo = now.lo + cycles; + } else { + end.hi = now.hi +1; // + end.lo = cycles - (1+(0xffffffff - now.lo)); + } + do { + now = rdmsr(TSC_MSR); + } while ((now.hi < end.hi) || ((now.hi == end.hi) && (now.lo < end.lo))); +} + /* Erratum 350 */ static void vErrata350(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) { @@ -385,7 +418,7 @@
print_t("vErrata350: step 3\n"); /* 3. Wait at least 300 nanoseconds. */ - coreDelay(); + coreDelay(1);
print_t("vErrata350: step 4\n"); /* 4. Write 0000_0000h to register F2x[1, 0]9C_xD080F0C. */ @@ -398,7 +431,7 @@
print_t("vErrata350: step 5\n"); /* 5. Wait at least 2 microseconds. */ - coreDelay(); + coreDelay(2);
}