soc/intel/xeon_sp/cpx: set up cpus

Set up cpus:
* setup apic IDs.
* setup MSR to enable fast string, speed step, etc.
* Enable turbo

Signed-off-by: Jonathan Zhang <jonzhang@fb.com>
Signed-off-by: Reddy Chagam <anjaneya.chagam@intel.com>
Change-Id: I5765e98151f6ceebaabccc06db63d5911caf7ce8
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40112
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
diff --git a/src/soc/intel/xeon_sp/cpx/Makefile.inc b/src/soc/intel/xeon_sp/cpx/Makefile.inc
index 54004a5..aca8572 100644
--- a/src/soc/intel/xeon_sp/cpx/Makefile.inc
+++ b/src/soc/intel/xeon_sp/cpx/Makefile.inc
@@ -2,6 +2,7 @@
 
 ifeq ($(CONFIG_SOC_INTEL_COOPERLAKE_SP),y)
 
+subdirs-y += ../../../../cpu/intel/turbo
 subdirs-y += ../../../../cpu/x86/lapic
 subdirs-y += ../../../../cpu/x86/mtrr
 subdirs-y += ../../../../cpu/x86/tsc
diff --git a/src/soc/intel/xeon_sp/cpx/cpu.c b/src/soc/intel/xeon_sp/cpx/cpu.c
index 1c33218..e2724ce 100644
--- a/src/soc/intel/xeon_sp/cpx/cpu.c
+++ b/src/soc/intel/xeon_sp/cpx/cpu.c
@@ -2,18 +2,49 @@
 
 #include <acpi/acpigen.h>
 #include <acpi/acpi.h>
+#include <assert.h>
 #include <console/console.h>
 #include <cpu/cpu.h>
 #include <cpu/intel/microcode.h>
+#include <cpu/intel/turbo.h>
 #include <cpu/x86/lapic.h>
 #include <cpu/x86/mp.h>
 #include <cpu/x86/mtrr.h>
 #include <intelblocks/cpulib.h>
 #include <intelblocks/mp_init.h>
 #include <soc/cpu.h>
+#include <soc/msr.h>
+#include <soc/soc_util.h>
+#include "chip.h"
 
 static const void *microcode_patch;
 
+static const config_t *chip_config = NULL;
+
+static void xeon_configure_mca(void)
+{
+	msr_t msr;
+	struct cpuid_result cpuid_regs;
+
+	/*
+	 * Check feature flag in CPUID.(EAX=1):EDX[7]==1  MCE
+	 *                   and CPUID.(EAX=1):EDX[14]==1 MCA
+	 */
+	cpuid_regs = cpuid(1);
+	if ((cpuid_regs.edx & (1 << 7 | 1 << 14)) != (1 << 7 | 1 << 14))
+		return;
+
+	msr = rdmsr(IA32_MCG_CAP);
+	if (msr.lo & IA32_MCG_CAP_CTL_P_MASK) {
+		/* Enable all error logging */
+		msr.lo = msr.hi = 0xffffffff;
+		wrmsr(IA32_MCG_CTL, msr);
+	}
+
+	mca_configure();
+}
+
+
 void get_microcode_info(const void **microcode, int *parallel)
 {
 	*microcode = intel_mp_current_microcode();
@@ -27,10 +58,28 @@
 
 static void each_cpu_init(struct device *cpu)
 {
+	msr_t msr;
+
 	printk(BIOS_SPEW, "%s dev: %s, cpu: %d, apic_id: 0x%x\n",
 		__func__, dev_path(cpu), cpu_index(), cpu->path.apic.apic_id);
-
 	setup_lapic();
+
+	/* Enable Fast Strings */
+	msr = rdmsr(IA32_MISC_ENABLE);
+	msr.lo |= FAST_STRINGS_ENABLE_BIT;
+	wrmsr(IA32_MISC_ENABLE, msr);
+	/* Enable Turbo */
+	enable_turbo();
+
+	/* Enable speed step. */
+	if (get_turbo_state() == TURBO_ENABLED) {
+		msr = rdmsr(IA32_MISC_ENABLE);
+		msr.lo |= SPEED_STEP_ENABLE_BIT;
+		wrmsr(IA32_MISC_ENABLE, msr);
+	}
+
+	/* Clear out pending MCEs */
+	xeon_configure_mca();
 }
 
 static struct device_operations cpu_dev_ops = {
@@ -47,6 +96,33 @@
 	.id_table = cpu_table,
 };
 
+static void set_max_turbo_freq(void)
+{
+	msr_t msr, perf_ctl;
+
+	FUNC_ENTER();
+	perf_ctl.hi = 0;
+
+	/* Check for configurable TDP option */
+	if (get_turbo_state() == TURBO_ENABLED) {
+		msr = rdmsr(MSR_TURBO_RATIO_LIMIT);
+		perf_ctl.lo = (msr.lo & 0xff) << 8;
+	} else if (cpu_config_tdp_levels()) {
+		/* Set to nominal TDP ratio */
+		msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
+		perf_ctl.lo = (msr.lo & 0xff) << 8;
+	} else {
+		/* Platform Info bits 15:8 give max ratio */
+		msr = rdmsr(MSR_PLATFORM_INFO);
+		perf_ctl.lo = msr.lo & 0xff00;
+	}
+	wrmsr(IA32_PERF_CTL, perf_ctl);
+
+	printk(BIOS_DEBUG, "cpu: frequency set to %d\n",
+	       ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK);
+	FUNC_EXIT();
+}
+
 /*
  * Do essential initialization tasks before APs can be fired up
  */
@@ -72,10 +148,17 @@
 	return num_virts * CONFIG_MAX_SOCKET;
 }
 
