see patch
Improving BKDG implementation of P-states, CPU and northbridge frequency and voltage handling for Fam 10 in SVI mode. Factor out some common expressions. Add an error message when coreboots hangs waiting for a pstate that never comes (it happened to me), and throw some paranoia at it for good mesure. If I understood BKDG fam10 CPUs never need a software initiated vid transition, because the hardware knows what to do when you just request a Pstate change if the cpu is properly configured. In fact unifying a little what PVI and SVI do was better for my board (SVI). So I drop transitionVid, which I didn't understand either (why did it have a case for PVI if it is never called for PVI ? Why did the PVI case distinguigh cpu or nb when PVI is theoretically single voltage plane ? ). Signed-off-by: Xavi Drudis Ferran <[email protected]> --- src/cpu/amd/model_10xxx/fidvid.c 2011-02-13 21:29:50.000000000 +0100 +++ src/cpu/amd/model_10xxx/fidvid.c 2011-02-13 23:08:32.000000000 +0100 @@ -443,6 +443,62 @@ } } +static void waitCurrentPstate(u32 target_pstate){ + msr_t initial_msr = rdmsr(TSC_MSR); + msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR); + msr_t tsc_msr; + u8 timedout ; + + /* paranoia ? I fear when we run fixPsNbVidBeforeWR we can enter a + * P1 that is a copy of P0, therefore has the same NB DID but the + * TSC will count twice per tick, so we have to wait for twice the + * count to achieve the desired timeout. But I'm likely to + * misunderstand this... + */ + u32 corrected_timeout = ( (pstate_msr.lo==1) + && (!(rdmsr(0xC0010065).lo & NB_DID_M_ON)) ) ? + WAIT_PSTATE_TIMEOUT*2 : WAIT_PSTATE_TIMEOUT ; + msr_t timeout; + + timeout.lo = initial_msr.lo + corrected_timeout ; + timeout.hi = initial_msr.hi; + if ( (((u32)0xffffffff) - initial_msr.lo) < corrected_timeout ) { + timeout.hi++; + } + + // assuming TSC ticks at 1.25 ns per tick (800 MHz) + do { + pstate_msr = rdmsr(CUR_PSTATE_MSR); + tsc_msr = rdmsr(TSC_MSR); + timedout = (tsc_msr.hi > timeout.hi) + || ((tsc_msr.hi == timeout.hi) && (tsc_msr.lo > timeout.lo )); + } while ( (pstate_msr.lo != target_pstate) && (! timedout) ) ; + + if (pstate_msr.lo != target_pstate) { + msr_t limit_msr = rdmsr(0xc0010061); + printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state %01x P-state current limit MSRC001_0061=%02x\n", target_pstate, pstate_msr.lo, limit_msr.lo); + + do { // should we just go on instead ? + pstate_msr = rdmsr(CUR_PSTATE_MSR); + } while ( pstate_msr.lo != target_pstate ) ; + } +} + +static void set_pstate(u32 nonBoostedPState) { + msr_t msr; + + // Transition P0 for calling core. + msr = rdmsr(0xC0010062); + + msr.lo = nonBoostedPState; + wrmsr(0xC0010062, msr); + + /* Wait for P0 to set. */ + waitCurrentPstate(nonBoostedPState); +} + + + static void UpdateSinglePlaneNbVid(void) { @@ -468,56 +524,62 @@ } } -static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid) -{ - msr_t msr; - u8 startup_pstate; - - /* This function sets NbVid before the warm reset. - * Get StartupPstate from MSRC001_0071. - * Read Pstate register pionted by [StartupPstate]. - * and copy its content to P0 and P1 registers. - * Copy newNbVid to P0[NbVid]. - * transition to P1 on all cores, - * then transition to P0 on core 0. - * Wait for MSRC001_0063[CurPstate] = 000b on core 0. - */ - - msr = rdmsr(0xc0010071); +static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid, u32 dev, u8 pviMode) + { + msr_t msr; + u8 startup_pstate; + + /* This function sets NbVid before the warm reset. + * Get StartupPstate from MSRC001_0071. + * Read Pstate register pointed by [StartupPstate]. + * and copy its content to P0 and P1 registers. + * Copy newNbVid to P0[NbVid]. + * transition to P1 on all cores, + * then transition to P0 on core 0. + * Wait for MSRC001_0063[CurPstate] = 000b on core 0. + * see BKDG rev 3.48 2.4.2.9.1 BIOS NB COF and VID Configuration + * for SVI and Single-Plane PVI Systems + */ + + msr = rdmsr(0xc0010071); startup_pstate = (msr.hi >> (32 - 32)) & 0x07; - /* Copy startup pstate to P1 and P0 MSRs. Set the maxvid for this node in P0. - * Then transition to P1 for corex and P0 for core0. - * These setting will be cleared by the warm reset + /* Copy startup pstate to P1 and P0 MSRs. Set the maxvid for + * this node in P0. Then transition to P1 for corex and P0 + * for core0. These setting will be cleared by the warm reset */ msr = rdmsr(0xC0010064 + startup_pstate); wrmsr(0xC0010065, msr); wrmsr(0xC0010064, msr); + + /* missing step 2 from BDKG , F3xDC[PstateMaxVal] = + * max(1,F3xDC[PstateMaxVal] ) because it would take + * 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)) ) { + 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"); + }; msr.lo &= ~0xFE000000; // clear nbvid - msr.lo |= newNbVid << 25; + msr.lo |= (newNbVid << 25); wrmsr(0xC0010064, msr); - UpdateSinglePlaneNbVid(); + if (pviMode) { /* single plane*/ + UpdateSinglePlaneNbVid(); + } // Transition to P1 for all APs and P0 for core0. - msr = rdmsr(0xC0010062); - msr.lo = (msr.lo & ~0x07) | 1; - wrmsr(0xC0010062, msr); + set_pstate(1); + + if (coreid == 0) { + set_pstate(0); + } - // Wait for P1 to set. - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 1); + /* missing step 7 (restore PstateMax to 0 if needed) because + * we skipped step 2 + */ - if (coreid == 0) { - msr.lo = msr.lo & ~0x07; - wrmsr(0xC0010062, msr); - // Wait for P0 to set. - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 0); - } } static void coreDelay(void) @@ -540,87 +602,6 @@ } while (lo - saved < cycles); } -static void transitionVid(u32 targetVid, u8 dev, u8 isNb) -{ - u32 currentVid, dtemp; - msr_t msr; - u8 vsTimecode; - u16 timeTable[8] = { 10, 20, 30, 40, 60, 100, 200, 500 }; - int vsTime; - - /* This function steps or slam the Nb VID to the target VID. - * It uses VSRampTime for [SlamVidMode]=0 ([PviMode]=1) - * or VSSlamTime for [SlamVidMode]=1 ([PviMode]=0)to time period. - */ - - /* get the current VID */ - msr = rdmsr(0xC0010071); - if (isNb) - currentVid = (msr.lo >> NB_VID_POS) & BIT_MASK_7; - else - currentVid = (msr.lo >> CPU_VID_POS) & BIT_MASK_7; - - /* Read MSRC001_0070 COFVID Control Register */ - msr = rdmsr(0xC0010070); - - /* check PVI/SPI */ - dtemp = pci_read_config32(dev, 0xA0); - if (dtemp & PVI_MODE) { /* PVI, step VID */ - if (currentVid < targetVid) { - while (currentVid < targetVid) { - currentVid++; - if (isNb) - msr.lo = (msr.lo & NB_VID_MASK_OFF) | (currentVid << NB_VID_POS); - else - msr.lo = (msr.lo & CPU_VID_MASK_OFF) | (currentVid << CPU_VID_POS); - wrmsr(0xC0010070, msr); - - /* read F3xD8[VSRampTime] */ - dtemp = pci_read_config32(dev, 0xD8); - vsTimecode = (u8) ((dtemp >> VS_RAMP_T) & 0x7); - vsTime = (int)timeTable[vsTimecode]; - do { - coreDelay(); - vsTime -= 40; - } while (vsTime > 0); - } - } else if (currentVid > targetVid) { - while (currentVid > targetVid) { - currentVid--; - if (isNb) - msr.lo = (msr.lo & NB_VID_MASK_OFF) | (currentVid << NB_VID_POS); - else - msr.lo = (msr.lo & CPU_VID_MASK_OFF) | (currentVid << CPU_VID_POS); - wrmsr(0xC0010070, msr); - - /* read F3xD8[VSRampTime] */ - dtemp = pci_read_config32(dev, 0xD8); - vsTimecode = (u8) ((dtemp >> VS_RAMP_T) & 0x7); - vsTime = (int)timeTable[vsTimecode]; - do { - coreDelay(); - vsTime -= 40; - } while (vsTime > 0); - } - } - } else { /* SVI, slam VID */ - if (isNb) - msr.lo = (msr.lo & NB_VID_MASK_OFF) | (targetVid << NB_VID_POS); - else - msr.lo = (msr.lo & CPU_VID_MASK_OFF) | (targetVid << CPU_VID_POS); - wrmsr(0xC0010070, msr); - - /* read F3xD8[VSRampTime] */ - dtemp = pci_read_config32(dev, 0xD8); - vsTimecode = (u8) ((dtemp >> VS_RAMP_T) & 0x7); - vsTime = (int)timeTable[vsTimecode]; - do { - coreDelay(); - vsTime -= 40; - } while (vsTime > 0); - } -} - static u32 needs_NB_COF_VID_update(void) { u8 nb_cof_vid_update; @@ -647,31 +628,29 @@ { device_t dev; u32 vid_max; - u32 fid_max=0; + u32 fid_max = 0; u8 nb_cof_vid_update = needs_NB_COF_VID_update(); u8 pvimode; u32 reg1fc; /* Steps 1-6 of BIOS NB COF and VID Configuration - * for SVI and Single-Plane PVI Systems. + * for SVI and Single-Plane PVI Systems. BKDG 2.4.2.9 #31116 rev 3.48 */ dev = NODE_PCI(nodeid, 3); - pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; + pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE; reg1fc = pci_read_config32(dev, 0x1FC); if (nb_cof_vid_update) { - if (pvimode) { - vid_max = (reg1fc >> 7) & 0x7F; - fid_max = (reg1fc >> 2) & 0x1F; + vid_max = (reg1fc & SINGLE_PLANE_NB_VID_MASK ) >> SINGLE_PLANE_NB_VID_SHIFT ; + fid_max = (reg1fc & SINGLE_PLANE_NB_FID_MASK ) >> SINGLE_PLANE_NB_FID_SHIFT ; - /* write newNbVid to P-state Reg's NbVid always if NbVidUpdatedAll=1 */ - fixPsNbVidBeforeWR(vid_max, coreid); - } else { /* SVI */ - vid_max = ((reg1fc >> 7) & 0x7F) - ((reg1fc >> 17) & 0x1F); - fid_max = ((reg1fc >> 2) & 0x1F) + ((reg1fc >> 14) & 0x7); - transitionVid(vid_max, dev, IS_NB); + if (!pvimode) { /* SVI, dual power plane */ + vid_max = vid_max - ((reg1fc & DUAL_PLANE_NB_VID_OFF_MASK ) >> DUAL_PLANE_NB_VID_SHIFT ); + fid_max = fid_max + ((reg1fc & DUAL_PLANE_NB_FID_OFF_MASK ) >> DUAL_PLANE_NB_FID_SHIFT ); } + /* write newNbVid to P-state Reg's NbVid always if NbVidUpdatedAll=1 */ + fixPsNbVidBeforeWR(vid_max, coreid,dev,pvimode); /* fid setup is handled by the BSP at the end. */ @@ -812,21 +791,6 @@ } while (msr.lo != StartupPstate); } -static void set_p0(void) -{ - msr_t msr; - - // Transition P0 for calling core. - msr = rdmsr(0xC0010062); - msr.lo = (msr.lo & ~0x07); - wrmsr(0xC0010062, msr); - - /* Wait for P0 to set. */ - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 0); -} - static void finalPstateChange(void) { /* Enble P0 on all cores for best performance. @@ -834,7 +798,7 @@ * It is safe since they will be in C1 halt * most of the time anyway. */ - set_p0(); + set_pstate(0); } static void init_fidvid_stage2(u32 apicid, u32 nodeid) --- src/northbridge/amd/amdht/AsPsDefs.h 2011-02-13 21:29:50.000000000 +0100 +++ src/northbridge/amd/amdht/AsPsDefs.h 2011-02-13 22:19:01.000000000 +0100 @@ -231,6 +231,16 @@ /* F3x1FC Product Information Register */ #define NB_COF_VID_UPDATE_MASK 1 /* for CPU rev <= C */ +#define SINGLE_PLANE_NB_FID_MASK 0x007c/* for CPU rev <= C */ +#define SINGLE_PLANE_NB_FID_SHIFT 2/* for CPU rev <= C */ +#define SINGLE_PLANE_NB_VID_MASK 0x3f80/* for CPU rev <= C */ +#define SINGLE_PLANE_NB_VID_SHIFT 7/* for CPU rev <= C */ + +#define DUAL_PLANE_NB_FID_OFF_MASK 0x001c000/* for CPU rev <= C */ +#define DUAL_PLANE_NB_FID_SHIFT 14/* for CPU rev <= C */ +#define DUAL_PLANE_NB_VID_OFF_MASK 0x3e0000/* for CPU rev <= C */ +#define DUAL_PLANE_NB_VID_SHIFT 17/* for CPU rev <= C */ + #define NM_PS_REG 5 /* number of P-state MSR registers */ @@ -266,4 +276,9 @@ #define GH_REV_A2 0x4 /* GH Rev A2 logical ID, Upper half */ +#define TSC_MSR 0x10 +#define CUR_PSTATE_MSR 0xc0010063 + +#define WAIT_PSTATE_TIMEOUT 80000000 /* 0.1 s , unit : 1.25 ns */ + #endif
-- coreboot mailing list: [email protected] http://www.coreboot.org/mailman/listinfo/coreboot

