From 8f0d565329ddc702412d6941a5a0fea7c81e73e8 Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Mon, 8 Jun 2015 19:35:06 -0500
Subject: [PATCH 047/143] cpu/amd: Add CC6 support

Change-Id: I44ce157cda97fb85f3e8f3d7262d4712b5410670
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/arch/x86/acpigen.c                            |   26 +++-
 src/arch/x86/include/arch/acpigen.h               |    3 +
 src/cpu/amd/family_10h-family_15h/fidvid.c        |  170 ++++++++++-----------
 src/cpu/amd/family_10h-family_15h/init_cpus.c     |   81 ++++++++++
 src/cpu/amd/family_10h-family_15h/powernow_acpi.c |  135 ++++++++++++++--
 src/include/cpu/amd/powernow.h                    |    2 +
 src/mainboard/asus/kgpe-d16/cmos.default          |    1 +
 src/mainboard/asus/kgpe-d16/cmos.layout           |    5 +-
 src/northbridge/amd/amdfam10/link_control.c       |   81 +++++++++-
 src/northbridge/amd/amdfam10/northbridge.c        |   58 ++++---
 src/northbridge/amd/amdht/AsPsDefs.h              |    3 +-
 src/northbridge/amd/amdmct/amddefs.h              |   66 ++++----
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.c       |   57 ++++---
 src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c    |    8 +
 src/southbridge/amd/sb700/early_setup.c           |   20 ++-
 src/southbridge/amd/sb700/fadt.c                  |    5 +
 src/southbridge/amd/sb700/sb700.h                 |    7 +-
 src/southbridge/amd/sb700/sm.c                    |    5 +-
 src/southbridge/amd/sb800/fadt.c                  |    4 +
 src/southbridge/amd/sb800/sb800.h                 |    8 +-
 20 files changed, 544 insertions(+), 201 deletions(-)

diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c
index 3aa823c..4136e65 100644
--- a/src/arch/x86/acpigen.c
+++ b/src/arch/x86/acpigen.c
@@ -1,6 +1,7 @@
 /*
  * This file is part of the coreboot project.
  *
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,11 +22,11 @@
 #define ACPIGEN_LENSTACK_SIZE 10
 
 /*
- * If you need to change this, change acpigen_write_f and
+ * If you need to change this, change acpigen_write_len_f and
  * acpigen_pop_len
  */
 
-#define ACPIGEN_MAXLEN 0xfff
+#define ACPIGEN_MAXLEN 0xfffff
 
 #include <string.h>
 #include <arch/acpigen.h>
@@ -43,6 +44,7 @@ void acpigen_write_len_f(void)
 	len_stack[ltop++] = gencurrent;
 	acpigen_emit_byte(0);
 	acpigen_emit_byte(0);
+	acpigen_emit_byte(0);
 }
 
 void acpigen_pop_len(void)
@@ -52,9 +54,10 @@ void acpigen_pop_len(void)
 	char *p = len_stack[--ltop];
 	len = gencurrent - p;
 	ASSERT(len <= ACPIGEN_MAXLEN)
-	/* generate store length for 0xfff max */
-	p[0] = (0x40 | (len & 0xf));
+	/* generate store length for 0xfffff max */
+	p[0] = (0x80 | (len & 0xf));
 	p[1] = (len >> 4 & 0xff);
+	p[2] = (len >> 12 & 0xff);
 
 }
 
@@ -483,6 +486,21 @@ void acpigen_write_CST_package(acpi_cstate_t *cstate, int nentries)
 	acpigen_pop_len();
 }
 