+static void post_mp_init(void)
+{
+	/* Set Max Ratio */
+	set_max_turbo_freq();
+}
+
 static const struct mp_ops mp_ops = {
 	.pre_mp_init = pre_mp_init,
 	.get_cpu_count = get_thread_count,
-	.get_microcode_info = get_microcode_info
+	.get_microcode_info = get_microcode_info,
+	.post_mp_init = post_mp_init,
 };
 
 void cpx_init_cpus(struct device *dev)
@@ -89,4 +172,13 @@
 
 	if (mp_init_with_smm(dev->link_list, &mp_ops) < 0)
 		printk(BIOS_ERR, "MP initialization failure.\n");
+
+	/*
+	 * chip_config is used in cpu device callback. Other than cpu 0,
+	 * rest of the CPU devices do not have chip_info updated.
+	 */
+	chip_config = dev->chip_info;
+
+	/* update numa domain for all cpu devices */
+	xeonsp_init_cpu_config();
 }
diff --git a/src/soc/intel/xeon_sp/cpx/include/soc/cpu.h b/src/soc/intel/xeon_sp/cpx/include/soc/cpu.h
index 7f2f6cd..2d12699 100644
--- a/src/soc/intel/xeon_sp/cpx/include/soc/cpu.h
+++ b/src/soc/intel/xeon_sp/cpx/include/soc/cpu.h
@@ -7,6 +7,9 @@
 
 #define CPUID_COOPERLAKE_SP_A0			0x05065a
 
+/* CPU bus clock is fixed at 100MHz */
+#define CPU_BCLK 100
+
 void cpx_init_cpus(struct device *dev);
 
 #endif
