From b2b65511ad56a90e2f206d99d348854d379a719b Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Thu, 25 Jun 2015 15:07:34 -0500
Subject: [PATCH 071/143] cpu/amd: Fix AMD Family 15h ECC initialization
 reliability issues

Change-Id: I7f009b655f8500aeb22981f7020f1db74cdd6925
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/cpu/amd/car/cache_as_ram.inc               |    4 +
 src/cpu/amd/family_10h-family_15h/init_cpus.c  |   16 ++++
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |   12 +--
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |    6 +-
 src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   21 ++++-
 src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c |  110 +++++++++++-------------
 src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c |    6 +-
 src/northbridge/amd/amdmct/mct_ddr3/s3utils.c  |   57 +++++++-----
 8 files changed, 136 insertions(+), 96 deletions(-)

diff --git a/src/cpu/amd/car/cache_as_ram.inc b/src/cpu/amd/car/cache_as_ram.inc
index 9edc41f..5db9224 100644
--- a/src/cpu/amd/car/cache_as_ram.inc
+++ b/src/cpu/amd/car/cache_as_ram.inc
@@ -362,12 +362,16 @@ clear_fixed_var_mtrr_out:
 	simplemask CacheSize, 0
 	wrmsr
 
+	jmp_if_fam15h(fam15_skip_dram_mtrr_setup)
+
 	/* Enable memory access for first MBs using top_mem. */
 	movl	$TOP_MEM, %ecx
 	xorl	%edx, %edx
 	movl	$(((CONFIG_RAMTOP) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax
 	wrmsr
 
+fam15_skip_dram_mtrr_setup:
+
 #if CONFIG_XIP_ROM_SIZE
 
 	/* Enable write base caching so we can do execute in place (XIP)
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 061bba2..d45671c 100644
--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
@@ -317,6 +317,22 @@ static void STOP_CAR_AND_CPU(uint8_t skip_sharedc_config, uint32_t apicid)
 		msr = rdmsr(BU_CFG2);
 		msr.lo &= ~(1 << ClLinesToNbDis);
 		wrmsr(BU_CFG2, msr);
+	} else {
+		/* Family 15h or later
+		 * DRAM setup is delayed on Fam15 in order to prevent
+		 * any DRAM access before ECC check bits are initialized.
+		 * Each core also needs to have its initial DRAM map initialized
+		 * before it is put to sleep, otherwise it will fail to wake
+		 * in ramstage.  To meet both of these goals, delay DRAM map
+		 * setup until the last possible moment, where speculative
+		 * memory access is highly unlikely before core halt...
+		 */
+		if (!skip_sharedc_config) {
+			/* Enable memory access for first MBs using top_mem */
+			msr.hi = 0;
+			msr.lo = (CONFIG_RAMTOP + TOP_MEM_MASK) & (~TOP_MEM_MASK);
+			wrmsr(TOP_MEM, msr);
+		}
 	}
 
 	disable_cache_as_ram(skip_sharedc_config);	// inline
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index 78bc8b3..dda997e 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -1458,8 +1458,7 @@ restartinit:
 		HTMemMapInit_D(pMCTstat, pDCTstatA);	/* Map local memory into system address space.*/
 		mctHookAfterHTMap();
 
-		printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
-		CPUMemTyping_D(pMCTstat, pDCTstatA);	/* Map dram into WB/UC CPU cacheability */
+		printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctHookAfterCPU\n");
 		mctHookAfterCPU();			/* Setup external northbridge(s) */
 
 		/* FIXME
@@ -1482,9 +1481,6 @@ restartinit:
 		printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
 		DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore);	/* Get Receiver Enable and DQS signal timing*/
 
-		printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
-		UMAMemTyping_D(pMCTstat, pDCTstatA);	/* Fix up for UMA sizing */
-
 		if (!allow_config_restore) {
 			printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
 			mct_OtherTiming(pMCTstat, pDCTstatA);
@@ -1505,6 +1501,12 @@ restartinit:
 			MCTMemClr_D(pMCTstat,pDCTstatA);
 		}
 
+		printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
+		CPUMemTyping_D(pMCTstat, pDCTstatA);	/* Map dram into WB/UC CPU cacheability */
+
+		printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
+		UMAMemTyping_D(pMCTstat, pDCTstatA);	/* Fix up for UMA sizing */
+
 		printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
 		for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
 			struct DCTStatStruc *pDCTstat;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
index 11555ae..ac8c934 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
@@ -725,8 +725,10 @@ struct amd_s3_persistent_mct_channel_data {
 	uint32_t f2x9cx30[12];
 	uint32_t f2x9cx40[12];
 
-	/* Other (1 dword) */
+	/* Other (3 dwords) */
 	uint32_t f3x58;
+	uint32_t f3x5c;
+	uint32_t f3x60;
 
 	/* Family 15h-specific registers (90 dwords) */
 	uint32_t f2x200;
@@ -785,7 +787,7 @@ struct amd_s3_persistent_mct_channel_data {
 	uint32_t f2x9cx0d0f0_0_f_31[9];		/* [lane] */
 	uint32_t f2x9cx0d0f8021;
 
-	/* TOTAL: 340 dwords */
+	/* TOTAL: 342 dwords */
 } __attribute__((packed));
 
 struct amd_s3_persistent_node_data {
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
index 740edae..b0ad54b 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
@@ -902,6 +902,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
 	uint32_t dev = pDCTstat->dev_dct;
 	uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
 
+#if DQS_TRAIN_DEBUG > 0
+	printk(BIOS_DEBUG, "%s: Start\n", __func__);
+#endif
+
+	mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
+	if (fam15h_freq_tab[mem_clk] == 0) {
+		pDCTstat->CH_MaxRdLat[dct] = 0x55;
+		return;
+	}
+
 	/* P is specified in PhyCLKs (1/2 MEMCLKs) */
 	for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
 		/* 2.10.5.8.5 (2) */
@@ -949,7 +959,6 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
 		t += 800;
 
 		/* 2.10.5.8.5 (10) */
-		mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
 		dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 4)));		/* Retrieve NbDid, NbFid */
 		nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) & 0x1)?2:1);
 		n = (((((uint64_t)p * 1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + ((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
@@ -964,8 +973,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
 		Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
 
 		/* Save result for later use */
-		pDCTstat->CH_MaxRdLat[dct] = n;
+		pDCTstat->CH_MaxRdLat[dct] = n - 1;
+
+#if DQS_TRAIN_DEBUG > 0
+	printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, pDCTstat->CH_MaxRdLat[dct]);
+#endif
 	}
+
+#if DQS_TRAIN_DEBUG > 0
+	printk(BIOS_DEBUG, "%s: Done\n", __func__);
+#endif
 }
 
 static void start_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
index a0482e8..d25ed53 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
@@ -92,13 +92,8 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 	uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED];
 	uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED];
 
-	uint8_t redirect_ecc_scrub = 0;
-
 	mctHookBeforeECC();
 
-	if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && mctGet_NVbits(NV_ECCRedir))
-		redirect_ecc_scrub = 1;
-
 	/* Construct these booleans, based on setup options, for easy handling
 	later in this procedure */
 	OB_NBECC = mctGet_NVbits(NV_NBECC);			/* MCA ECC (MCE) enable bit */