+void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype, u32 index)
+{
+	acpigen_write_name("_CSD");
+	acpigen_write_package(1);
+	acpigen_write_package(6);
+	acpigen_write_byte(6);	// 6 values
+	acpigen_write_byte(0);	// revision 0
+	acpigen_write_dword(domain);
+	acpigen_write_dword(coordtype);
+	acpigen_write_dword(numprocs);
+	acpigen_write_dword(index);
+	acpigen_pop_len();
+	acpigen_pop_len();
+}
+
 void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list)
 {
 /*
diff --git a/src/arch/x86/include/arch/acpigen.h b/src/arch/x86/include/arch/acpigen.h
index a3e65eb..8e50960 100644
--- a/src/arch/x86/include/arch/acpigen.h
+++ b/src/arch/x86/include/arch/acpigen.h
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -55,6 +56,8 @@ typedef enum { SW_ALL=0xfc, SW_ANY=0xfd, HW_ALL=0xfe } PSD_coord;
 void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
 void acpigen_write_CST_package_entry(acpi_cstate_t *cstate);
 void acpigen_write_CST_package(acpi_cstate_t *entry, int nentries);
+typedef enum { CSD_HW_ALL=0xfe } CSD_coord;
+void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype, u32 index);
 void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len);
 void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list);
 void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c b/src/cpu/amd/family_10h-family_15h/fidvid.c
index e8e0818..0e7d299 100644
--- a/src/cpu/amd/family_10h-family_15h/fidvid.c
+++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
@@ -169,87 +169,87 @@ static void applyBoostFIDOffset(device_t dev, uint32_t nodeid) {
 }
 
 static void enableNbPState1( device_t dev ) {
-  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
-  if (cpuRev & AMD_FAM10_C3) {
-    u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
-    if ( nbPState){
-      u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & NB_VID1_MASK) >> NB_VID1_SHIFT;
-      u32 i;
-      for (i = nbPState; i < NM_PS_REG; i++) {
-         msr_t msr =  rdmsr(PS_REG_BASE + i);
-         if (msr.hi &  PS_EN_MASK ) {
-            msr.hi |= NB_DID_M_ON;
-            msr.lo &= NB_VID_MASK_OFF;
-	    msr.lo |= ( nbVid1 << NB_VID_POS);
-	    wrmsr(PS_REG_BASE + i, msr);
-	 }
-      }
-    }
-  }
+	uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
+	if (cpuRev & AMD_FAM10_C3) {
+		u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
+		if ( nbPState){
+			u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & NB_VID1_MASK) >> NB_VID1_SHIFT;
+			u32 i;
+			for (i = nbPState; i < NM_PS_REG; i++) {
+				msr_t msr =  rdmsr(PS_REG_BASE + i);
+				if (msr.hi &  PS_EN_MASK ) {
+				msr.hi |= NB_DID_M_ON;
+				msr.lo &= NB_VID_MASK_OFF;
+				msr.lo |= ( nbVid1 << NB_VID_POS);
+				wrmsr(PS_REG_BASE + i, msr);
+				}
+			}
+		}
+	}
 }
 
-static u8 setPStateMaxVal( device_t dev ) {
-      u8 i,maxpstate=0;
-      for (i = 0; i < NM_PS_REG; i++) {
-         msr_t msr =  rdmsr(PS_REG_BASE + i);
-         if (msr.hi & PS_IDD_VALUE_MASK) {
-	   msr.hi |= PS_EN_MASK ;
-	     wrmsr(PS_REG_BASE + i, msr);
-	 }
-         if (msr.hi & PS_EN_MASK) {
-	   maxpstate = i;
-	 }
-      }
-      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
-      u32 reg = pci_read_config32(dev, CPTC2);
-      reg &= PS_MAX_VAL_MASK;
-      reg |= (maxpstate << PS_MAX_VAL_POS);
-      pci_write_config32(dev, CPTC2,reg);
-      return maxpstate;
+static u8 setPStateMaxVal(device_t dev) {
+	u8 i, maxpstate=0;
+	for (i = 0; i < NM_PS_REG; i++) {
+		msr_t msr = rdmsr(PS_REG_BASE + i);
+		if (msr.hi & PS_IDD_VALUE_MASK) {
+			msr.hi |= PS_EN_MASK ;
+			wrmsr(PS_REG_BASE + i, msr);
+		}
+		if (msr.hi & PS_EN_MASK) {
+			maxpstate = i;
+		}
+	}
+	//FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
+	u32 reg = pci_read_config32(dev, CPTC2);
+	reg &= PS_MAX_VAL_MASK;
+	reg |= (maxpstate << PS_MAX_VAL_POS);
+	pci_write_config32(dev, CPTC2,reg);
+	return maxpstate;
 }
 
 static void dualPlaneOnly(  device_t dev ) {
-  // BKDG 2.4.2.7
-
-  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
-  if ((mctGetProcessorPackageType() ==  AMD_PKGTYPE_AM3_2r2)
-      && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no constant for E
-    if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
-	 && (pci_read_config32(dev, 0xA0) & PVI_MODE) ){
-      if (cpuid_edx(0x80000007) & CPB_MASK) {
-          // revision E only, but E is apparently not supported yet, therefore untested
-         msr_t minPstate = rdmsr(0xC0010065);
-         wrmsr(0xC0010065, rdmsr(0xC0010068) );
-         wrmsr(0xC0010068,minPstate);
-      } else {
-	 msr_t msr;
-         msr.lo=0; msr.hi=0;
-         wrmsr(0xC0010064, rdmsr(0xC0010068) );
-         wrmsr(0xC0010068, msr );
-      }
-
-      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
-      u8 maxpstate = setPStateMaxVal(dev);
-
-      u32 reg = pci_read_config32(dev, HTC_REG);
-      reg &= HTC_PS_LMT_MASK;
-      reg |= (maxpstate << PS_LIMIT_POS);
-      pci_write_config32(dev, HTC_REG,reg);
-
-    }
-  }
+	// BKDG 2.4.2.7
+
+	uint64_t cpuRev = mctGetLogicalCPUID(0xFF);
+	if ((mctGetProcessorPackageType() == AMD_PKGTYPE_AM3_2r2)
+		&& (cpuRev & (AMD_DR_Cx | AMD_DR_Ex))) {
+		if ((pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
+			&& (pci_read_config32(dev, 0xA0) & PVI_MODE)) {
+			if (cpuid_edx(0x80000007) & CPB_MASK) {
+				// revision E only, but E is apparently not supported yet, therefore untested
+				msr_t minPstate = rdmsr(0xC0010065);
+				wrmsr(0xC0010065, rdmsr(0xC0010068));
+				wrmsr(0xC0010068, minPstate);
+			} else {
+				msr_t msr;
+				msr.lo=0; msr.hi=0;
+				wrmsr(0xC0010064, rdmsr(0xC0010068) );
+				wrmsr(0xC0010068, msr);
+			}
+
+			//FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
+			u8 maxpstate = setPStateMaxVal(dev);
+
+			u32 reg = pci_read_config32(dev, HTC_REG);
+			reg &= HTC_PS_LMT_MASK;
+			reg |= (maxpstate << PS_LIMIT_POS);
+			pci_write_config32(dev, HTC_REG,reg);
+		}
+	}
 }
 
 static int vidTo100uV(u8 vid)
-{// returns voltage corresponding to vid in tenths of mV, i.e. hundreds of uV
- // BKDG #31116 rev 3.48 2.4.1.6
-  int voltage;
-  if (vid >= 0x7c) {
-    voltage = 0;
-  } else {
-    voltage = (15500 - (125*vid));
-  }
-  return voltage;
+{
+	// returns voltage corresponding to vid in tenths of mV, i.e. hundreds of uV
+	// BKDG #31116 rev 3.48 2.4.1.6
+	int voltage;
+	if (vid >= 0x7c) {
+		voltage = 0;
+	} else {
+		voltage = (15500 - (125*vid));
+	}
+	return voltage;
 }
 
 static void setVSRamp(device_t dev) {
@@ -348,7 +348,7 @@ static void recalculateVsSlamTimeSettingOnCorePre(device_t dev)
 	}
 
 	/* Get AltVID */
-	dtemp = pci_read_config32(dev, 0xDC);
+	dtemp = pci_read_config32(dev, 0xdc);
 	bValue = (u8) (dtemp & BIT_MASK_7);
 
 	/* Use the VID with the lowest voltage (higher VID) */
@@ -512,15 +512,15 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 cpuRev) {
            values (min latency) */
 	u32 nbPstate = pci_read_config32(dev,0x1f0) & NB_PSTATE_MASK;
         u8 nbSynPtrAdj;
-	if ((cpuRev & (AMD_DR_Bx|AMD_DA_Cx) )
-	    || ( (cpuRev & AMD_RB_C3) && (nbPstate!=0)))  {
-	  nbSynPtrAdj = 5;
+	if ((cpuRev & (AMD_DR_Bx | AMD_DA_Cx | AMD_FAM15_ALL) )
+		|| ((cpuRev & AMD_RB_C3) && (nbPstate != 0))) {
+		nbSynPtrAdj = 5;
 	} else {
-          nbSynPtrAdj = 6;
+		nbSynPtrAdj = 6;
 	}
 
-	u32 dword = pci_read_config32(dev, 0xDc);
-        dword &= ~ NB_SYN_PTR_ADJ_MASK;
+	u32 dword = pci_read_config32(dev, 0xdc);
+        dword &= ~NB_SYN_PTR_ADJ_MASK;
 	dword |= nbSynPtrAdj << NB_SYN_PTR_ADJ_POS;
         /* NbsynPtrAdj set to 5 or 6 per BKDG (needs reset) */
 	pci_write_config32(dev, 0xdc, dword);
@@ -552,7 +552,7 @@ static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 procPkg
 			}
 		} else { // rev C or later
 			// same doubt as cache scrubbing: ok to check current state ?
-			dword = pci_read_config32(dev, 0xDC);
+			dword = pci_read_config32(dev, 0xdc);
 			u32 cacheFlushOnHalt = dword & (7 << 16);
 			if (!cacheFlushOnHalt) {
 				c1 = 0x80;
@@ -623,11 +623,11 @@ static void prep_fid_change(void)
 		printk(BIOS_DEBUG, "  F3x80: %08x\n", dword);
 		dword = pci_read_config32(dev, 0x84);
 		printk(BIOS_DEBUG, "  F3x84: %08x\n", dword);
-		dword = pci_read_config32(dev, 0xD4);
+		dword = pci_read_config32(dev, 0xd4);
 		printk(BIOS_DEBUG, "  F3xD4: %08x\n", dword);
-		dword = pci_read_config32(dev, 0xD8);
+		dword = pci_read_config32(dev, 0xd8);
 		printk(BIOS_DEBUG, "  F3xD8: %08x\n", dword);
-		dword = pci_read_config32(dev, 0xDC);
+		dword = pci_read_config32(dev, 0xdc);
 		printk(BIOS_DEBUG, "  F3xDC: %08x\n", dword);
 	}
 }