diff --git a/src/soc/intel/xeon_sp/cpx/include/soc/msr.h b/src/soc/intel/xeon_sp/cpx/include/soc/msr.h
new file mode 100644
index 0000000..f9d59f1
--- /dev/null
+++ b/src/soc/intel/xeon_sp/cpx/include/soc/msr.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_MSR_H_
+#define _SOC_MSR_H_
+
+#include <intelblocks/msr.h>
+
+#define IA32_MCG_CAP                    0x179
+#define IA32_MCG_CAP_COUNT_MASK         0xff
+#define IA32_MCG_CAP_CTL_P_BIT          8
+#define IA32_MCG_CAP_CTL_P_MASK         (1 << IA32_MCG_CAP_CTL_P_BIT)
+
+#define IA32_MCG_CTL                    0x17b
+
+/* IA32_MISC_ENABLE bits */
+#define FAST_STRINGS_ENABLE_BIT         (1 << 0)
+#define SPEED_STEP_ENABLE_BIT           (1 << 16)
+#define MONIOR_ENABLE_BIT               (1 << 18)
+
+#define MSR_IA32_ENERGY_PERF_BIAS       0x1b0
+
+/* MSR_PKG_CST_CONFIG_CONTROL bits */
+#define MSR_PKG_CST_CONFIG_CONTROL       0xe2
+#define PKG_CSTATE_LIMIT_SHIFT           0 /* 0:3 */
+/* No package C-state limit. All C-States supported by the processor are available. */
+#define PKG_CSTATE_LIMIT_MASK            (0xf << PKG_CSTATE_LIMIT_SHIFT)
+#define PKG_CSTATE_NO_LIMIT              (0x7 << PKG_CSTATE_LIMIT_SHIFT)
+#define IO_MWAIT_REDIRECTION_SHIFT       10
+#define IO_MWAIT_REDIRECTION_ENABLE      (1 << IO_MWAIT_REDIRECTION_SHIFT)
+#define CFG_LOCK_SHIFT                   15
+#define CFG_LOCK_ENABLE                  (1 << CFG_LOCK_SHIFT)
+
+/* MSR_PMG_IO_CAPTURE_BASE bits */
+#define MSR_PMG_IO_CAPTURE_BASE          0xe4
+#define LVL_2_BASE_ADDRESS_SHIFT         0 /* 15:0 bits */
+#define LVL_2_BASE_ADDRESS               (0x0514 << LVL_2_BASE_ADDRESS_SHIFT)
+#define CST_RANGE_SHIFT                  16 /* 18:16 bits */
+#define CST_RANGE_MAX_C6                 (0x1 << CST_RANGE_SHIFT)
+
+/* MSR_POWER_CTL bits */
+#define MSR_POWER_CTL                            0x1fc
+#define BIDIR_PROCHOT_ENABLE_SHIFT               0
+#define BIDIR_PROCHOT_ENABLE                     (1 << BIDIR_PROCHOT_ENABLE_SHIFT)
+#define FAST_BRK_SNP_ENABLE_SHIFT                3
+#define FAST_BRK_SNP_ENABLE                      (1 << FAST_BRK_SNP_ENABLE_SHIFT)
+#define FAST_BRK_INT_ENABLE_SHIFT                4
+#define FAST_BRK_INT_ENABLE                      (1 << FAST_BRK_INT_ENABLE_SHIFT)
+#define PHOLD_CST_PREVENTION_INIT_SHIFT          6
+#define PHOLD_CST_PREVENTION_INIT_VALUE          (1 << PHOLD_CST_PREVENTION_INIT_SHIFT)
+#define ENERGY_PERF_BIAS_ACCESS_ENABLE_SHIFT     18
+#define ENERGY_PERF_BIAS_ACCESS_ENABLE           (1 << ENERGY_PERF_BIAS_ACCESS_ENABLE_SHIFT)
+#define PROCHOT_OUTPUT_DISABLE_SHIFT             21
+#define PROCHOT_OUTPUT_DISABLE                   (1 << PROCHOT_OUTPUT_DISABLE_SHIFT)
+#define PWR_PERF_TUNING_DYN_SWITCHING_SHIFT      24
+#define PWR_PERF_TUNING_DYN_SWITCHING_ENABLE     (1 << PWR_PERF_TUNING_DYN_SWITCHING_SHIFT)
+#define PROCHOT_LOCK_SHIFT                       27
+#define PROCHOT_LOCK_ENABLE                      (1 << PROCHOT_LOCK_SHIFT)
+#define LTR_IIO_DISABLE_SHIFT                    29
+#define LTR_IIO_DISABLE                          (1 << LTR_IIO_DISABLE_SHIFT)
+
+/* MSR_IA32_PERF_CTRL (0x199) bits */
+#define MSR_IA32_PERF_CTRL          0x199
+#define PSTATE_REQ_SHIFT            8 /* 8:14 bits */
+#define PSTATE_REQ_MASK             (0x7f << PSTATE_REQ_SHIFT)
+#define PSTATE_REQ_RATIO            (0xa << PSTATE_REQ_SHIFT)
+
+/* MSR_MISC_PWR_MGMT bits */
+#define MSR_MISC_PWR_MGMT            0x1aa
+#define HWP_ENUM_SHIFT               6
+#define HWP_ENUM_ENABLE              (1 << HWP_ENUM_SHIFT)
+#define HWP_EPP_SHIFT                12
+#define HWP_EPP_ENUM_ENABLE          (1 << HWP_EPP_SHIFT)
+#define LOCK_MISC_PWR_MGMT_MSR_SHIFT 13
+#define LOCK_MISC_PWR_MGMT_MSR       (1 << LOCK_MISC_PWR_MGMT_MSR_SHIFT)
+#define LOCK_THERM_INT_SHIFT         22
+#define LOCK_THERM_INT               (1 << LOCK_THERM_INT_SHIFT)
+
+/* MSR_TURBO_RATIO_LIMIT bits */
+#define MSR_TURBO_RATIO_LIMIT        0x1ad
+
+/* MSR_TURBO_RATIO_LIMIT_CORES (0x1ae) */
+#define MSR_TURBO_RATIO_LIMIT_CORES  0x1ae
+
+/* MSR_VR_CURRENT_CONFIG bits */
+#define MSR_VR_CURRENT_CONFIG        0x601
+#define CURRENT_LIMIT_LOCK_SHIFT     31
+#define CURRENT_LIMIT_LOCK           (0x1 << CURRENT_LIMIT_LOCK_SHIFT)
+
+/* MSR_TURBO_ACTIVATION_RATIO bits */
+#define MSR_TURBO_ACTIVATION_RATIO   0x64c
+#define MAX_NON_TURBO_RATIO_SHIFT    0
+#define MAX_NON_TURBO_RATIO          (0xff << MAX_NON_TURBO_RATIO_SHIFT)
+
+/* MSR_ENERGY_PERF_BIAS_CONFIG bits */
+#define MSR_ENERGY_PERF_BIAS_CONFIG  0xa01
+#define EPB_ENERGY_POLICY_SHIFT      3
+#define EPB_ENERGY_POLICY_MASK       (0xf << EPB_ENERGY_POLICY_SHIFT)
+
+#endif /* _SOC_MSR_H_ */
diff --git a/src/soc/intel/xeon_sp/cpx/include/soc/soc_util.h b/src/soc/intel/xeon_sp/cpx/include/soc/soc_util.h
index d8b038c..679ad4a 100644
--- a/src/soc/intel/xeon_sp/cpx/include/soc/soc_util.h
+++ b/src/soc/intel/xeon_sp/cpx/include/soc/soc_util.h
@@ -16,10 +16,24 @@
 	printk(BIOS_SPEW, "%s:%s:%d: EXIT (dev: %s)\n", __FILE__, \
 		__func__, __LINE__, dev_path(dev))
 
