Find matching settings for each CPUs FID, VID, and P-state registers and
initialize them. Supports single and split plane systems. Set P0 on all
cores for best performance. All APs will be in hlt(C1).

The platform warm rest logic has been updated to alway reset for HT and
FID/VID setup. It is not optional anymore.

Signed-off-by: Marc Jones (marc.jones@amd.com)


Index: coreboot-v2/src/cpu/amd/model_10xxx/fidvid.c
===================================================================
--- coreboot-v2.orig/src/cpu/amd/model_10xxx/fidvid.c	2008-04-16 10:19:39.000000000 -0600
+++ coreboot-v2/src/cpu/amd/model_10xxx/fidvid.c	2008-04-16 10:36:34.000000000 -0600
@@ -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 @@
 }
 
 
+struct fidvid_st {
+	u32 common_fid;
+};
+
+
 static void enable_fid_change(u8 fid)
 {
 	u32 dword;
@@ -53,7 +59,7 @@
 	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 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;
+
+			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 init_fidvid_ap(u32 bsp_apicid, u32 apicid, u32 nodeid, u32 coreid)
-{
 
+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,7 +377,164 @@
 			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 @@
 	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 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();
 	}
-
-	// 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);
+	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 @@
 	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);
+	dev = NODE_PCI(0, 3);
+	pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1;
+	reg1fc = pci_read_config32(dev, 0x1FC);
 
-	// Transition to P1 and then P0 for core0.
-	msr = rdmsr(0xC0010062);
-	msr.lo = (msr.lo & ~0x07) | 1;
-	wrmsr(0xC0010062, msr);
+	if (nb_cof_vid_update) {
+		if (pvimode) {
+			vid_max = (reg1fc >> 7) & 0x7F;
+			fid_max = (reg1fc >> 2) & 0x1F;
 
-	// Wait for P1 to set.
-	do {
-		msr = rdmsr(0xC0010063);
-	} while (msr.lo != 1);
+			/* 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 @@
 
 	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 @@
 
 	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
Index: coreboot-v2/src/northbridge/amd/amdht/AsPsDefs.h
===================================================================
--- coreboot-v2.orig/src/northbridge/amd/amdht/AsPsDefs.h	2008-04-16 10:19:39.000000000 -0600
+++ coreboot-v2/src/northbridge/amd/amdht/AsPsDefs.h	2008-04-16 10:36:34.000000000 -0600
@@ -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 */
Index: coreboot-v2/src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c
===================================================================
--- coreboot-v2.orig/src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c	2008-04-16 11:24:39.000000000 -0600
+++ coreboot-v2/src/mainboard/amd/serengeti_cheetah_fam10/cache_as_ram_auto.c	2008-04-16 10:39:59.000000000 -0600
@@ -229,7 +229,6 @@
 {
 
 	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 @@
 	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 @@
 	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 @@
 
  #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 @@
 
 	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);
