diff --git a/src/cpu/amd/model_10xxx/fidvid.c b/src/cpu/amd/model_10xxx/fidvid.c index 94ee3bc010..dac53f8806 100644 --- a/src/cpu/amd/model_10xxx/fidvid.c +++ b/src/cpu/amd/model_10xxx/fidvid.c @@ -18,6 +18,7 @@ */ #if FAM10_SET_FIDVID == 1 +#include "../../../northbridge/amd/amdht/AsPsDefs.h" #define FAM10_SET_FIDVID_DEBUG 1 @@ -46,6 +47,11 @@ static inline void print_debug_fv_64(const char *str, u32 val, u32 val2) } +struct fidvid_st { + u32 common_fid; +}; + + static void enable_fid_change(u8 fid) { u32 dword; @@ -53,7 +59,7 @@ static void enable_fid_change(u8 fid) device_t dev; int i; - nodes = ((pci_read_config32(PCI_DEV(CBB, CDB, 0), 0x60) >> 4) & 7) + 1; + nodes = get_nodes(); for(i = 0; i < nodes; i++) { dev = NODE_PCI(i,3); @@ -66,124 +72,293 @@ static void enable_fid_change(u8 fid) } } + +static void recalculateVsSlamTimeSettingOnCorePre(device_t dev) +{ + u8 pviModeFlag; + u8 highVoltageVid, lowVoltageVid, bValue; + u16 minimumSlamTime; + u16 vSlamTimes[7]={1000,2000,3000,4000,6000,10000,20000}; /* Reg settings scaled by 100 */ + u32 dtemp; + msr_t msr; + + /* This function calculates the VsSlamTime using the range of possible + * voltages instead of a hardcoded 200us. + * Note:This function is called from setFidVidRegs and setUserPs after + * programming a custom Pstate. + */ + + /* Calculate Slam Time + * Vslam = 0.4us/mV * Vp0 - (lowest out of Vpmin or Valt) + * In our case, we will scale the values by 100 to avoid + * decimals. + */ + + + + /* Determine if this is a PVI or SVI system */ + dtemp = pci_read_config32(dev, 0xA0); + + if( dtemp & PVI_MODE ) + pviModeFlag = 1; + else + pviModeFlag = 0; + + /* Get P0's voltage */ + msr = rdmsr(0xC0010064); + highVoltageVid = (u8) ((msr.lo >> PS_CPU_VID_SHFT) & 0x7F); + + /* If SVI, we only care about CPU VID. + * If PVI, determine the higher voltage b/t NB and CPU + */ + if (pviModeFlag) { + bValue = (u8) ((msr.lo >> PS_NB_VID_SHFT) & 0x7F); + if( highVoltageVid > bValue ) + highVoltageVid = bValue; + } + + /* Get Pmin's index */ + msr = rdmsr(0xC0010061); + bValue = (u8) ((msr.lo >> PS_CUR_LIM_SHFT) & BIT_MASK_3); + + /* Get Pmin's VID */ + msr = rdmsr(0xC0010064 + bValue); + lowVoltageVid = (u8) ((msr.lo >> PS_CPU_VID_SHFT) & 0x7F); + + /* If SVI, we only care about CPU VID. + * If PVI, determine the higher voltage b/t NB and CPU + */ + if (pviModeFlag) { + bValue = (u8) ((msr.lo >> PS_NB_VID_SHFT) & 0x7F); + if( lowVoltageVid > bValue ) + lowVoltageVid = bValue; + } + + /* Get AltVID */ + dtemp = pci_read_config32(dev, 0xDC); + bValue = (u8) (dtemp & BIT_MASK_7); + + /* Use the VID with the lowest voltage (higher VID) */ + if( lowVoltageVid < bValue ) + lowVoltageVid = bValue; + + /* If Vids are 7Dh - 7Fh, force 7Ch to keep calculations linear */ + if (lowVoltageVid > 0x7C) { + lowVoltageVid = 0x7C; + if(highVoltageVid > 0x7C) + highVoltageVid = 0x7C; + } + + bValue = (u8) (lowVoltageVid - highVoltageVid); + + /* Each Vid increment is 12.5 mV. The minimum slam time is: + * vidCodeDelta * 12.5mV * 0.4us/mV + * Scale by 100 to avoid decimals. + */ + minimumSlamTime = bValue * (125 * 4); + + /* Now round up to nearest register setting. + * Note that if we don't find a value, we + * will fall through to a value of 7 + */ + for(bValue=0; bValue < 7; bValue++) { + if(minimumSlamTime <= vSlamTimes[bValue]) + break; + } + + /* Apply the value */ + dtemp = pci_read_config32(dev, 0xD8); + dtemp &= VSSLAM_MASK; + dtemp |= bValue; + pci_write_config32(dev, 0xd8, dtemp); +} + + static void prep_fid_change(void) { - u32 dword; + u32 dword, dtemp; u32 nodes; device_t dev; int i; /* This needs to be run before any Pstate changes are requested */ - nodes = ((pci_read_config32(PCI_DEV(CBB, CDB, 0), 0x60) >> 4) & 7) + 1; + nodes = get_nodes(); for(i = 0; i < nodes; i++) { - printk_debug("Node:%02x \n", i); + printk_debug("Prep FID/VID Node:%02x \n", i); dev = NODE_PCI(i,3); - dword = pci_read_config32(dev, 0xa0); - dword &= ~(1<<29); - dword |= ((~dword >> 8) & 1) << 29; // SlamVidMode is the inverse to the PviMode - dword |= PLLLOCK_DFT_L; /* Force per BKDG */ - pci_write_config32(dev, 0xa0, dword); - printk_debug(" F3xA0: %08x \n", dword); - dword = pci_read_config32(dev, 0xd8); - dword &= ~0x77; - dword |= (1<<4) | 6; // VSRampTime, and VSSlamTime - dword |= 3 << 24; // ReConDel set to 3 per BKDG + dword &= VSRAMP_MASK; + dword |= VSRAMP_VALUE; pci_write_config32(dev, 0xd8, dword); - printk_debug(" F3xD8: %08x \n", dword); - dword = pci_read_config32(dev, 0xd4); - dword &= 0x1F; - dword |= 0xC331AF00; // per BKDG - pci_write_config32(dev, 0xd4, dword); - printk_debug(" F3xD4: %08x \n", dword); + /* Figure out the value for VsSlamTime and program it */ + recalculateVsSlamTimeSettingOnCorePre(dev); - dword = pci_read_config32(dev, 0xdc); - dword |= 0x5 << 12; // NbsynPtrAdj set to 0x5 per BKDG (needs reset) + /* Program fields in Clock Power/Control register0 (F3xD4) */ + /* set F3xD4 Clock Power/Timing Control 0 Register + * NbClkDidApplyAll=1b + * NbClkDid=100b + * PowerStepUp= "platform dependent" + * PowerStepDown= "platform dependent" + * LinkPllLink=01b + * ClkRampHystSel=HW default + */ + /* check platform type */ + if (!(get_platform_type() & AMD_PTYPE_SVR)) { + /* For non-server platform + * PowerStepUp=01000b - 50nS + * PowerStepDown=01000b - 50ns + */ + dword = pci_read_config32(dev, 0xd4); + dword &= CPTC0_MASK; + dword |= NB_CLKDID_ALL | NB_CLKDID | PW_STP_UP50 | PW_STP_DN50 | + LNK_PLL_LOCK; /* per BKDG */ + pci_write_config32(dev, 0xd4, dword); + } else { + dword = pci_read_config32(dev, 0xd4); + dword &= CPTC0_MASK; + /* get number of cores for PowerStepUp & PowerStepDown in server + 1 core - 400nS - 0000b + 2 cores - 200nS - 0010b + 3 cores - 133nS -> 100nS - 0011b + 4 cores - 100nS - 0011b + */ + switch(get_core_num_in_bsp(i)) + { + case 0: + dword |= PW_STP_UP400 | PW_STP_DN400; + break; + case 1: + case 2: + dword |= PW_STP_UP200 | PW_STP_DN200; + break; + case 3: + dword |= PW_STP_UP100 | PW_STP_DN100; + break; + default: + dword |= PW_STP_UP100 | PW_STP_DN100; + break; + } + dword |= NB_CLKDID_ALL | NB_CLKDID | LNK_PLL_LOCK; + pci_write_config32(dev, 0xd4, dword); + } + + /* check PVI/SVI */ + dword = pci_read_config32(dev, 0xA0); + if(dword & PVI_MODE) { /* PVI */ + /* set slamVidMode to 0 for PVI */ + dword &= VID_SLAM_OFF | PLLLOCK_OFF; + dword |= PLLLOCK_DFT_L; + pci_write_config32(dev, 0xA0, dword); + } else { /* SVI */ + /* set slamVidMode to 1 for SVI */ + dword &= PLLLOCK_OFF; + dword |= PLLLOCK_DFT_L | VID_SLAM_ON; + pci_write_config32(dev, 0xA0, dword); + + dtemp = dword; + + /* Program F3xD8[PwrPlanes] according F3xA0[DulaVdd] */ + dword = pci_read_config32(dev, 0xD8); + + if( dtemp & DUAL_VDD_BIT) + dword |= PWR_PLN_ON; + else + dword &= PWR_PLN_OFF; + pci_write_config32(dev, 0xD8, dword); + } + + /* Note the following settings are additional from the ported + * function setFidVidRegs() + */ + dword = pci_read_config32(dev, 0xDc); + dword |= 0x5 << 12; /* NbsynPtrAdj set to 0x5 per BKDG (needs reset) */ pci_write_config32(dev, 0xdc, dword); - printk_debug(" F3xDC: %08x \n", dword); - // Rev B settings - FIXME: support other revs. + /* Rev B settings - FIXME: support other revs. */ dword = 0xA0E641E6; pci_write_config32(dev, 0x84, dword); - printk_debug(" F3x84: %08x \n", dword); dword = 0xE600A681; pci_write_config32(dev, 0x80, dword); + + dword = pci_read_config32(dev, 0x80); printk_debug(" F3x80: %08x \n", dword); + dword = pci_read_config32(dev, 0x84); + printk_debug(" F3x84: %08x \n", dword); + dword = pci_read_config32(dev, 0xD4); + printk_debug(" F3xD4: %08x \n", dword); + dword = pci_read_config32(dev, 0xD8); + printk_debug(" F3xD8: %08x \n", dword); + dword = pci_read_config32(dev, 0xDC); + printk_debug(" F3xDC: %08x \n", dword); + } } -#include "fidvid_common.c" - - - -static void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid) +static void UpdateSinglePlaneNbVid(void) { - + u32 nbVid, cpuVid; + u8 i; msr_t msr; - device_t dev; - u8 vid_max; - u8 fid_max; - u8 startup_pstate; - u8 nb_cof_vid_update; - u8 pvimode; - u32 reg1fc; - u32 dword; - u32 send; - printk_debug("FIDVID on AP: %02x\n", apicid); + /* copy higher voltage (lower VID) of NBVID & CPUVID to both */ + for (i = 0; i < 5; i++) { + msr = rdmsr(PS_REG_BASE + i); + nbVid = (msr.lo & PS_CPU_VID_M_ON) >> PS_CPU_VID_SHFT; + cpuVid = (msr.lo & PS_NB_VID_M_ON) >> PS_NB_VID_SHFT; - /* Only support single plane system at this time. */ - /* Steps 1-6 of BIOS NB COF and VID Configuration - * for Single-Plane PVI Systems - */ - dev = NODE_PCI(nodeid,3); - reg1fc = pci_read_config32(dev, 0x1FC); - nb_cof_vid_update = reg1fc & 1; - if (nb_cof_vid_update) { - /* Get fused settings */ - dword = pci_read_config32(dev, 0xa0); - pvimode = (dword >> 8) & 1; + if( nbVid != cpuVid ) { + if(nbVid > cpuVid) + nbVid = cpuVid; - vid_max = (reg1fc >> 7) & 0x7F; // per node - fid_max = (reg1fc >> 2) & 0x1F; // per system - - if (pvimode) { - /* FIXME: support daul plane mode */ - die("PVImode not supported\n"); - /* fidmax = vidmax - (reg1fc >> 17) & 0x1F; - fidmax = fidmax + (reg1fc >> 14) & 0x03; - */ + msr.lo = msr.lo & PS_BOTH_VID_OFF; + msr.lo = msr.lo | (u32)((nbVid) << PS_NB_VID_SHFT); + msr.lo = msr.lo | (u32)((nbVid) << PS_CPU_VID_SHFT); + wrmsr(PS_REG_BASE + i, msr); } - - } else { - /* Use current values */ - msr = rdmsr(0xc0010071); - fid_max = ((msr.hi >> (59-32)) & 0x1f); //max nb fid - vid_max = ((msr.hi >> (35-32)) & 0x7f); //max vid } +} + + + +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. + */ - /* Note this is the single plane setup. Need to add dual plane path */ 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. */ + * 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); msr.lo &= ~0xFE000000; // clear nbvid - msr.lo |= vid_max << 25; + msr.lo |= newNbVid << 25; wrmsr(0xC0010064, msr); + UpdateSinglePlaneNbVid(); + // Transition to P1 for all APs and P0 for core0. msr = rdmsr(0xC0010062); msr.lo = (msr.lo & ~0x07) | 1; @@ -202,8 +377,165 @@ static void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid) msr = rdmsr(0xC0010063); } while (msr.lo != 0); } +} +static void coreDelay (void) +{ + u32 saved; + u32 hi, lo, msr; + u32 cycles; + + /* delay ~40us + This seems like a hack to me... + It would be nice to have a central delay function. */ + + cycles = 8000 << 3; /* x8 (number of 1.25ns ticks) */ + + msr = 0x10; /* TSC */ + _RDMSR(msr, &lo, &hi); + saved = lo; + do { + _RDMSR(msr, &lo, &hi); + } 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 void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid) +{ + device_t dev; + u32 vid_max; + u32 fid_max; + u8 nb_cof_vid_update; + u8 pvimode; + u32 reg1fc; + u32 send; + u8 nodes; + u8 i; + + printk_debug("FIDVID on AP: %02x\n", apicid); + + /* Steps 1-6 of BIOS NB COF and VID Configuration + * for SVI and Single-Plane PVI Systems. + */ + + /* If any node has nb_cof_vid_update set all nodes need an update. */ + nodes = get_nodes(); + nb_cof_vid_update = 0; + for (i = 0; i < nodes; i++) { + if (pci_read_config32(NODE_PCI(i,3), 0x1FC) & 1) { + nb_cof_vid_update = 1; + break; + } + } + + dev = NODE_PCI(nodeid,3); + pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; + reg1fc = pci_read_config32(dev, 0x1FC); + + if (nb_cof_vid_update) { + if (pvimode) { + vid_max = (reg1fc >> 7) & 0x7F; + fid_max = (reg1fc >> 2) & 0x1F; + + /* 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); + } + + /* fid setup is handled by the BSP at the end. */ + + } else { /* ! nb_cof_vid_update */ + /* Use max values */ + if (pvimode) + UpdateSinglePlaneNbVid(); + } + send = (nb_cof_vid_update << 16) | (fid_max << 8); send |= (apicid << 24); // ap apicid @@ -232,9 +564,6 @@ static u32 calc_common_fid(u32 fid_packed, u32 fid_packed_new) return fid_packed; } -struct fidvid_st { - u32 common_fid; -}; static void init_fidvid_bsp_stage1(u32 ap_apicid, void *gp ) { @@ -269,44 +598,147 @@ static void init_fidvid_bsp_stage1(u32 ap_apicid, void *gp ) } +static void updateSviPsNbVidAfterWR(u32 newNbVid) +{ + msr_t msr; + u8 i; + + /* This function copies newNbVid to NbVid bits in P-state Registers[4:0] + * for SVI mode. + */ + + for( i = 0; i < 5; i++) { + msr = rdmsr(0xC0010064 + i); + if ((msr.hi >> 31) & 1) { /* PstateEn? */ + msr.lo &= ~(0x7F << 25); + msr.lo |= (newNbVid & 0x7F) << 25; + wrmsr(0xC0010064 + i, msr); + } + } +} + + +static void fixPsNbVidAfterWR(u32 newNbVid, u8 NbVidUpdatedAll) +{ + msr_t msr; + u8 i; + u8 StartupPstate; + + /* This function copies newNbVid to NbVid bits in P-state + * Registers[4:0] if its NbDid bit=0 and PstateEn bit =1 in case of + * NbVidUpdatedAll =0 or copies copies newNbVid to NbVid bits in + * P-state Registers[4:0] if its and PstateEn bit =1 in case of + * NbVidUpdatedAll=1. Then transition to StartPstate. + */ + + /* write newNbVid to P-state Reg's NbVid if its NbDid=0 */ + for( i = 0; i < 5; i++) { + msr = rdmsr(0xC0010064 + i); + /* NbDid (bit 22 of P-state Reg) == 0 or NbVidUpdatedAll = 1 */ + if ((((msr.lo >> 22) & 1) == 0) || NbVidUpdatedAll) { + msr.lo &= ~(0x7F << 25); + msr.lo |= (newNbVid & 0x7F) << 25; + wrmsr (0xC0010064 + i, msr); + } + } + + UpdateSinglePlaneNbVid(); + + /* For each core in the system, transition all cores to StartupPstate */ + msr = rdmsr(0xC0010071); + StartupPstate = msr.hi & 0x07; + msr = rdmsr(0xC0010062); + msr.lo = StartupPstate; + wrmsr(0xC0010062, msr); + + /* Wait for StartupPstate to set.*/ + do { + msr = rdmsr(0xC0010063); + } 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. + * Linux can slow them down later if need be. + * It is safe since they will be in C1 halt + * most of the time anyway. + */ + set_p0(); +} + + static void init_fidvid_stage2(u32 apicid, u32 nodeid) { msr_t msr; device_t dev; u32 reg1fc; - u8 StartupPstate; - u8 nbvid; - int i; + u32 dtemp; + u32 nbvid; + u8 nb_cof_vid_update; + u8 nodes; + u8 NbVidUpdateAll; + u8 i; + u8 pvimode; /* After warm reset finish the fid/vid setup for all cores. */ - dev = NODE_PCI(nodeid,3); - reg1fc = pci_read_config32(dev, 0x1FC); - nbvid = (reg1fc >> 7) & 0x7F; - if (reg1fc & 0x02) { // NbVidUpdateAll ? - for( i = 0; i < 5; i++) { - msr = rdmsr(0xC0010064 + i); - if ((msr.hi >> 31) & 1) { // PstateEn? - msr.lo &= ~(0x7F << 25); - msr.lo |= (nbvid & 0x7F) << 25; - } - } - } else { - for( i = 0; i < 5; i++) { - msr = rdmsr(0xC0010064 + i); - if (((msr.hi >> 31) & 1) && (((msr.lo >> 22) & 1) == 0)) { // PstateEn and PDid == 0? - msr.lo &= ~(0x7F << 25); - msr.lo |= (nbvid & 0x7F) << 25; - } + /* If any node has nb_cof_vid_update set all nodes need an update. */ + nodes = get_nodes(); + nb_cof_vid_update = 0; + for (i = 0; i < nodes; i++) { + if (pci_read_config32(NODE_PCI(i,3), 0x1FC) & 1) { + nb_cof_vid_update = 1; + break; } } - // For each processor in the system, transition all cores to StartupPstate - msr = rdmsr(0xC0010071); - StartupPstate = msr.hi >> (32-32) & 0x03; - msr = rdmsr(0xC0010062); - msr.lo = StartupPstate; - wrmsr(0xC0010062, msr); + dev = NODE_PCI(nodeid,3); + pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; + reg1fc = pci_read_config32(dev, 0x1FC); + nbvid = (reg1fc >> 7) & 0x7F; + NbVidUpdateAll = (reg1fc >> 1) & 1; + + if (nb_cof_vid_update) { + if (pvimode) { + nbvid = (reg1fc >> 7) & 0x7F; + /* write newNbVid to P-state Reg's NbVid if its NbDid=0 */ + fixPsNbVidAfterWR(nbvid, NbVidUpdateAll); + } else { /* SVI */ + nbvid = ((reg1fc >> 7) & 0x7F) - ((reg1fc >> 17) & 0x1F); + updateSviPsNbVidAfterWR(nbvid); + } + } else { /* !nb_cof_vid_update */ + if (pvimode) + UpdateSinglePlaneNbVid(); + } + dtemp = pci_read_config32(dev, 0xA0); + dtemp &= PLLLOCK_OFF; + dtemp |= PLLLOCK_DFT_L; + pci_write_config32(dev, 0xA0, dtemp); + + finalPstateChange(); + + /* Set TSC to tick at the P0 ndfid rate */ + msr = rdmsr(HWCR); + msr.lo |= 1 << 24; + wrmsr(HWCR, msr); } @@ -334,80 +766,55 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes) u32 i; #endif struct fidvid_st fv; - msr_t msr; device_t dev; - u8 vid_max; - u8 fid_max; - u8 startup_pstate; + u32 vid_max; + u32 fid_max; u8 nb_cof_vid_update; u32 reg1fc; - u32 dword; u8 pvimode; printk_debug("FIDVID on BSP, APIC_id: %02x\n", bsp_apicid); - - /* FIXME: Only support single plane system at this time. */ - /* Steps 1-6 of BIOS NB COF and VID Configuration - * for Single-Plane PVI Systems + /* FIXME: The first half of this function is nearly the same as + * init_fidvid_bsp() and the code could be combined. */ - dev = NODE_PCI(0,3); // nodeid for the BSP is 0 - reg1fc = pci_read_config32(dev, 0x1FC); - nb_cof_vid_update = reg1fc & 1; - if (nb_cof_vid_update) { - /* Get fused settings */ - dword = pci_read_config32(dev, 0xa0); - pvimode = (dword >> 8) & 1; - vid_max = (reg1fc >> 7) & 0x7F; // per node - fid_max = (reg1fc >> 2) & 0x1F; // per system + /* Steps 1-6 of BIOS NB COF and VID Configuration + * for SVI and Single-Plane PVI Systems. + */ - if (pvimode) { - /* FIXME: support daul plane mode */ - die("PVImode not supported\n"); - /* fidmax = vidmax - (reg1fc >> 17) & 0x1F; - fidmax = fidmax + (reg1fc >> 14) & 0x03; - */ + /* If any node has nb_cof_vid_update set all nodes need an update. */ + nb_cof_vid_update = 0; + for (i = 0; i < nodes; i++) { + if (pci_read_config32(NODE_PCI(i,3), 0x1FC) & 1) { + nb_cof_vid_update = 1; + break; } - - } else { - /* Use current values */ - msr = rdmsr(0xc0010071); - fid_max = ((msr.hi >> (59-32)) & 0x1f); //max nb fid - vid_max = ((msr.hi >> (35-32)) & 0x7f); //max vid } - /* Note this is the single plane setup. Need to add dual plane path */ - msr = rdmsr(0xc0010071); - startup_pstate = (msr.hi >> (32-32)) & 0x07; + dev = NODE_PCI(0, 3); + pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; + reg1fc = pci_read_config32(dev, 0x1FC); + if (nb_cof_vid_update) { + if (pvimode) { + vid_max = (reg1fc >> 7) & 0x7F; + fid_max = (reg1fc >> 2) & 0x1F; - /* 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. */ - msr = rdmsr(0xC0010064 + startup_pstate); - wrmsr(0xC0010065, msr); - wrmsr(0xC0010064, msr); + /* write newNbVid to P-state Reg's NbVid always if NbVidUpdatedAll=1 */ + fixPsNbVidBeforeWR(vid_max, 0); + } else { /* SVI */ + vid_max = ((reg1fc >> 7) & 0x7F) - ((reg1fc >> 17) & 0x1F); + fid_max = ((reg1fc >> 2) & 0x1F) + ((reg1fc >> 14) & 0x7); + transitionVid(vid_max, dev, IS_NB); + } - msr.lo &= ~0xFE000000; // clear nbvid - msr.lo |= vid_max << 25; - wrmsr(0xC0010064, msr); - - // Transition to P1 and then P0 for core0. - msr = rdmsr(0xC0010062); - msr.lo = (msr.lo & ~0x07) | 1; - wrmsr(0xC0010062, msr); - - // Wait for P1 to set. - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 1); - - msr.lo = msr.lo & ~0x07; - wrmsr(0xC0010062, msr); - // Wait for P0 to set. - do { - msr = rdmsr(0xC0010063); - } while (msr.lo != 0); + /* fid setup is handled by the BSP at the end. */ + } else { /* ! nb_cof_vid_update */ + /* Use max values */ + if (pvimode) + UpdateSinglePlaneNbVid(); + } fv.common_fid = (nb_cof_vid_update << 16) | (fid_max << 8) ; print_debug_fv("BSP fid = ", fv.common_fid); @@ -430,7 +837,7 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes) print_debug_fv("common_fid = ", fv.common_fid); - if (fv.common_fid & ~(0xFF << 16)) { // check nb_cof_vid_update + if (fv.common_fid & (1 << 16)) { /* check nb_cof_vid_update */ // Enable the common fid and other settings. enable_fid_change((fv.common_fid >> 8) & 0x1F); @@ -441,15 +848,4 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes) return 0; // No FID/VID changes. Don't reset } -static void set_p0(void) -{ - msr_t msr; - - // Transition P0 for calling core. - msr = rdmsr(0xC0010062); - msr.lo = (msr.lo & ~0x07); - wrmsr(0xC0010062, msr); - - // Don't bother to wait around for the P state to change. -} #endif diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c b/src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c index 5ee60cadcf..5c81720ac3 100644 --- a/src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c +++ b/src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c @@ -229,7 +229,6 @@ void real_main(unsigned long bist, unsigned long cpu_init_detectedx) { struct sys_info *sysinfo = (struct sys_info *)(DCACHE_RAM_BASE + DCACHE_RAM_SIZE - DCACHE_RAM_GLOBAL_VAR_SIZE); - int needs_reset = 0; u32 bsp_apicid = 0; u32 val; msr_t msr; @@ -237,7 +236,7 @@ void real_main(unsigned long bist, unsigned long cpu_init_detectedx) post_code(0x30); if (bist == 0) { - bsp_apicid = init_cpus(cpu_init_detectedx, sysinfo); //mmconf is inited in init_cpus + bsp_apicid = init_cpus(cpu_init_detectedx, sysinfo); /* mmconf is inited in init_cpus */ /* All cores run this but the BSP(node0,core0) is the only core that returns. */ } @@ -288,7 +287,7 @@ void real_main(unsigned long bist, unsigned long cpu_init_detectedx) wait_all_core0_started(); #if CONFIG_LOGICAL_CPUS==1 - // Core0 on each node is configured. Now setup any additional cores. + /* Core0 on each node is configured. Now setup any additional cores. */ printk_debug("start_other_cores()\n"); start_other_cores(); post_code(0x37); @@ -299,7 +298,7 @@ void real_main(unsigned long bist, unsigned long cpu_init_detectedx) #if FAM10_SET_FIDVID == 1 msr = rdmsr(0xc0010071); - printk_debug("Begin MSR 0xc0010071 0x%08x 0x%08x \n", msr.hi, msr.lo); + printk_debug("\nBegin FIDVID MSR 0xc0010071 0x%08x 0x%08x \n", msr.hi, msr.lo); /* FIXME: The sb fid change may survive the warm reset and only need to be done once.*/ @@ -307,36 +306,37 @@ void real_main(unsigned long bist, unsigned long cpu_init_detectedx) post_code(0x39); - if (warm_reset_detect(0)) { // BSP is node 0 - init_fidvid_stage2(bsp_apicid, 0); // BSP is node 0 + if (!warm_reset_detect(0)) { // BSP is node 0 + init_fidvid_bsp(bsp_apicid, sysinfo->nodes); } else { - needs_reset |= (init_fidvid_bsp(bsp_apicid, sysinfo->nodes) << 31); + init_fidvid_stage2(bsp_apicid, 0); // BSP is node 0 } post_code(0x3A); - set_p0(); // Speed up the BSP! - - // show final fid and vid + /* show final fid and vid */ msr=rdmsr(0xc0010071); - printk_debug("End MSR 0xc0010071 0x%08x 0x%08x \n", msr.hi, msr.lo); + printk_debug("End FIDVIDMSR 0xc0010071 0x%08x 0x%08x \n", msr.hi, msr.lo); #endif - // Reset for HT and FIDVID changes? - if (needs_reset) { - print_info("\tht reset -\n"); + + /* Reset for HT, FIDVID, PLL and errata changes to take affect. */ + if (!warm_reset_detect(0)) { + print_info("...WARM RESET...\n\n\n"); soft_reset_x(sysinfo->sbbusn, sysinfo->sbdn); die("After soft_reset_x - shouldn't see this message!!!\n"); } post_code(0x3B); - //enable cf9 for hard reset + + /* FIXME: Move this to chipset init. + enable cf9 for hard reset */ print_debug("enable_cf9_x()\n"); enable_cf9_x(sysinfo->sbbusn, sysinfo->sbdn); post_code(0x3C); - //It's the time to set ctrl in sysinfo now; + /* It's the time to set ctrl in sysinfo now; */ printk_debug("fill_mem_ctrl()\n"); fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr); post_code(0x3D); diff --git a/src/northbridge/amd/amdht/AsPsDefs.h b/src/northbridge/amd/amdht/AsPsDefs.h index 62b7edba6d..dfc6821ed9 100644 --- a/src/northbridge/amd/amdht/AsPsDefs.h +++ b/src/northbridge/amd/amdht/AsPsDefs.h @@ -157,7 +157,10 @@ #define CPTC1 0xd8 /* Clock Power/Timing Control1 Register*/ #define VSRAMP_SLAM_MASK 0xffffff88 /* MaskOff [VSRampTime]&[VSSlamTime] */ #define VSRAMP_SLAM_VALUE 0x16 /* [VSRampTime]=001b&[VSSlamTime]=110b */ +#define VSRAMP_MASK 0xffffff8f /* MaskOff [VSRampTime] */ +#define VSRAMP_VALUE 0x10 /* [VSRampTime]=001b */ #define VS_RAMP_T 4 /* VSRampTime bit position */ +#define VSSLAM_MASK 0xfffffff8 /* MaskOff [VSSlamTime] */ #define PWR_PLN_SHIFT 28 /* PwrPlanes bit shift */ #define PWR_PLN_ON 0x10000000 /* PwrPlanes bit ON */ #define PWR_PLN_OFF 0x0efffffff /* PwrPlanes bit OFF */