haswell/lynxpoint: Add native early ME init

Implement native early ME init for Lynx Point. This is only needed when
MRC.bin is not used.

Change-Id: If416e2078f139f26b4742c564b70e018725bf003
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/64178
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
index 0938e02..6a00254 100644
--- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
@@ -1,18 +1,24 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
 #include <console/console.h>
+#include <delay.h>
 #include <northbridge/intel/haswell/haswell.h>
 #include <northbridge/intel/haswell/raminit.h>
+#include <southbridge/intel/lynxpoint/me.h>
 #include <types.h>
 
 static bool early_init_native(int s3resume)
 {
 	printk(BIOS_DEBUG, "Starting native platform initialisation\n");
 
+	intel_early_me_init();
+	/** TODO: CPU replacement check must be skipped in warm boots and S3 resumes **/
+	const bool cpu_replaced = !s3resume && intel_early_me_cpu_replacement_check();
+
 	if (!CONFIG(INTEL_LYNXPOINT_LP))
 		dmi_early_init();
 
-	return false;
+	return cpu_replaced;
 }
 
 void perform_raminit(const int s3resume)
@@ -25,6 +31,15 @@
 
 	(void)cpu_replaced;
 
+	/** TODO: Move after raminit */
+	if (intel_early_me_uma_size() > 0) {
+		/** TODO: Update status once raminit is implemented **/
+		uint8_t me_status = ME_INIT_STATUS_ERROR;
+		intel_early_me_init_done(me_status);
+	}
+
+	intel_early_me_status();
+
 	/** TODO: Implement the required magic **/
 	die("NATIVE RAMINIT: More Magic (tm) required.\n");
 }
diff --git a/src/southbridge/intel/lynxpoint/early_me.c b/src/southbridge/intel/lynxpoint/early_me.c
index 947c570..07013c5 100644
--- a/src/southbridge/intel/lynxpoint/early_me.c
+++ b/src/southbridge/intel/lynxpoint/early_me.c
@@ -1,11 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <arch/io.h>
+#include <cf9_reset.h>
 #include <device/pci_ops.h>
 #include <console/console.h>
 #include <delay.h>
 #include <halt.h>
-
+#include <timer.h>
 #include "me.h"
 #include "pch.h"
 
@@ -60,6 +61,33 @@
 	return 0;
 }
 
+bool intel_early_me_cpu_replacement_check(void)
+{
+	printk(BIOS_DEBUG, "ME: Checking whether CPU was replaced... ");
+
+	struct stopwatch timer;
+	stopwatch_init_msecs_expire(&timer, 50);
+
+	union me_hfs2 hfs2;
+	do {
+		hfs2.raw = pci_read_config32(PCH_ME_DEV, PCI_ME_HFS2);
+		if (stopwatch_expired(&timer)) {
+			/* Assume CPU was replaced just in case */
+			printk(BIOS_DEBUG, "timed out, assuming CPU was replaced\n");
+			return true;
+		}
+		udelay(ME_DELAY);
+	} while (!hfs2.cpu_replaced_valid);
+
+	if (hfs2.warm_reset_request) {
+		printk(BIOS_DEBUG, "warm reset needed for dynamic fusing\n");
+		system_reset();
+	}
+
+	printk(BIOS_DEBUG, "%sreplaced\n", hfs2.cpu_replaced_sts ? "" : "not ");
+	return hfs2.cpu_replaced_sts;
+}
+
 int intel_early_me_uma_size(void)
 {
 	union me_uma uma = { .raw = pci_read_config32(PCH_ME_DEV, PCI_ME_UMA) };
diff --git a/src/southbridge/intel/lynxpoint/me.h b/src/southbridge/intel/lynxpoint/me.h
index fe8b026..6990322 100644
--- a/src/southbridge/intel/lynxpoint/me.h
+++ b/src/southbridge/intel/lynxpoint/me.h
@@ -177,14 +177,16 @@
 union me_hfs2 {
 	struct __packed {
 		u32 bist_in_progress: 1;
-		u32 reserved1: 2;
+		u32 icc_prog_sts: 2;
 		u32 invoke_mebx: 1;
 		u32 cpu_replaced_sts: 1;
 		u32 mbp_rdy: 1;
 		u32 mfs_failure: 1;
 		u32 warm_reset_request: 1;
 		u32 cpu_replaced_valid: 1;
-		u32 reserved2: 4;
+		u32 reserved: 2;
+		u32 fw_upd_ipu: 1;
+		u32 reserved2: 1;
 		u32 mbp_cleared: 1;
 		u32 reserved3: 2;
 		u32 current_state: 8;
@@ -338,6 +340,7 @@
 
 void intel_early_me_status(void);
 int intel_early_me_init(void);
+bool intel_early_me_cpu_replacement_check(void);
 int intel_early_me_uma_size(void);
 int intel_early_me_init_done(u8 status);