@@ -756,7 +756,7 @@ static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid, u32 dev, u8 pviMode)
          * 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)) ) {
+        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");
 	};
 
diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c b/src/cpu/amd/family_10h-family_15h/init_cpus.c
index aced850..061bba2 100644
--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
@@ -30,6 +30,14 @@
 #include <northbridge/amd/amdfam10/raminit_amdmct.c>
 #include <reset.h>
 
+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700)
+#include <southbridge/amd/sb700/sb700.h>
+#endif
+
+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
+#include <southbridge/amd/sb800/sb800.h>
+#endif
+
 #if IS_ENABLED(CONFIG_SET_FIDVID)
 static void prep_fid_change(void);
 static void init_fidvid_stage2(u32 apicid, u32 nodeid);
@@ -874,6 +882,7 @@ void cpuSetAMDMSR(uint8_t node_id)
 	u8 i;
 	u32 platform;
 	uint64_t revision;
+	uint8_t enable_c_states;
 
 	printk(BIOS_DEBUG, "cpuSetAMDMSR ");
 
@@ -936,6 +945,44 @@ void cpuSetAMDMSR(uint8_t node_id)
 		wrmsr(FP_CFG, msr);
 	}
 
+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
+	uint8_t nvram;
+
+	if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
+		/* Set up message triggered C1E */
+		msr = rdmsr(0xc0010055);
+		msr.lo &= ~0xffff;		/* IOMsgAddr = ACPI_PM_EVT_BLK */
+		msr.lo |= ACPI_PM_EVT_BLK & 0xffff;
+		msr.lo |= (0x1 << 29);		/* BmStsClrOnHltEn = 1 */
+		if (revision & AMD_DR_GT_D0) {
+			msr.lo &= ~(0x1 << 28);	/* C1eOnCmpHalt = 0 */
+			msr.lo &= ~(0x1 << 27);	/* SmiOnCmpHalt = 0 */
+		}
+		wrmsr(0xc0010055, msr);
+
+		msr = rdmsr(0xc0010015);
+		msr.lo |= (0x1 << 12);		/* HltXSpCycEn = 1 */
+		wrmsr(0xc0010015, msr);
+	}
+
+	if (revision & (AMD_DR_Ex | AMD_FAM15_ALL)) {
+		enable_c_states = 0;
+		if (IS_ENABLED(CONFIG_HAVE_ACPI_TABLES))
+			if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
+				enable_c_states = !!nvram;
+
+		if (enable_c_states) {
+			/* Set up the C-state base address */
+			msr_t c_state_addr_msr;
+			c_state_addr_msr = rdmsr(0xc0010073);
+			c_state_addr_msr.lo = ACPI_CPU_P_LVL2;	/* CstateAddr = ACPI_CPU_P_LVL2 */
+			wrmsr(0xc0010073, c_state_addr_msr);
+		}
+	}
+#else
+	enable_c_states = 0;
+#endif
+
 	printk(BIOS_DEBUG, " done\n");
 }
 
@@ -950,6 +997,7 @@ static void cpuSetAMDPCI(u8 node)
 	u32 platform;
 	u32 val;
 	u8 offset;
+	uint32_t dword;
 	uint64_t revision;
 
 	printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node);
@@ -1008,6 +1056,39 @@ static void cpuSetAMDPCI(u8 node)
 	   if (revision & (AMD_DR_B2 | AMD_DR_B3))
 	   dctPhyDiag(); */
 
+	if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
+		/* Set up message triggered C1E */
+		dword = pci_read_config32(NODE_PCI(node, 3), 0xd4);
+		dword &= ~(0x1 << 14);			/* CacheFlushImmOnAllHalt = !is_fam15h() */
+		dword |= (is_fam15h()?0:1) << 14;
+		pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
+
+		dword = pci_read_config32(NODE_PCI(node, 3), 0xdc);
+		dword |= 0x1 << 26;			/* IgnCpuPrbEn = 1 */
+		dword &= ~(0x7f << 19);			/* CacheFlushOnHaltTmr = 0x28 */
+		dword |= 0x28 << 19;
+		dword |= 0x7 << 16;			/* CacheFlushOnHaltCtl = 0x7 */
+		pci_write_config32(NODE_PCI(node, 3), 0xdc, dword);
+
+		dword = pci_read_config32(NODE_PCI(node, 3), 0xa0);
+		dword |= 0x1 << 10;			/* IdleExitEn = 1 */
+		pci_write_config32(NODE_PCI(node, 3), 0xa0, dword);
+
+		if (revision & AMD_DR_GT_D0) {
+			dword = pci_read_config32(NODE_PCI(node, 3), 0x188);
+			dword |= 0x1 << 4;			/* EnStpGntOnFlushMaskWakeup = 1 */
+			pci_write_config32(NODE_PCI(node, 3), 0x188, dword);
+		} else {
+			dword = pci_read_config32(NODE_PCI(node, 4), 0x128);
+			dword &= ~(0x1 << 31);			/* CstateMsgDis = 0 */
+			pci_write_config32(NODE_PCI(node, 4), 0x128, dword);
+		}
+
+		dword = pci_read_config32(NODE_PCI(node, 3), 0xd4);
+		dword |= 0x1 << 13;			/* MTC1eEn = 1 */
+		pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
+	}
+
 	printk(BIOS_DEBUG, " done\n");
 }
 
diff --git a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
index 84e5514..028ae3f 100644
--- a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
+++ b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
@@ -21,6 +21,7 @@
 
 #include <console/console.h>
 #include <stdint.h>
+#include <option.h>
 #include <cpu/x86/msr.h>
 #include <arch/acpigen.h>
 #include <cpu/amd/powernow.h>
@@ -34,21 +35,29 @@
 #include <northbridge/amd/amdmct/mct/mct.h>
 #include <northbridge/amd/amdmct/amddefs.h>
 
+static inline uint8_t is_fam15h(void)
+{
+	uint8_t fam15h = 0;
+	uint32_t family;
+
+	family = cpuid_eax(0x80000001);
+	family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+
+	if (family >= 0x6f)
+		/* Family 15h or later */
+		fam15h = 1;
+
+	return fam15h;
+}
+
 static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 *pstate_power,
 				u32 *pstate_latency, u32 *pstate_control,
 				u32 *pstate_status, int coreID,
-				u32 pcontrol_blk, u8 plen, u8 onlyBSP,
 				uint8_t single_link)
 {
 	int i;
 	struct cpuid_result cpuid1;
 
-	if ((onlyBSP) && (coreID != 0)) {
-	    plen = 0;
-	    pcontrol_blk = 0;
-	}
-
-	acpigen_write_processor(coreID, pcontrol_blk, plen);
 	acpigen_write_empty_PCT();
 	acpigen_write_name("_PSS");
 
@@ -92,9 +101,62 @@ static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 *pstate_p
 		if (cpu)
 			acpigen_write_PSD_package(cpu->path.apic.apic_id, 1, SW_ANY);
 	}
+}
 
