summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/amd/model_10xxx/fidvid.c730
-rw-r--r--src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c32
-rw-r--r--src/northbridge/amd/amdht/AsPsDefs.h3
3 files changed, 582 insertions, 183 deletions
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);
+
+ /* 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);
+ }
- dword = pci_read_config32(dev, 0xdc);
- dword |= 0x5 << 12; // NbsynPtrAdj set to 0x5 per BKDG (needs reset)
+ /* 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 UpdateSinglePlaneNbVid(void)
+{
+ u32 nbVid, cpuVid;
+ u8 i;
+ msr_t msr;
+ /* 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;
+ if( nbVid != cpuVid ) {
+ if(nbVid > cpuVid)
+ nbVid = cpuVid;
-static void init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid)
-{
+ 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);
+ }
+ }
+}
+
+
+static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid)
+{
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);
- /* Only support single plane system at this time. */
- /* Steps 1-6 of BIOS NB COF and VID Configuration
- * for Single-Plane PVI Systems
+ /* 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.
*/
- 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;
-
- 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;
- */
- }
-
- } 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;
-
/* 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. */
+
+ /* 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);
nbvid = (reg1fc >> 7) & 0x7F;
+ NbVidUpdateAll = (reg1fc >> 1) & 1;
- 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 (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);
- // 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);
+ 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: The first half of this function is nearly the same as
+ * init_fidvid_bsp() and the code could be combined.
+ */
- /* FIXME: Only support single plane system at this time. */
/* Steps 1-6 of BIOS NB COF and VID Configuration
- * for Single-Plane PVI Systems
+ * for SVI and Single-Plane PVI Systems.
*/
- 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
-
- 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;
-
-
- /* 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);
-
- 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);
+ dev = NODE_PCI(0, 3);
+ pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1;
+ reg1fc = pci_read_config32(dev, 0x1FC);
- // Wait for P1 to set.
- do {
- msr = rdmsr(0xC0010063);
- } while (msr.lo != 1);
+ 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, 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 = 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 */