+#define FUNC_ENTER() \
+	printk(BIOS_SPEW, "%s:%s:%d: ENTER\n", __FILE__, __func__, __LINE__)
+
+#define FUNC_EXIT() \
+	printk(BIOS_SPEW, "%s:%s:%d: EXIT\n", __FILE__, __func__, __LINE__)
+
 struct iiostack_resource {
 	uint8_t     no_of_stacks;
 	STACK_RES   res[MAX_SOCKET * MAX_LOGIC_IIO_STACK];
 };
 
 uint8_t get_iiostack_info(struct iiostack_resource *info);
+
+void xeonsp_init_cpu_config(void);
+const IIO_UDS *get_iio_uds(void);
+void get_core_thread_bits(uint32_t *core_bits, uint32_t *thread_bits);
+void get_cpu_info_from_apicid(uint32_t apicid, uint32_t core_bits, uint32_t thread_bits,
+	uint8_t *package, uint8_t *core, uint8_t *thread);
+unsigned int xeon_sp_get_cpu_count(void);
+
 #endif /* _SOC_UTIL_H_ */
diff --git a/src/soc/intel/xeon_sp/cpx/soc_util.c b/src/soc/intel/xeon_sp/cpx/soc_util.c
index 8548615..2d10657 100644
--- a/src/soc/intel/xeon_sp/cpx/soc_util.c
+++ b/src/soc/intel/xeon_sp/cpx/soc_util.c
@@ -1,10 +1,135 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <assert.h>
+#include <commonlib/sort.h>
+#include <device/device.h>
+#include <intelblocks/cpulib.h>
+#include <soc/cpu.h>
 #include <soc/soc_util.h>
 #include <stdlib.h>
 #include <string.h>
 