-	/* patch the whole Processor token length */
-	acpigen_pop_len();
+static void write_cstates_for_core(int coreID)
+{
+	/* Generate C state entries */
+	uint8_t cstate_count = 1;
+	acpi_cstate_t cstate;
+
+	if (is_fam15h()) {
+		cstate.ctype = 2;
+		cstate.latency = 100;
+		cstate.power = 0;
+		cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO;
+		cstate.resource.bit_width = 8;
+		cstate.resource.bit_offset = 0;
+		cstate.resource.addrl = rdmsr(0xc0010073).lo + 1;
+		cstate.resource.addrh = 0;
+		cstate.resource.resv = 1;
+	} else {
+		cstate.ctype = 2;
+		cstate.latency = 75;
+		cstate.power = 0;
+		cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO;
+		cstate.resource.bit_width = 8;
+		cstate.resource.bit_offset = 0;
+		cstate.resource.addrl = rdmsr(0xc0010073).lo;
+		cstate.resource.addrh = 0;
+		cstate.resource.resv = 1;
+	}
+
+	acpigen_write_CST_package(&cstate, cstate_count);
+
+	/* Find the local APIC ID for the specified core ID */
+	if (is_fam15h()) {
+		struct device* cpu;
+		int cpu_index = 0;
+		for (cpu = all_devices; cpu; cpu = cpu->next) {
+			if ((cpu->path.type != DEVICE_PATH_APIC) ||
+				(cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER))
+				continue;
+			if (!cpu->enabled)
+				continue;
+			if (cpu_index == coreID)
+				break;
+			cpu_index++;
+		}
+
+		if (cpu) {
+			/* TODO
+			 * Detect dual core status and skip CSD generation if dual core is disabled
+			 */
+
+			/* Generate C state dependency entries */
+			acpigen_write_CSD_package((cpu->path.apic.apic_id >> 1) & 0x7f, 2, CSD_HW_ALL, 0);
+		}
+	}
 }
 
 /*
@@ -125,6 +187,15 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
 	u8 index;
 	msr_t msr;
 
+	uint8_t nvram;
+	uint8_t enable_c_states;
+
+	enable_c_states = 0;
+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
+	if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
+		enable_c_states = !!nvram;
+#endif
+
 	/* Get the Processor Brand String using cpuid(0x8000000x) command x=2,3,4 */
 	cpuid1 = cpuid(0x80000002);
 	v = (u32 *) processor_brand;
@@ -200,6 +271,10 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
 		return;
 	}
 
+	if (fam15h)
+		/* Set P_LVL2 P_BLK entry */
+		*(((uint8_t *)pcontrol_blk) + 0x04) = (rdmsr(0xc0010073).lo + 1) & 0xff;
+
 	uint8_t pviModeFlag;
 	uint8_t Pstate_max;
 	uint8_t cpufid;
@@ -318,18 +393,56 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
 			    Pstate_latency[index]);
 	}
 
+	/* Enter processor block scope */
 	char pscope[] = "\\_PR";
-
 	acpigen_write_scope(pscope);
+
 	for (index = 0; index < total_core_count; index++) {
 		/* Determine if this is a single-link processor */
 		node_index = 0x18 + (index / cores_per_node);
 		dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(node_index, 0)), 0x80);
 		single_link = !!(((dtemp & 0xff00) >> 8) == 0);
 
+		/* Enter processor core scope */
+		uint8_t plen_cur = plen;
+		uint32_t pcontrol_blk_cur = pcontrol_blk;
+		if ((onlyBSP) && (index != 0)) {
+			plen_cur = 0;
+			pcontrol_blk_cur = 0;
+		}
+		acpigen_write_processor(index, pcontrol_blk_cur, plen_cur);
+
+		/* Write P-state status and dependency objects */
 		write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_power,
 				Pstate_latency, Pstate_control, Pstate_status,
-				index, pcontrol_blk, plen, onlyBSP, single_link);
+				index, single_link);
+
+		/* Write C-state status and dependency objects */
+		if (fam15h && enable_c_states)
+			write_cstates_for_core(index);
+
+		/* Exit processor core scope */
+		acpigen_pop_len();
 	}
+
+	/* Exit processor block scope */
 	acpigen_pop_len();
 }
+
+void amd_powernow_update_fadt(acpi_fadt_t * fadt)
+{
+	if (is_fam15h()) {
+		fadt->p_lvl2_lat = 101;		/* NOTE: While the BKDG states this should
+						 * be set to 100, there is no way to meet
+						 * the other FADT requirements.  I suspect
+						 * there is an error in the BKDG for ACPI
+						 * 1.x support; disable all FADT-based C
+						 * states > 2... */
+		fadt->p_lvl3_lat = 1001;
+		fadt->flags |= 0x1 << 2;	/* FLAGS.PROC_C1 = 1 */
+		fadt->flags |= 0x1 << 3;	/* FLAGS.P_LVL2_UP = 1 */
+	} else {
+		fadt->cst_cnt = 0;
+	}
+	fadt->pstate_cnt = 0;
+}
diff --git a/src/include/cpu/amd/powernow.h b/src/include/cpu/amd/powernow.h
index 85356bd..07817d9 100644
--- a/src/include/cpu/amd/powernow.h
+++ b/src/include/cpu/amd/powernow.h
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2009 Rudolf Marek <r.marek@assembler.cz>
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,5 +22,6 @@
 #define POWERNOW_H
 
 void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP);
+void amd_powernow_update_fadt(acpi_fadt_t * fadt);
 
 #endif
diff --git a/src/mainboard/asus/kgpe-d16/cmos.default b/src/mainboard/asus/kgpe-d16/cmos.default
index bfd2020..e3eb4fe 100644
--- a/src/mainboard/asus/kgpe-d16/cmos.default
+++ b/src/mainboard/asus/kgpe-d16/cmos.default
@@ -14,6 +14,7 @@ ecc_scrub_rate = 1.28us
 interleave_chip_selects = Enable
 interleave_nodes = Disable
 interleave_memory_channels = Enable
+cpu_c_states = Enable
 cpu_cc6_state = Enable
 ieee1394 = Enable
 power_on_after_fail = On
diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout b/src/mainboard/asus/kgpe-d16/cmos.layout
index 630219e..7f9f661 100644
--- a/src/mainboard/asus/kgpe-d16/cmos.layout
+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
@@ -43,8 +43,9 @@ entries
 458          4       e       11       hypertransport_speed_limit
 462          2       e       12       minimum_memory_voltage
 464          1       e       2        compute_unit_siblings
-465          1       e       1        cpu_cc6_state
-466          1       r       0        allow_spd_nvram_cache_restore
+465          1       e       1        cpu_c_states
+466          1       e       1        cpu_cc6_state
+467          1       r       0        allow_spd_nvram_cache_restore
 477          1       e       1        ieee1394
 728        256       h       0        user_data
 984         16       h       0        check_sum
