nb/intel/sandybridge/raminit: Add ECC debug code

* Add ECC test code when DEBUG_RAM_SETUP is enabled
* Move ECC scrubbing after set_scrambling_seed() to be able to observe
  what has been cleared in the test routine. If clearing happens
  before set_scrambling_seed the data is XORed with a different PRN.
  Data read from memory will look random instead of all zeros.
* ECC scrubbing must happen after dram_dimm_set_mapping()
  The ECC logic is set to "normal mode" in dram_dimm_set_mapping(). In
  normal mode the ECC bits are calculated and stored on write
  transactions.
* Move method out of try_init_dram_ddr3().
  This satisfies point 2 and point 3 of the list above.

Change-Id: I76174ec962c9b0bb72852897586eb95d896d301e
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40946
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c
index 2728037..06b4d1e 100644
--- a/src/northbridge/intel/sandybridge/raminit.c
+++ b/src/northbridge/intel/sandybridge/raminit.c
@@ -416,10 +416,41 @@
 
 	set_scrambling_seed(&ctrl);
 
+	if (!s3resume && ctrl.ecc_enabled)
+		channel_scrub(&ctrl);
+
 	set_normal_operation(&ctrl);
 
 	final_registers(&ctrl);
 
+	/* can't do this earlier because it needs to be done in normal operation */
+	if (CONFIG(DEBUG_RAM_SETUP) && !s3resume && ctrl.ecc_enabled) {
+		uint32_t i, tseg = pci_read_config32(HOST_BRIDGE, TSEGMB);
+
+		printk(BIOS_INFO, "RAMINIT: ECC scrub test on first channel up to 0x%x\n",
+		       tseg);
+
+		/*
+		 * This test helps to debug the ECC scrubbing.
+		 * It likely tests every channel/rank, as rank interleave and enhanced
+		 * interleave are enabled, but there's no guarantee for it.
+		 */
+
+		/* Skip first MB to avoid special case for A-seg and test up to TSEG */
+		for (i = 1; i < tseg >> 20; i++) {
+			for (int j = 0; j < 1 * MiB; j += 4096) {
+				uintptr_t addr = i * MiB + j;
+				if (read32((u32 *)addr) == 0)
+					continue;
+
+				printk(BIOS_ERR, "RAMINIT: ECC scrub: DRAM not cleared at"
+				       " addr 0x%lx\n", addr);
+				break;
+			}
+		}
+		printk(BIOS_INFO, "RAMINIT: ECC scrub test done.\n");
+	}
+
 	/* Zone config */
 	dram_zones(&ctrl, 0);
 
diff --git a/src/northbridge/intel/sandybridge/raminit_native.c b/src/northbridge/intel/sandybridge/raminit_native.c
index 62715a1..c23a5ac 100644
--- a/src/northbridge/intel/sandybridge/raminit_native.c
+++ b/src/northbridge/intel/sandybridge/raminit_native.c
@@ -687,9 +687,6 @@
 		err = channel_test(ctrl);
 		if (err)
 			return err;
-
-		if (ctrl->ecc_enabled)
-			channel_scrub(ctrl);
 	}
 
 	/* Set MAD-DIMM registers */