@@ -117,8 +112,11 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 		OF_ScrubCTL |= (u32) nvbits << 8;
 	}
 
+	nvbits = mctGet_NVbits(NV_L3BKScrub);
+	OF_ScrubCTL |= (nvbits & 0x1f) << 24;			/* L3Scrub = NV_L3BKScrub */
+
 	nvbits = mctGet_NVbits(NV_DramBKScrub);
-	OF_ScrubCTL |= nvbits;
+	OF_ScrubCTL |= nvbits;					/* DramScrub = NV_DramBKScrub */
 
 	/* Prevent lockups on DRAM errors during ECC init */
 	for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
@@ -133,6 +131,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 			dword &= ~(0x1 << 21);
 			Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
 
+			/* Clear MC4 error status */
+			pci_write_config32(pDCTstat->dev_nbmisc, 0x48, 0x0);
+			pci_write_config32(pDCTstat->dev_nbmisc, 0x4c, 0x0);
+
 			/* Clear the RAM before enabling ECC to prevent MCE-related lockups */
 			DCTMemClr_Init_D(pMCTstat, pDCTstat);
 			DCTMemClr_Sync_D(pMCTstat, pDCTstat);
@@ -170,6 +172,9 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 				if(LDramECC) {	/* if ECC is enabled on this dram */
 					if (OB_NBECC) {
 						mct_EnableDatIntlv_D(pMCTstat, pDCTstat);
+						val = Get_NB32(pDCTstat->dev_dct, 0x110);
+						val |= 1 << 5;	/* DctDatIntLv = 1 */
+						Set_NB32(pDCTstat->dev_dct, 0x110, val);
 						dev = pDCTstat->dev_nbmisc;
 						reg = 0x44;	/* MCA NB Configuration */
 						val = Get_NB32(dev, reg);
@@ -180,37 +185,16 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 						printk(BIOS_DEBUG, "  ECC enabled on node: %02x\n", Node);
 					}
 				}	/* this node has ECC enabled dram */