diff --git a/src/northbridge/amd/amdfam10/link_control.c b/src/northbridge/amd/amdfam10/link_control.c
index 1091ef4..7fa9f12 100644
--- a/src/northbridge/amd/amdfam10/link_control.c
+++ b/src/northbridge/amd/amdfam10/link_control.c
@@ -49,15 +49,94 @@ static inline uint8_t is_fam15h(void)
 
 static void nb_control_init(struct device *dev)
 {
+	uint8_t enable_c_states;
+	uint8_t enable_cc6;
 	uint32_t dword;
 
 	printk(BIOS_DEBUG, "NB: Function 4 Link Control.. ");
 
+	/* Configure L3 Power Control */
+	dword = pci_read_config32(dev, 0x1c4);
+	dword |= (0x1 << 8);			/* L3PwrSavEn = 1 */
+	pci_write_config32(dev, 0x1c4, dword);
+
 	if (is_fam15h()) {
+		/* Configure L3 Control 2 */
+		dword = pci_read_config32(dev, 0x1cc);
+		dword &= ~(0x7 << 6);			/* ImplRdProjDelayThresh = 0x2 */
+		dword |= (0x2 << 6);
+		pci_write_config32(dev, 0x1cc, dword);
+
+		/* Configure TDP Accumulator Divisor Control */
+		dword = pci_read_config32(dev, 0x104);
+		dword &= ~(0xfff << 2);			/* TdpAccDivRate = 0xc8 */
+		dword |= (0xc8 << 2);
+		dword &= ~0x3;				/* TdpAccDivVal = 0x1 */
+		dword |= 0x1;
+		pci_write_config32(dev, 0x104, dword);
+
+		/* Configure Sample and Residency Timers */
+		dword = pci_read_config32(dev, 0x110);
+		dword &= ~0xfff;			/* CSampleTimer = 0x1 */
+		dword |= 0x1;
+		pci_write_config32(dev, 0x110, dword);
+
+		/* Configure APM TDP Control */
+		dword = pci_read_config32(dev, 0x16c);
+		dword |= (0x1 << 4);			/* ApmTdpLimitIntEn = 1 */
+		pci_write_config32(dev, 0x16c, dword);
+
 		/* Enable APM */
 		dword = pci_read_config32(dev, 0x15c);
 		dword |= (0x1 << 7);			/* ApmMasterEn = 1 */
 		pci_write_config32(dev, 0x15c, dword);
+
+		enable_c_states = 0;
+		enable_cc6 = 0;
+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
+		uint8_t nvram;
+
+		if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
+			enable_c_states = !!nvram;
+
+		if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
+			enable_cc6 = !!nvram;
+#endif
+
+		if (enable_c_states) {
+			/* Configure C-state Control 1 */
+			dword = pci_read_config32(dev, 0x118);
+			dword |= (0x1 << 24);		/* PwrGateEnCstAct1 = 1 */
+			dword &= ~(0x7 << 21);		/* ClkDivisorCstAct1 = 0x0 */
+			dword &= ~(0x3 << 18);		/* CacheFlushTmrSelCstAct1 = 0x1 */
+			dword |= (0x1 << 18);
+			dword |= (0x1 << 17);		/* CacheFlushEnCstAct1 = 1 */
+			dword |= (0x1 << 16);		/* CpuPrbEnCstAct1 = 1 */
+			dword &= ~(0x1 << 8);		/* PwrGateEnCstAct0 = 0 */
+			dword &= ~(0x7 << 5);		/* ClkDivisorCstAct0 = 0x0 */
+			dword &= ~(0x3 << 2);		/* CacheFlushTmrSelCstAct0 = 0x2 */
+			dword |= (0x2 << 2);
+			dword |= (0x1 << 1);		/* CacheFlushEnCstAct0 = 1 */
+			dword |= 0x1;			/* CpuPrbEnCstAct0 = 1 */
+			pci_write_config32(dev, 0x118, dword);
+
+			/* Configure C-state Control 2 */
+			dword = pci_read_config32(dev, 0x11c);
+			dword &= ~(0x1 << 8);		/* PwrGateEnCstAct2 = 0 */
+			dword &= ~(0x7 << 5);		/* ClkDivisorCstAct2 = 0x0 */
+			dword &= ~(0x3 << 2);		/* CacheFlushTmrSelCstAct0 = 0x0 */
+			dword &= ~(0x1 << 1);		/* CacheFlushEnCstAct0 = 0 */
+			dword &= ~(0x1);		/* CpuPrbEnCstAct0 = 0 */
+			pci_write_config32(dev, 0x11c, dword);
+
+			/* Configure C-state Policy Control 1 */
+			dword = pci_read_config32(dev, 0x128);
+			dword &= ~(0x7f << 5);		/* CacheFlushTmr = 0x28 */
+			dword |= (0x28 << 5);
+			dword &= ~0x1;			/* CoreCstateMode = !enable_cc6 */
+			dword |= ((enable_cc6)?0:1);
+			pci_write_config32(dev, 0x128, dword);
+		}
 	}
 
 	printk(BIOS_DEBUG, "done.\n");
@@ -83,4 +162,4 @@ static const struct pci_driver mcf4_driver_fam15 __pci_driver = {
 	.ops    = &mcf4_ops,
 	.vendor = PCI_VENDOR_ID_AMD,
 	.device = 0x1604,
-};
\ No newline at end of file
+};
diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c
index e5612fa..9fe0ccb 100644
--- a/src/northbridge/amd/amdfam10/northbridge.c
+++ b/src/northbridge/amd/amdfam10/northbridge.c
@@ -770,53 +770,49 @@ static void amdfam10_domain_read_resources(device_t dev)
 			uint8_t num_nodes;
 
 			/* Find highest DRAM range (DramLimitAddr) */
+			num_nodes = 0;
 			max_node = 0;
 			max_range = -1;
 			interleaved = 0;
 			max_range_limit = 0;
-			for (range = 0; range < 8; range++) {
-				dword = f1_read_config32(0x40 + (range * 0x8));
-				if (!(dword & 0x3))
-					continue;
-
-				if ((dword >> 8) & 0x7)
-					interleaved = 1;
-
-				dword = f1_read_config32(0x44 + (range * 0x8));
-				dword2 = f1_read_config32(0x144 + (range * 0x8));
-				qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
-				qword |= (((uint64_t)dword2) & 0xff) << 40;
-
-				if (qword > max_range_limit) {
-					max_range = range;
-					max_range_limit = qword;
-					max_node = dword & 0x7;
-				}
-			}
-
-			num_nodes = 0;
 			device_t node_dev;
 			for (node = 0; node < FX_DEVS; node++) {
 				node_dev = get_node_pci(node, 0);
 				/* Test for node presence */
-				if ((node_dev) && (pci_read_config32(node_dev, PCI_VENDOR_ID) != 0xffffffff))
-					num_nodes++;
+				if ((!node_dev) || (pci_read_config32(node_dev, PCI_VENDOR_ID) == 0xffffffff))
+					continue;
+
+				num_nodes++;
+				for (range = 0; range < 8; range++) {
+					dword = pci_read_config32(get_node_pci(node, 1), 0x40 + (range * 0x8));
+					if (!(dword & 0x3))
+						continue;
+
+					if ((dword >> 8) & 0x7)
+						interleaved = 1;
+
+					dword = pci_read_config32(get_node_pci(node, 1), 0x44 + (range * 0x8));
+					dword2 = pci_read_config32(get_node_pci(node, 1), 0x144 + (range * 0x8));
+					qword = 0xffffff;
+					qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24;
+					qword |= (((uint64_t)dword2) & 0xff) << 40;
+
+					if (qword > max_range_limit) {
+						max_range = range;
+						max_range_limit = qword;
+						max_node = dword & 0x7;
+					}
+				}
 			}
 
