aboutsummaryrefslogtreecommitdiff
path: root/resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch')
-rw-r--r--resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch1307
1 files changed, 1307 insertions, 0 deletions
diff --git a/resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch b/resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch
new file mode 100644
index 00000000..026d8430
--- /dev/null
+++ b/resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch
@@ -0,0 +1,1307 @@
+From 674911f61b4b32b0707962fa6a5a7e50811f721a Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <tpearson@raptorengineeringinc.com>
+Date: Mon, 8 Jun 2015 19:35:06 -0500
+Subject: [PATCH 046/139] 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 | 80 ++++++++++
+ 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 | 78 ++++++++++
+ 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 | 4 +
+ src/southbridge/amd/sb700/sb700.h | 7 +-
+ src/southbridge/amd/sb700/sm.c | 5 +-
+ src/southbridge/amd/sb800/fadt.c | 3 +
+ src/southbridge/amd/sb800/sb800.h | 8 +-
+ 20 files changed, 539 insertions(+), 200 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 2e26645..0e870e3 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..818431b 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,8 @@ void cpuSetAMDMSR(uint8_t node_id)
+ u8 i;
+ u32 platform;
+ uint64_t revision;
++ uint8_t nvram;
++ uint8_t enable_c_states;
+
+ printk(BIOS_DEBUG, "cpuSetAMDMSR ");
+
+@@ -936,6 +946,42 @@ void cpuSetAMDMSR(uint8_t node_id)
+ wrmsr(FP_CFG, msr);
+ }
+
++#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
++ 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 +996,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 +1055,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..4acd66c 100644
+--- a/src/northbridge/amd/amdfam10/link_control.c
++++ b/src/northbridge/amd/amdfam10/link_control.c
+@@ -49,15 +49,93 @@ static inline uint8_t is_fam15h(void)
+
+ static void nb_control_init(struct device *dev)
+ {
++ uint8_t nvram;
++ 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)
++ 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");
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c
+index 51eac77..3fc31c0 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..6b1924f 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,7 @@ 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;
+
++ 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 a4b78d0..81e3046 100644
+--- a/src/southbridge/amd/sb700/sm.c
++++ b/src/southbridge/amd/sb700/sm.c
+@@ -114,7 +114,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..5250e20 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,7 @@ 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;
+
++ 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.9.1
+