+
+				if (MemClrECC) {
+					DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+				}
 			} else {
 				LDramECC = 0;
 			}	/* Node has Dram */
-
-			if (MemClrECC) {
-				DCTMemClr_Sync_D(pMCTstat, pDCTstat);
-			}
-
-			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 */
 	}
 
-	/* Restore previous MCA error handling settings */
-	for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-		struct DCTStatStruc *pDCTstat;
-		pDCTstat = pDCTstatA + Node;
-
-		if (NodePresent_D(Node)) {
-			dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
-			dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
-			dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
-			Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
-		}
-	}
-
 	if(AllECC)
 		pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
 	else
@@ -229,19 +213,26 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 			/*WE/RE is checked because memory config may have been */
 			if((val & 3)==3) {	/* Node has dram populated */
 				if (isDramECCEn_D(pDCTstat)) {	/* if ECC is enabled on this dram */
-					if (is_fam15h()) {
-						/* Erratum 505 */
-						fam15h_switch_dct(pDCTstat->dev_map, 0);
-					}
 					dev = pDCTstat->dev_nbmisc;
 					val = curBase << 8;
 					if (OB_ECCRedir) {
-						val |= (1<<0);			/* enable redirection */
+						val |= (1 << 0);		/* Enable redirection */
 					}
 					Set_NB32(dev, 0x5c, val);		/* Dram Scrub Addr Low */
-					val = curBase>>24;
+					val = curBase >> 24;
 					Set_NB32(dev, 0x60, val);		/* Dram Scrub Addr High */
-					Set_NB32(dev, 0x58, OF_ScrubCTL);	/*Scrub Control */
+
+					/* Set scrub rate controls */
+					if (is_fam15h()) {
+						/* Erratum 505 */
+						fam15h_switch_dct(pDCTstat->dev_map, 0);
+					}
+					Set_NB32(dev, 0x58, OF_ScrubCTL);	/* Scrub Control */
+					if (is_fam15h()) {
+						fam15h_switch_dct(pDCTstat->dev_map, 1);	/* Erratum 505 */
+						Set_NB32(dev, 0x58, OF_ScrubCTL);		/* Scrub Control */
+						fam15h_switch_dct(pDCTstat->dev_map, 0);	/* Erratum 505 */
+					}
 
 					if (!is_fam15h()) {
 						/* Divisor should not be set deeper than
@@ -258,36 +249,31 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
 						}
 					}
 
-					if (is_fam15h()) {
-						uint8_t dct;
-
-						/* Disable training mode
-						 * See fam15EnableTrainingMode for the non-ECC training mode tear-down code
-						 */
-						for (dct = 0; dct < 2; dct++) {
-							/* NOTE: Reads use DCT 0 and writes use the current DCT per Erratum 505 */
-							dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, 0, 0x58);	/* Scrub Rate Control */
-							dword &= ~(0x1f << 24);					/* L3Scrub = NV_L3BKScrub */
-							dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
-							dword &= ~(0x1f);					/* DramScrub = NV_DramBKScrub */
-							dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f;
-							Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);	/* Scrub Rate Control */
-
-							dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);	/* DRAM Scrub Address Low */
-							dword &= ~(0x1);					/* ScrubReDirEn = redirect_ecc_scrub */
-							dword |= redirect_ecc_scrub & 0x1;
-							Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);	/* DRAM Scrub Address Low */
-
-							dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8);	/* L3 Control 1 */
-							dword &= ~(0x1 << 4);					/* L3ScrbRedirDis = 0 */
-							Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);	/* L3 Control 1 */
-						}
+					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);
 					}
 				}	/* this node has ECC enabled dram */
 			}	/*Node has Dram */
 		}	/*if Node present */
 	}
 