-			/* Calculate CC6 sotrage area size */
+			/* Calculate CC6 storage area size */
 			if (interleaved)
 				qword = (0x1000000 * num_nodes);
 			else
 				qword = 0x1000000;
 
 			/* Reserve the CC6 save segment */
-			reserved_ram_resource(dev, 8, max_range_limit >> 10, qword >> 10);
-
-			/* Set up the C-state base address */
-			msr_t c_state_addr_msr;
-			c_state_addr_msr = rdmsr(0xc0010073);
-			c_state_addr_msr.lo = 0xe0e0;		/* CstateAddr = 0xe0e0 */
-			wrmsr(0xc0010073, c_state_addr_msr);
+			reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 10, qword >> 10);
 		}
 	}
 }
diff --git a/src/northbridge/amd/amdht/AsPsDefs.h b/src/northbridge/amd/amdht/AsPsDefs.h
index caeb9b4..7f29dd1 100644
--- a/src/northbridge/amd/amdht/AsPsDefs.h
+++ b/src/northbridge/amd/amdht/AsPsDefs.h
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -254,7 +255,7 @@
 #define DUAL_PLANE_NB_VID_SHIFT 17/* for CPU rev <= C */
 
 
-#define NM_PS_REG 5			/* number of P-state MSR registers */
+#define NM_PS_REG (is_fam15h()?8:5)	/* number of P-state MSR registers */
 
 /* sFidVidInit.outFlags defines */
 #define PWR_CK_OK 0			/* System board check OK */
diff --git a/src/northbridge/amd/amdmct/amddefs.h b/src/northbridge/amd/amdmct/amddefs.h
index 20a77d3..7aa4698 100644
--- a/src/northbridge/amd/amdmct/amddefs.h
+++ b/src/northbridge/amd/amdmct/amddefs.h
@@ -53,32 +53,34 @@
 /*
  * Groups - Create as many as you wish, from the above public values
  */
-#define	AMD_NPT_F2	(AMD_NPT_F2C | AMD_NPT_F2D | AMD_NPT_F2E | AMD_NPT_F2G | AMD_NPT_F2J | AMD_NPT_F2K)
-#define	AMD_NPT_F3	(AMD_NPT_F3L)
-#define	AMD_NPT_Fx	(AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2 | AMD_NPT_F3)
-#define	AMD_NPT_Gx	(AMD_NPT_G0A | AMD_NPT_G1B)
-#define	AMD_NPT_ALL	(AMD_NPT_Fx | AMD_NPT_Gx)
-#define	AMD_FINEDELAY	(AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2)
-#define	AMD_GT_F0	(AMD_NPT_ALL AND NOT AMD_NPT_F0)
-#define	AMD_DR_Ax	(AMD_DR_A0A + AMD_DR_A1B + AMD_DR_A2)
-#define	AMD_DR_Bx	(AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_B3 | AMD_DR_BA)
-#define	AMD_DR_LT_B2	(AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)
-#define	AMD_DR_LT_B3	(AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_BA)
-#define	AMD_DR_GT_B0	(AMD_DR_ALL & ~(AMD_DR_B0))
-#define	AMD_DR_GT_Bx	(AMD_DR_ALL & ~(AMD_DR_Ax | AMD_DR_Bx))
-#define	AMD_DR_ALL	(AMD_DR_Bx)
-#define	AMD_FAM10_ALL	(AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | AMD_DA_C3 | AMD_DA_C2 | AMD_RB_C3 | AMD_HY_D1 | AMD_PH_E0)
-#define AMD_FAM10_LT_D  (AMD_FAM10_ALL & ~(AMD_HY_D0))
-#define	AMD_FAM10_GT_B0	(AMD_FAM10_ALL & ~(AMD_DR_B0))
-#define AMD_FAM10_REV_D	(AMD_HY_D0 | AMD_HY_D1)
-#define	AMD_DA_Cx       (AMD_DA_C2 | AMD_DA_C3)
-#define	AMD_DR_Cx       (AMD_RB_C2 | AMD_RB_C3 | AMD_DA_Cx)
-#define	AMD_FAM10_C3       (AMD_RB_C3 | AMD_DA_C3)
-#define	AMD_DR_Dx	(AMD_HY_D0 | AMD_HY_D1)
-#define	AMD_DRBH_Cx	(AMD_DR_Cx | AMD_HY_D0 )
-#define	AMD_DRBA23_RBC2	(AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 )
+#define	AMD_NPT_F2		(AMD_NPT_F2C | AMD_NPT_F2D | AMD_NPT_F2E | AMD_NPT_F2G | AMD_NPT_F2J | AMD_NPT_F2K)
+#define	AMD_NPT_F3		(AMD_NPT_F3L)
+#define	AMD_NPT_Fx		(AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2 | AMD_NPT_F3)
+#define	AMD_NPT_Gx		(AMD_NPT_G0A | AMD_NPT_G1B)
+#define	AMD_NPT_ALL		(AMD_NPT_Fx | AMD_NPT_Gx)
+#define	AMD_FINEDELAY		(AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2)
+#define	AMD_GT_F0		(AMD_NPT_ALL AND NOT AMD_NPT_F0)
+#define	AMD_DR_Ax		(AMD_DR_A0A + AMD_DR_A1B + AMD_DR_A2)
+#define	AMD_DR_Bx		(AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_B3 | AMD_DR_BA)
+#define	AMD_DR_Cx		(AMD_RB_C2 | AMD_RB_C3 | AMD_DA_Cx)
+#define	AMD_DR_Dx		(AMD_HY_D0 | AMD_HY_D1)
+#define	AMD_DR_Ex		(AMD_PH_E0)
+#define	AMD_DR_LT_B2		(AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)
+#define	AMD_DR_LT_B3		(AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_BA)
+#define	AMD_DR_GT_B0		(AMD_DR_ALL & ~(AMD_DR_B0))
+#define	AMD_DR_GT_Bx		(AMD_DR_ALL & ~(AMD_DR_Ax | AMD_DR_Bx))
+#define	AMD_DR_GT_D0		((AMD_DR_Dx & ~(AMD_HY_D0)) | AMD_DR_Ex)
+#define	AMD_DR_ALL		(AMD_DR_Bx)
+#define	AMD_FAM10_ALL		(AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | AMD_DA_C3 | AMD_DA_C2 | AMD_RB_C3 | AMD_HY_D1 | AMD_PH_E0)
+#define AMD_FAM10_LT_D  	(AMD_FAM10_ALL & ~(AMD_HY_D0))
+#define	AMD_FAM10_GT_B0		(AMD_FAM10_ALL & ~(AMD_DR_B0))
+#define AMD_FAM10_REV_D		(AMD_HY_D0 | AMD_HY_D1)
+#define	AMD_DA_Cx       	(AMD_DA_C2 | AMD_DA_C3)
+#define	AMD_FAM10_C3		(AMD_RB_C3 | AMD_DA_C3)
+#define	AMD_DRBH_Cx		(AMD_DR_Cx | AMD_HY_D0 )
+#define	AMD_DRBA23_RBC2		(AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 )
 #define	AMD_DR_DAC2_OR_C3	(AMD_DA_C2 | AMD_DA_C3 | AMD_RB_C3)
