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);
-
+
}
}
}
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) {
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);
}
}
-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;
}
/* 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
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);
}
/* 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);
}
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 */
}
-static void fixPsNbVidAfterWR(u32 newNbVid, u8 NbVidUpdatedAll,u8 pviMode)
+static void fixPsNbVidAfterWR(u32 newNbVid, u8 NbVidUpdatedAll,u8 pviMode)
{
msr_t msr;
u8 i;
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;
/* 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);
}
#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)
{
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. */
print_t("vErrata350: step 5\n");
/* 5. Wait at least 2 microseconds. */
- coreDelay();
+ coreDelay(2);
}