+	/* Restore previous MCA error handling settings */
+	for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+		struct DCTStatStruc *pDCTstat;
+		pDCTstat = pDCTstatA + Node;
+
+		if (NodePresent_D(Node)) {
+			dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
+			dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
+			dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
+			Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
+		}
+	}
+
 	if(mctGet_NVbits(NV_SyncOnUnEccEn))
 		setSyncOnUnEccEn_D(pMCTstat, pDCTstatA);
 
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
index 596fb23..abc8ae3 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
@@ -232,9 +232,9 @@ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat
 		Cache32bTOP = val;
 		pMCTstat->Sub4GCacheTop = val;
 
-	/*======================================================================
-	 * Clear variable MTRR values
-	 *======================================================================*/
+		/*======================================================================
+		 * Clear variable MTRR values
+		 *======================================================================*/
 		addr = 0x200;
 		lo = 0;
 		hi = lo;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
index fe89af1..b4a084c 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
@@ -89,6 +89,28 @@ static uint32_t read_config32_dct(device_t dev, uint8_t node, uint8_t dct, uint3
 	return pci_read_config32(dev, reg);
 }
 
+static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t reg, uint32_t value) {
+	if (is_fam15h()) {
+		uint32_t dword;
+#ifdef __PRE_RAM__
+		device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+#else
+		device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
+#endif
+
+		/* Select DCT */
+		dword = pci_read_config32(dev_fn1, 0x10c);
+		dword &= ~0x1;
+		dword |= (dct & 0x1);
+		pci_write_config32(dev_fn1, 0x10c, dword);
+	} else {
+		/* Apply offset */
+		reg += dct * 0x100;
+	}
+
+	pci_write_config32(dev, reg, value);
+}
+
 static uint32_t read_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg, uint32_t index)
 {
 	uint32_t dword;
@@ -489,29 +511,17 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da
 
 			/* Other */
 			/* ECC scrub rate control */
-			data->f3x58 = pci_read_config32(dev_fn3, 0x58);
+			data->f3x58 = read_config32_dct(dev_fn3, node, 0, 0x58);
+
+			/* ECC scrub location */
+			write_config32_dct(dev_fn3, node, 0, 0x58, 0x0);		/* Disable sequential scrub to work around non-atomic location read */
+			data->f3x5c = read_config32_dct(dev_fn3, node, 0, 0x5c);
+			data->f3x60 = read_config32_dct(dev_fn3, node, 0, 0x60);
+			write_config32_dct(dev_fn3, node, 0, 0x58, data->f3x58);	/* Re-enable sequential scrub */
 		}
 	}
 }
 #else
-static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t reg, uint32_t value) {
-	if (is_fam15h()) {
-		uint32_t dword;
-		device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-
-		/* Select DCT */
-		dword = pci_read_config32(dev_fn1, 0x10c);
-		dword &= ~0x1;
-		dword |= (dct & 0x1);
-		pci_write_config32(dev_fn1, 0x10c, dword);
-	} else {
-		/* Apply offset */
-		reg += dct * 0x100;
-	}
-
-	pci_write_config32(dev, reg, value);
-}
-
 static void write_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t dct, uint8_t nb_pstate, uint32_t reg, uint32_t value) {
 	uint32_t dword;
 	device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
@@ -613,8 +623,7 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
 				if (is_fam15h()) {
 					for (i=0; i<4; i++)
 						write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 0x210, data->f2x210[i]);
-				}
-				else {
+				} else {
 					write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x78, data->f2x78);
 				}
 
@@ -1060,8 +1069,12 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
 			if (!persistent_data->node[node].node_present)
 				continue;
 
+			/* ECC scrub location */
+			write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 0x5c, data->f3x5c);
+			write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 0x60, data->f3x60);
+
 			/* ECC scrub rate control */
-			pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x58, data->f3x58);
+			write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 0x58, data->f3x58);
 
 			if (is_fam15h())
 				/* Set LockDramCfg and CC6SaveEn */
-- 
1.7.9.5