-#define	AMD_FAM15_ALL	(AMD_OR_B2 | AMD_OR_C0)
+#define	AMD_FAM15_ALL		(AMD_OR_B2 | AMD_OR_C0)
 
 /*
  *  Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH CPUPLATFORMTYPE RETURN VALUE
@@ -91,9 +93,9 @@
 #define	AMD_PTYPE_MC	0x020	/* Multi Core (>2) */
 #define	AMD_PTYPE_UMA	0x040	/* UMA required */
 
-	/*
-	 * Groups - Create as many as you wish, from the above public values
-	 */
+/*
+ * Groups - Create as many as you wish, from the above public values
+ */
 #define	AMD_PTYPE_ALL	0xFFFFFFFF	/* A mask for all */
 
 
@@ -102,11 +104,11 @@
  */
 #define HTPHY_LINKTYPE_HT3		0x00000001
 #define HTPHY_LINKTYPE_HT1		0x00000002
-#define HTPHY_LINKTYPE_COHERENT	0x00000004
+#define HTPHY_LINKTYPE_COHERENT		0x00000004
 #define HTPHY_LINKTYPE_NONCOHERENT	0x00000008
 #define HTPHY_LINKTYPE_CONNECTED	(HTPHY_LINKTYPE_COHERENT | HTPHY_LINKTYPE_NONCOHERENT)
 #define HTPHY_LINKTYPE_GANGED		0x00000010
-#define HTPHY_LINKTYPE_UNGANGED	0x00000020
+#define HTPHY_LINKTYPE_UNGANGED		0x00000020
 #define HTPHY_LINKTYPE_ALL		0x7FFFFFFF
 
 
@@ -114,7 +116,7 @@
  * CPU HT PHY REGISTERS, FIELDS, AND MASKS
  */
 #define HTPHY_OFFSET_MASK		0xE00001FF
-#define HTPHY_WRITE_CMD		0x40000000
+#define HTPHY_WRITE_CMD			0x40000000
 #define HTPHY_IS_COMPLETE_MASK		0x80000000
 #define HTPHY_DIRECT_MAP		0x20000000
 #define HTPHY_DIRECT_OFFSET_MASK	0xE000FFFF
@@ -162,4 +164,4 @@
 #define AMD_PKGTYPE_S1gX 2
 #define AMD_PKGTYPE_G34 3
 #define AMD_PKGTYPE_ASB2 4
-#define AMD_PKGTYPE_C32 5
+#define AMD_PKGTYPE_C32 5
\ No newline at end of file
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index 2798506..4044c36 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -1197,6 +1197,7 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat,
 	int8_t max_range;
 	uint8_t max_node;
 	uint64_t max_range_limit;
+	uint8_t byte;
 	uint32_t dword;
 	uint32_t dword2;
 	uint64_t qword;
@@ -1216,7 +1217,8 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat,
 
 		dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
 		dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
-		qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
+		qword = 0xffffff;
+		qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24;
 		qword |= (((uint64_t)dword2) & 0xff) << 40;
 
 		if (qword > max_range_limit) {
@@ -1226,26 +1228,35 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat,
 		}
 	}
 
-	if (pDCTstat->Node_ID == max_node) {
-		if (max_range >= 0) {
-			if (interleaved)
-				/* Move upper limit down by 16M * the number of nodes */
-				max_range_limit -= (0x1000000 * num_nodes);
-			else
-				/* Move upper limit down by 16M */
-				max_range_limit -= 0x1000000;
-
-			/* Store modified range */
-			dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
-			dword &= ~(0xffff << 16);		/* DramLimit[39:24] = max_range_limit[39:24] */
-			dword |= (max_range_limit >> 24) & 0xffff;
-			Set_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8), dword);
-
-			dword = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
-			dword &= ~(0xffff << 16);		/* DramLimit[47:40] = max_range_limit[47:40] */
-			dword |= (max_range_limit >> 40) & 0xff;
-			Set_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8), dword);
-		}
+	if (max_range >= 0) {
+		if (interleaved)
+			/* Move upper limit down by 16M * the number of nodes */
+			max_range_limit -= (0x1000000 * num_nodes);
+		else
+			/* Move upper limit down by 16M */
+			max_range_limit -= 0x1000000;
+
+		/* Disable the range */
+		dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
+		byte = dword & 0x3;
+		dword &= ~(0x3);
+		Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword);
+
+		/* Store modified range */
+		dword = Get_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8));
+		dword &= ~(0xffff << 16);		/* DramLimit[39:24] = max_range_limit[39:24] */
+		dword |= ((max_range_limit >> 24) & 0xffff) << 16;
+		Set_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8), dword);
+
+		dword = Get_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8));
+		dword &= ~0xff;			/* DramLimit[47:40] = max_range_limit[47:40] */
+		dword |= (max_range_limit >> 40) & 0xff;
+		Set_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8), dword);
+
+		/* Reenable the range */
+		dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
+		dword |= byte;
+		Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword);
 	}
 
 	/* Determine save state destination node */
@@ -1531,8 +1542,8 @@ restartinit:
 					pDCTstat = pDCTstatA + Node;
 
 					if (pDCTstat->NodePresent) {
-						lock_dram_config(pMCTstat, pDCTstat);
 						set_cc6_save_enable(pMCTstat, pDCTstat, 1);
+						lock_dram_config(pMCTstat, pDCTstat);
 					}
 				}
 			}
@@ -5110,7 +5121,7 @@ static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
 		/* get base/limit from Node0 */
 		reg = 0x40 + (Node << 3);		/* Node0/Dram Base 0 */
 		val = Get_NB32(dev, reg);
-		Drambase = val >> ( 16 + 3);
+		Drambase = val >> (16 + 3);
 
 		reg = 0x44 + (Node << 3);		/* Node0/Dram Base 0 */
 		val = Get_NB32(dev, reg);
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
index 11f1b2c..3a9fecc 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
@@ -159,6 +159,14 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 			if (MemClrECC) {
 				MCTMemClrSync_D(pMCTstat, pDCTstatA);
 			}
+
+			if (pDCTstat->LogicalCPUID & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
+				/* Set up message triggered C1E */
+				val = pci_read_config32(pDCTstat->dev_nbmisc, 0xd4);
+				val &= ~(0x1 << 15);			/* StutterScrubEn = DRAM scrub enabled */
+				val |= (mctGet_NVbits(NV_DramBKScrub)?1:0) << 15;
+				pci_write_config32(pDCTstat->dev_nbmisc, 0xd4, val);
+			}
 		}	/* if Node present */
 	}
 
diff --git a/src/southbridge/amd/sb700/early_setup.c b/src/southbridge/amd/sb700/early_setup.c
index a6849b0..fd3b099 100644
--- a/src/southbridge/amd/sb700/early_setup.c
+++ b/src/southbridge/amd/sb700/early_setup.c
@@ -22,6 +22,7 @@
 #define _SB700_EARLY_SETUP_C_
 
 #include <stdint.h>
+#include <option.h>
 #include <arch/acpi.h>
 #include <arch/cpu.h>
 #include <arch/io.h>