+void get_cpu_info_from_apicid(uint32_t apicid, uint32_t core_bits, uint32_t thread_bits,
+	uint8_t *package, uint8_t *core, uint8_t *thread)
+{
+	if (package != NULL)
+		*package = (apicid >> (thread_bits + core_bits));
+	if (core != NULL)
+		*core = (uint32_t)((apicid >> thread_bits) & ~((~0) << core_bits));
+	if (thread != NULL)
+		*thread = (uint32_t)(apicid & ~((~0) << thread_bits));
+}
+
+void get_core_thread_bits(uint32_t *core_bits, uint32_t *thread_bits)
+{
+	register int ecx;
+	struct cpuid_result cpuid_regs;
+
+	/* get max index of CPUID */
+	cpuid_regs = cpuid(0);
+	assert(cpuid_regs.eax >= 0xb); /* cpuid_regs.eax is max input value for cpuid */
+
+	*thread_bits = *core_bits = 0;
+	ecx = 0;
+	while (1) {
+		cpuid_regs = cpuid_ext(0xb, ecx);
+		if (ecx == 0) {
+			*thread_bits = (cpuid_regs.eax & 0x1f);
+		} else {
+			*core_bits = (cpuid_regs.eax & 0x1f) - *thread_bits;
+			break;
+		}
+		ecx++;
+	}
+}
+
+const IIO_UDS *get_iio_uds(void)
+{
+	size_t hob_size;
+	const IIO_UDS *hob;
+	const uint8_t fsp_hob_iio_universal_data_guid[16] = FSP_HOB_IIO_UNIVERSAL_DATA_GUID;
+
+	hob = fsp_find_extension_hob_by_guid(fsp_hob_iio_universal_data_guid, &hob_size);
+	assert(hob != NULL && hob_size != 0);
+	return hob;
+}
+
+unsigned int xeon_sp_get_cpu_count(void)
+{
+	return get_iio_uds()->SystemStatus.numCpus;
+}
+
+void xeonsp_init_cpu_config(void)
+{
+	struct device *dev;
+	int apic_ids[CONFIG_MAX_CPUS] = {0}, apic_ids_by_thread[CONFIG_MAX_CPUS] = {0};
+	int  num_apics = 0;
+	uint32_t core_bits, thread_bits;
+	unsigned int core_count, thread_count;
+	unsigned int num_cpus;
+
+	/*
+	 * sort APIC ids in asending order to identify apicid ranges for
+	 * each numa domain
+	 */
+	for (dev = all_devices; dev; dev = dev->next) {
+		if ((dev->path.type != DEVICE_PATH_APIC) ||
+			(dev->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) {
+			continue;
+		}
+		if (!dev->enabled)
+			continue;
+		if (num_apics >= ARRAY_SIZE(apic_ids))
+			break;
+	  apic_ids[num_apics++] = dev->path.apic.apic_id;
+	}
+	if (num_apics > 1)
+		bubblesort(apic_ids, num_apics, NUM_ASCENDING);
+
+	/* Here num_cpus is the number of processors */
+	/* The FSP HOB parameter has it named as num_cpus */
+	num_cpus = xeon_sp_get_cpu_count();
+	cpu_read_topology(&core_count, &thread_count);
+	assert(num_apics == (num_cpus * thread_count));
+
+	/* sort them by thread i.e., all cores with thread 0 and then thread 1 */
+	int index = 0;
+	for (int id = 0; id < num_apics; ++id) {
+		int apic_id = apic_ids[id];
+		if (apic_id & 0x1) { /* 2nd thread */
+			apic_ids_by_thread[index + (num_apics/2) - 1] = apic_id;
+		} else { /* 1st thread */
+			apic_ids_by_thread[index++] = apic_id;
+		}
+	}
+
+
+	/* update apic_id, node_id in sorted order */
+	num_apics = 0;
+	get_core_thread_bits(&core_bits, &thread_bits);
+	for (dev = all_devices; dev; dev = dev->next) {
+		uint8_t package;
+
+		if ((dev->path.type != DEVICE_PATH_APIC) ||
+			(dev->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) {
+			continue;
+		}
+		if (!dev->enabled)
+			continue;
+		if (num_apics >= ARRAY_SIZE(apic_ids))
+			break;
+		dev->path.apic.apic_id = apic_ids_by_thread[num_apics];
+		get_cpu_info_from_apicid(dev->path.apic.apic_id, core_bits, thread_bits,
+			&package, NULL, NULL);
+		dev->path.apic.node_id = package;
+		printk(BIOS_DEBUG, "CPU %d apic_id: 0x%x (%d), node_id: 0x%x\n",
+			num_apics, dev->path.apic.apic_id,
+			dev->path.apic.apic_id, dev->path.apic.node_id);
+
+		++num_apics;
+	}
+}
+
 uint8_t get_iiostack_info(struct iiostack_resource *info)
 {
 	size_t hob_size;