@@ -271,10 +272,6 @@ void enable_fid_change_on_sb(u32 sbbusn, u32 sbdn)
 	byte &= ~(1<<6);
 	pmio_write(0x8d, byte);
 
-	byte = pmio_read(0x61);
-	byte &= ~0x04;
-	pmio_write(0x61, byte);
-
 	byte = pmio_read(0x42);
 	byte &= ~0x04;
 	pmio_write(0x42, byte);
@@ -560,6 +557,13 @@ static void sb700_devices_por_init(void)
 static void sb700_pmio_por_init(void)
 {
 	u8 byte;
+	uint8_t enable_c_states;
+
+	enable_c_states = 0;
+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
+	if (get_option(&byte, "cpu_c_states") == CB_SUCCESS)
+		enable_c_states = !!byte;
+#endif
 
 	printk(BIOS_INFO, "sb700_pmio_por_init()\n");
 	/* K8KbRstEn, KB_RST# control for K8 system. */
@@ -621,6 +625,14 @@ static void sb700_pmio_por_init(void)
 	byte |= 1 << 0;
 	pmio_write(0xB2, byte);
 
+	/* Set up IOAPIC and BM_STS monitoring */
+	byte = pmio_read(0x61);
+	if (enable_c_states)
+		byte |= 0x4;
+	else
+		byte &= ~0x04;
+	pmio_write(0x61, byte);
+
 	// FIXME: Enabling this causes boot to hang while initializing processors.
 // 	/* Enable automatic C1e state switch */
 // 	byte = pmio_read(0xc9);
diff --git a/src/southbridge/amd/sb700/fadt.c b/src/southbridge/amd/sb700/fadt.c
index 96996a3..e860016 100644
--- a/src/southbridge/amd/sb700/fadt.c
+++ b/src/southbridge/amd/sb700/fadt.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,6 +27,7 @@
 #include <arch/acpi.h>
 #include <arch/io.h>
 #include <device/device.h>
+#include <cpu/amd/powernow.h>
 #include "sb700.h"
 
 void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
@@ -156,5 +158,8 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
 	fadt->x_gpe1_blk.addrl = 0;
 	fadt->x_gpe1_blk.addrh = 0x0;
 
+	if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
+		amd_powernow_update_fadt(fadt);
+
 	header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t));
 }
diff --git a/src/southbridge/amd/sb700/sb700.h b/src/southbridge/amd/sb700/sb700.h
index b477091..941a4fd 100644
--- a/src/southbridge/amd/sb700/sb700.h
+++ b/src/southbridge/amd/sb700/sb700.h
@@ -36,10 +36,11 @@
 
 #define ACPI_PM_EVT_BLK		(SB700_ACPI_IO_BASE + 0x00) /* 4 bytes */
 #define ACPI_PM1_CNT_BLK	(SB700_ACPI_IO_BASE + 0x04) /* 2 bytes */
-#define ACPI_PMA_CNT_BLK	(SB700_ACPI_IO_BASE + 0x0E) /* 1 byte */
-#define ACPI_PM_TMR_BLK		(SB700_ACPI_IO_BASE + 0x18) /* 4 bytes */
-#define ACPI_GPE0_BLK		(SB700_ACPI_IO_BASE + 0x10) /* 8 bytes */
+#define ACPI_PMA_CNT_BLK	(SB700_ACPI_IO_BASE + 0x16) /* 1 byte */
+#define ACPI_PM_TMR_BLK		(SB700_ACPI_IO_BASE + 0x20) /* 4 bytes */
+#define ACPI_GPE0_BLK		(SB700_ACPI_IO_BASE + 0x18) /* 8 bytes */
 #define ACPI_CPU_CONTROL	(SB700_ACPI_IO_BASE + 0x08) /* 6 bytes */
+#define ACPI_CPU_P_LVL2		(ACPI_CPU_CONTROL + 0x4)    /* 1 byte */
 
 extern void pm_iowrite(u8 reg, u8 value);
 extern u8 pm_ioread(u8 reg);
diff --git a/src/southbridge/amd/sb700/sm.c b/src/southbridge/amd/sb700/sm.c
index 71253b5..5bd49c5 100644
--- a/src/southbridge/amd/sb700/sm.c
+++ b/src/southbridge/amd/sb700/sm.c
@@ -117,7 +117,10 @@ static void sm_init(device_t dev)
 	pci_write_config8(dev, 0x41, byte);
 
 	byte = pm_ioread(0x61);
-	byte |= 1 << 1;		/* Set to enable NB/SB handshake during IOAPIC interrupt for AMD K8/K7 */
+	if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
+		byte &= ~(1 << 1);	/* Clear for non-K8 CPUs */
+	else
+		byte |= 1 << 1;		/* Set to enable NB/SB handshake during IOAPIC interrupt for AMD K8/K7 */
 	pm_iowrite(0x61, byte);
 
 	/* disable SMI */
diff --git a/src/southbridge/amd/sb800/fadt.c b/src/southbridge/amd/sb800/fadt.c
index fea98f9..30b4496 100644
--- a/src/southbridge/amd/sb800/fadt.c
+++ b/src/southbridge/amd/sb800/fadt.c
@@ -26,6 +26,7 @@
 #include <arch/acpi.h>
 #include <arch/io.h>
 #include <device/device.h>
+#include <cpu/amd/powernow.h>
 #include "sb800.h"
 
 void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
@@ -156,5 +157,8 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
 	fadt->x_gpe1_blk.addrl = 0;
 	fadt->x_gpe1_blk.addrh = 0x0;
 
+	if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
+		amd_powernow_update_fadt(fadt);
+
 	header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t));
 }
diff --git a/src/southbridge/amd/sb800/sb800.h b/src/southbridge/amd/sb800/sb800.h
index 9049182..3e3f077 100644
--- a/src/southbridge/amd/sb800/sb800.h
+++ b/src/southbridge/amd/sb800/sb800.h
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,10 +36,11 @@
 
 #define ACPI_PM_EVT_BLK		(SB800_ACPI_IO_BASE + 0x00) /* 4 bytes */
 #define ACPI_PM1_CNT_BLK	(SB800_ACPI_IO_BASE + 0x04) /* 2 bytes */
-#define ACPI_PMA_CNT_BLK	(SB800_ACPI_IO_BASE + 0x0F) /* 1 byte */
-#define ACPI_PM_TMR_BLK		(SB800_ACPI_IO_BASE + 0x18) /* 4 bytes */
-#define ACPI_GPE0_BLK		(SB800_ACPI_IO_BASE + 0x10) /* 8 bytes */
+#define ACPI_PMA_CNT_BLK	(SB800_ACPI_IO_BASE + 0x17) /* 1 byte */
+#define ACPI_PM_TMR_BLK		(SB800_ACPI_IO_BASE + 0x20) /* 4 bytes */
+#define ACPI_GPE0_BLK		(SB800_ACPI_IO_BASE + 0x18) /* 8 bytes */
 #define ACPI_CPU_CONTROL	(SB800_ACPI_IO_BASE + 0x08) /* 6 bytes */
+#define ACPI_CPU_P_LVL2		(ACPI_CPU_CONTROL + 0x4)    /* 1 byte */
 
 void pm_iowrite(u8 reg, u8 value);
 u8 pm_ioread(u8 reg);
-- 
1.7.9.5

