diff options
author | Jonathan Zhang <jonzhang@meta.com> | 2023-01-25 11:37:27 -0800 |
---|---|---|
committer | Lean Sheng Tan <sheng.tan@9elements.com> | 2023-03-19 09:53:02 +0000 |
commit | 3ed903fda9cb9b7237067f301d1efdb297a05a24 (patch) | |
tree | d5dd7beda731aea7ddbd6a80c7c151b5d1d38107 /src/soc/intel/xeon_sp/spr | |
parent | 15fc45982b9b8303978ab87ea6c93d423834e6e8 (diff) |
soc/intel/xeon_sp/spr: Add Sapphire Rapids ramstage code
It implements SPR ramstage including silicon initialization, MSR
programming, MP init and certain registers locking before booting
to payload.
Change-Id: I128fdc6e58c49fb5abf911d6ffa91e7411f6d1e2
Signed-off-by: Jonathan Zhang <jonzhang@meta.com>
Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/72443
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
Diffstat (limited to 'src/soc/intel/xeon_sp/spr')
-rw-r--r-- | src/soc/intel/xeon_sp/spr/Makefile.inc | 21 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/chip.c | 232 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/chip.h | 96 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/chipset.cb | 4 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/cpu.c | 281 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/crashlog.c | 28 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/numa.c | 117 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/ramstage.c | 30 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/reset.c | 17 | ||||
-rw-r--r-- | src/soc/intel/xeon_sp/spr/xhci.c | 42 |
10 files changed, 865 insertions, 3 deletions
diff --git a/src/soc/intel/xeon_sp/spr/Makefile.inc b/src/soc/intel/xeon_sp/spr/Makefile.inc new file mode 100644 index 0000000000..2ead6538e5 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/Makefile.inc @@ -0,0 +1,21 @@ +## SPDX-License-Identifier: GPL-2.0-only + +ifeq ($(CONFIG_SOC_INTEL_SAPPHIRERAPIDS_SP),y) + +subdirs-y += ../../../../cpu/intel/turbo +subdirs-y += ../../../../cpu/x86/lapic +subdirs-y += ../../../../cpu/x86/mtrr +subdirs-y += ../../../../cpu/x86/tsc +subdirs-y += ../../../../cpu/intel/microcode + +romstage-y += romstage.c soc_util.c ddr.c +romstage-$(CONFIG_DISPLAY_HOBS) += hob_display.c +romstage-$(CONFIG_DISPLAY_UPD_DATA) += upd_display.c + +ramstage-y += chip.c cpu.c soc_util.c ramstage.c soc_acpi.c xhci.c numa.c reset.c +ramstage-y += crashlog.c +ramstage-$(CONFIG_DISPLAY_HOBS) += hob_display.c +ramstage-$(CONFIG_DISPLAY_UPD_DATA) += upd_display.c +CPPFLAGS_common += -I$(src)/soc/intel/xeon_sp/spr/include -I$(src)/soc/intel/xeon_sp/spr + +endif ## CONFIG_SOC_INTEL_SAPPHIRERAPIDS_SP diff --git a/src/soc/intel/xeon_sp/spr/chip.c b/src/soc/intel/xeon_sp/spr/chip.c new file mode 100644 index 0000000000..16e059b34a --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/chip.c @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/ioapic.h> +#include <console/console.h> +#include <console/debug.h> +#include <cpu/x86/lapic.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pciexp.h> +#include <intelblocks/gpio.h> +#include <intelblocks/lpc_lib.h> +#include <intelblocks/p2sb.h> +#include <intelblocks/pcr.h> +#include <intelblocks/tco.h> +#include <soc/acpi.h> +#include <soc/chip_common.h> +#include <soc/crashlog.h> +#include <soc/numa.h> +#include <soc/p2sb.h> +#include <soc/pch.h> +#include <soc/soc_pch.h> +#include <soc/pci_devs.h> +#include <soc/ramstage.h> +#include <soc/soc_util.h> +#include <soc/util.h> +#include <soc/xhci.h> + +__weak void mainboard_silicon_init_params(FSPS_UPD *params) +{ + +} + +/* UPD parameters to be initialized before SiliconInit */ +void platform_fsp_silicon_init_params_cb(FSPS_UPD *silupd) +{ + mainboard_silicon_init_params(silupd); +} + +#if CONFIG(HAVE_ACPI_TABLES) +const char *soc_acpi_name(const struct device *dev); +const char *soc_acpi_name(const struct device *dev) +{ + if (dev->path.type == DEVICE_PATH_DOMAIN) + return "PC00"; + return NULL; +} +#endif + +static struct device_operations pci_domain_ops = { + .read_resources = &pci_domain_read_resources, + .set_resources = &xeonsp_pci_domain_set_resources, + .scan_bus = &xeonsp_pci_domain_scan_bus, +#if CONFIG(HAVE_ACPI_TABLES) + .write_acpi_tables = &northbridge_write_acpi_tables, + .acpi_name = soc_acpi_name +#endif +}; + +static struct device_operations cpu_bus_ops = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + .init = mp_cpu_bus_init, + .acpi_fill_ssdt = generate_cpu_entries, +}; + +struct pci_operations soc_pci_ops = { + .set_subsystem = pci_dev_set_subsystem, +}; + +static void chip_enable_dev(struct device *dev) +{ + /* Set the operations if it is a special bus type */ + if (dev->path.type == DEVICE_PATH_DOMAIN) { + dev->ops = &pci_domain_ops; + attach_iio_stacks(dev); + } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) { + dev->ops = &cpu_bus_ops; + } else if (dev->path.type == DEVICE_PATH_GPIO) { + block_gpio_enable(dev); + } +} + +static void pcu_pci_or_config32(u8 bus, u8 func, u32 reg, u32 orval) +{ + u32 data; + const uint32_t pcie_offset = PCI_DEV(bus, PCU_DEV, func); + + data = pci_s_read_config32(pcie_offset, reg); + data |= orval; + pci_s_write_config32(pcie_offset, reg, data); +} + +static void set_pcu_locks(void) +{ + for (uint32_t socket = 0; socket < soc_get_num_cpus(); ++socket) { + const uint32_t bus = get_ubox_busno(socket, UNCORE_BUS_1); + + /* configure PCU_CR0_FUN csrs */ + pcu_pci_or_config32(bus, PCU_CR0_FUN, PCU_CR0_P_STATE_LIMITS, + P_STATE_LIMITS_LOCK); + pcu_pci_or_config32(bus, PCU_CR0_FUN, PCU_CR0_PACKAGE_RAPL_LIMIT_UPR, + PKG_PWR_LIM_LOCK_UPR); + pcu_pci_or_config32(bus, PCU_CR0_FUN, PCU_CR0_TURBO_ACTIVATION_RATIO, + TURBO_ACTIVATION_RATIO_LOCK); + + /* configure PCU_CR2_FUN csrs */ + pcu_pci_or_config32(bus, PCU_CR2_FUN, PCU_CR2_DRAM_POWER_INFO_UPR, + DRAM_POWER_INFO_LOCK_UPR); + pcu_pci_or_config32(bus, PCU_CR2_FUN, PCU_CR2_DRAM_PLANE_POWER_LIMIT_UPR, + PP_PWR_LIM_LOCK_UPR); + + /* configure PCU_CR3_FUN csrs */ + pcu_pci_or_config32(bus, PCU_CR3_FUN, PCU_CR3_CONFIG_TDP_CONTROL, TDP_LOCK); + + /* configure PCU_CR6_FUN csrs */ + pcu_pci_or_config32(bus, PCU_CR6_FUN, PCU_CR6_PLATFORM_RAPL_LIMIT_CFG_UPR, + PLT_PWR_LIM_LOCK_UPR); + pcu_pci_or_config32(bus, PCU_CR6_FUN, PCU_CR6_PLATFORM_POWER_INFO_CFG_UPR, + PLT_PWR_INFO_LOCK_UPR); + } +} + +static void chip_final(void *data) +{ + /* Lock SBI */ + pci_or_config32(PCH_DEV_P2SB, P2SBC, SBILOCK); + + /* LOCK PAM */ + pci_or_config32(pcidev_path_on_root(PCI_DEVFN(0, 0)), 0x80, 1 << 0); + + set_pcu_locks(); + tco_lockdown(); + + p2sb_hide(); + + /* Accessing xHCI CSR needs to be done after PCI enumeration. */ + lock_oc_cfg(false); + mainboard_override_usb_oc(); + lock_oc_cfg(true); + /* Disable CPU Crashlog to avoid conflict between CPU Crashlog and BMC ACD. */ + disable_cpu_crashlog(); + + set_bios_init_completion(); +} + +static void chip_init(void *data) +{ + printk(BIOS_DEBUG, "coreboot: calling fsp_silicon_init\n"); + fsp_silicon_init(); + override_hpet_ioapic_bdf(); + pch_enable_ioapic(); + pch_lock_dmictl(); + p2sb_unhide(); + lock_gpio(false); + mainboard_override_fsp_gpio(); + lock_gpio(true); +} + +struct chip_operations soc_intel_xeon_sp_spr_ops = { + CHIP_NAME("Intel SapphireRapids-SP").enable_dev = chip_enable_dev, + .init = chip_init, + .final = chip_final, +}; + +void lock_gpio(bool lock) +{ + if (lock) { + pcr_write32(gpio_get_pad_portid(GPPC_B0), PAD_CFG_LOCK_B, 0xffffffff); + pcr_write32(gpio_get_pad_portid(GPP_D0), PAD_CFG_LOCK_D, 0xffffffff); + } else { + pcr_write32(gpio_get_pad_portid(GPPC_B0), PAD_CFG_LOCK_B, 0); + pcr_write32(gpio_get_pad_portid(GPP_D0), PAD_CFG_LOCK_D, 0); + } +} + +/* Root Complex Event Collector */ +static void rcec_init(struct device *dev) +{ + /* Set up RCEC EA extended capability, section 7.9.10 of PCIe 5.0 spec */ + const unsigned int rcecea_cap = + pciexp_find_extended_cap(dev, PCIE_EXT_CAP_RCECEA_ID, 0); + if (!rcecea_cap) + return; + + pci_devfn_t ecrc_bdf = PCI_BDF(dev); + uint32_t ecrc_bus = (ecrc_bdf >> 20) & 0xFFF; + uint32_t ecrc_dev = (ecrc_bdf >> 15) & 0x1F; + + /* + * Find all CXL devices, and match them with RCEC. + * With CXL 1.1, the bus# of CXL device (RCiEP) is 1 bigger than + * the bus# of RCEC. + */ + uint32_t ep_bus; + uint8_t i; + for (i = 0; i < pds.num_pds; i++) { + if (pds.pds[i].pd_type == PD_TYPE_PROCESSOR) + continue; + ep_bus = pds.pds[i].device_handle >> 20; + if (ep_bus == ecrc_bus + 1) + break; + } + if (i == pds.num_pds) + return; + + printk(BIOS_DEBUG, "ep_bus: %x, ecrc_dev: %x\n", ep_bus, ecrc_dev); + u32 rcecea_bitmap = 0x1 << ecrc_dev; + u32 rcecea_busnum = (ep_bus << 8) | (ep_bus << 16); + pci_write_config32(dev, rcecea_cap + PCI_RCECEA_BITMAP, rcecea_bitmap); + pci_write_config32(dev, rcecea_cap + PCI_RCECEA_BUSNUM, rcecea_busnum); +} + +#define SPR_IEH 0x0b23 + +static const unsigned short rcec_ids[] = { + SPR_IEH, + 0 +}; + +static struct device_operations rcec_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = rcec_init, + .ops_pci = &soc_pci_ops, +}; + +static const struct pci_driver rcec_driver __pci_driver = { + .ops = &rcec_ops, + .vendor = PCI_VID_INTEL, + .devices = rcec_ids, +}; diff --git a/src/soc/intel/xeon_sp/spr/chip.h b/src/soc/intel/xeon_sp/spr/chip.h new file mode 100644 index 0000000000..c0e990b473 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/chip.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_CHIP_H_ +#define _SOC_CHIP_H_ + +#include <gpio.h> +#include <intelblocks/cfg.h> +#include <soc/acpi.h> +#include <soc/irq.h> +#include <stdint.h> + +#define MAX_PCH_PCIE_PORT 20 + +/** + UPD_PCH_PCIE_PORT: + ForceEnable - Enable/Disable PCH PCIe port + PortLinkSpeed - Port Link Speed. Use PCIE_LINK_SPEED to set +**/ +struct pch_pcie_port { + uint8_t ForceEnable; + uint8_t PortLinkSpeed; +}; + +struct soc_intel_xeon_sp_spr_config { + /* Common struct containing soc config data required by common code */ + struct soc_intel_common_config common_soc_config; + + /* Struct for configuring PCH PCIe port */ + struct pch_pcie_port pch_pci_port[MAX_PCH_PCIE_PORT]; + + /** + * Interrupt Routing configuration + * If bit7 is 1, the interrupt is disabled. + */ + uint8_t pirqa_routing; + uint8_t pirqb_routing; + uint8_t pirqc_routing; + uint8_t pirqd_routing; + uint8_t pirqe_routing; + uint8_t pirqf_routing; + uint8_t pirqg_routing; + uint8_t pirqh_routing; + + /** + * Device Interrupt Routing configuration + * Interrupt Pin x Route. + * 0h = PIRQA# + * 1h = PIRQB# + * 2h = PIRQC# + * 3h = PIRQD# + * 4h = PIRQE# + * 5h = PIRQF# + * 6h = PIRQG# + * 7h = PIRQH# + */ + uint16_t ir00_routing; + uint16_t ir01_routing; + uint16_t ir02_routing; + uint16_t ir03_routing; + uint16_t ir04_routing; + + /** + * Device Interrupt Polarity Control + * ipc0 - IRQ-00-31 - 1: Active low to IOAPIC, 0: Active high to IOAPIC + * ipc1 - IRQ-32-63 - 1: Active low to IOAPIC, 0: Active high to IOAPIC + * ipc2 - IRQ-64-95 - 1: Active low to IOAPIC, 0: Active high to IOAPIC + * ipc3 - IRQ-96-119 - 1: Active low to IOAPIC, 0: Active high to IOAPIC + */ + uint32_t ipc0; + uint32_t ipc1; + uint32_t ipc2; + uint32_t ipc3; + + uint64_t turbo_ratio_limit; + uint64_t turbo_ratio_limit_cores; + + uint32_t pstate_req_ratio; + + uint8_t vtd_support; + uint8_t x2apic; + + /* Generic IO decode ranges */ + uint32_t gen1_dec; + uint32_t gen2_dec; + uint32_t gen3_dec; + uint32_t gen4_dec; + + /* TCC activation offset */ + uint32_t tcc_offset; + + enum acpi_cstate_mode cstate_states; +}; + +typedef struct soc_intel_xeon_sp_spr_config config_t; + +#endif diff --git a/src/soc/intel/xeon_sp/spr/chipset.cb b/src/soc/intel/xeon_sp/spr/chipset.cb index efc8637a56..9a913d96dc 100644 --- a/src/soc/intel/xeon_sp/spr/chipset.cb +++ b/src/soc/intel/xeon_sp/spr/chipset.cb @@ -32,9 +32,7 @@ chip soc/intel/xeon_sp/spr register "gen2_dec" = "0x000c0ca1" # IPMI KCS register "cstate_states" = "CSTATES_C1C6" - device cpu_cluster 0 on - device lapic 0 on end - end + device cpu_cluster 0 on end device domain 0 on device pci 00.0 on end # Intel device 09a2: Memory Map/Intel VT-d device pci 00.1 on end # Intel device 09a4: Mesh to IAL diff --git a/src/soc/intel/xeon_sp/spr/cpu.c b/src/soc/intel/xeon_sp/spr/cpu.c new file mode 100644 index 0000000000..eb35f3e3c8 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/cpu.c @@ -0,0 +1,281 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpigen.h> +#include <acpi/acpi.h> +#include <console/console.h> +#include <console/debug.h> +#include <cpu/cpu.h> +#include <cpu/intel/cpu_ids.h> +#include <cpu/intel/common/common.h> +#include <cpu/intel/em64t101_save_state.h> +#include <cpu/intel/microcode.h> +#include <cpu/intel/smm_reloc.h> +#include <cpu/intel/turbo.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/mp.h> +#include <cpu/x86/mtrr.h> +#include <device/pci_mmio_cfg.h> +#include <intelblocks/cpulib.h> +#include <intelblocks/mp_init.h> +#include <intelpch/lockdown.h> +#include <soc/msr.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_util.h> +#include <soc/smmrelocate.h> +#include <soc/util.h> + +#include "chip.h" + +static const void *microcode_patch; + +static const config_t *chip_config = NULL; + +bool cpu_soc_is_in_untrusted_mode(void) +{ + return false; +} + +void cpu_soc_bios_done(void) +{ +} + +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(); +} + +/* + * On server platforms the FIT mechanism only updates the microcode on + * the BSP. Loading MCU on AP in parallel seems to fail in 10% of the cases + * so do it serialized. + */ +void get_microcode_info(const void **microcode, int *parallel) +{ + *microcode = intel_microcode_find(); + *parallel = 0; +} + +static void each_cpu_init(struct device *cpu) +{ + msr_t msr; + + printk(BIOS_SPEW, "%s dev: %s, cpu: %lu, apic_id: 0x%x\n", __func__, dev_path(cpu), + cpu_index(), cpu->path.apic.apic_id); + + /* + * Enable PWR_PERF_PLTFRM_OVR and PROCHOT_LOCK. + * The value set by FSP is 20_005f, we set it to 1a_00a4_005b. + */ + msr = rdmsr(MSR_POWER_CTL); + msr.lo |= (0x16 << RESERVED1_SHIFT) | PWR_PERF_PLTFRM_OVR | PROCHOT_LOCK; + msr.hi = 0x1a; + wrmsr(MSR_POWER_CTL, msr); + + /* Set static, idle, dynamic load line impedance */ + msr = rdmsr(MSR_VR_MISC_CONFIG); + msr.lo = 0x1a1a1a; + wrmsr(MSR_VR_MISC_CONFIG, msr); + + /* Set current limitation */ + msr = rdmsr(MSR_VR_CURRENT_CONFIG); + msr.lo = 0x1130; + msr.lo |= CURRENT_LIMIT_LOCK; + wrmsr(MSR_VR_CURRENT_CONFIG, msr); + + /* Set Turbo Ratio Limits */ + msr.lo = chip_config->turbo_ratio_limit & 0xffffffff; + msr.hi = (chip_config->turbo_ratio_limit >> 32) & 0xffffffff; + wrmsr(MSR_TURBO_RATIO_LIMIT, msr); + + /* Set Turbo Ratio Limit Cores */ + msr.lo = chip_config->turbo_ratio_limit_cores & 0xffffffff; + msr.hi = (chip_config->turbo_ratio_limit_cores >> 32) & 0xffffffff; + wrmsr(MSR_TURBO_RATIO_LIMIT_CORES, msr); + + /* Set energy policy */ + msr = rdmsr(MSR_ENERGY_PERF_BIAS_CONFIG); + msr.lo = 0x178fa038; + wrmsr(MSR_ENERGY_PERF_BIAS_CONFIG, msr); + + msr.hi = 0x158d20; + msr.lo = 0x00158af0; + wrmsr(PACKAGE_RAPL_LIMIT, msr); + + /* + * Set HWP base feature, EPP reg enumeration, lock thermal and msr + * This is package level MSR. Need to check if it updates correctly on + * multi-socket platform. + */ + msr = rdmsr(MSR_MISC_PWR_MGMT); + if (!(msr.lo & LOCK_MISC_PWR_MGMT_MSR)) { /* if already locked skip update */ + msr.lo = (HWP_ENUM_ENABLE | HWP_EPP_ENUM_ENABLE | LOCK_MISC_PWR_MGMT_MSR + | LOCK_THERM_INT); + wrmsr(MSR_MISC_PWR_MGMT, msr); + } + + /* 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); + } + + /* Lock the supported Cstates */ + msr = rdmsr(MSR_PKG_CST_CONFIG_CONTROL); + msr.lo |= CST_CFG_LOCK_MASK; + wrmsr(MSR_PKG_CST_CONFIG_CONTROL, msr); + + /* Disable all writes to overclocking limits MSR */ + msr = rdmsr(MSR_FLEX_RATIO); + msr.lo |= MSR_FLEX_RATIO_OC_LOCK; + wrmsr(MSR_FLEX_RATIO, msr); + + /* Lock Power Plane Limit MSR */ + msr = rdmsr(MSR_DRAM_PLANE_POWER_LIMIT); + msr.hi |= MSR_HI_PP_PWR_LIM_LOCK; + wrmsr(MSR_DRAM_PLANE_POWER_LIMIT, msr); + + /* Clear out pending MCEs */ + xeon_configure_mca(); + + /* Enable Vmx */ + // set_vmx_and_lock(); + /* only lock. let vmx enable by FSP */ + set_feature_ctrl_lock(); +} + +static struct device_operations cpu_dev_ops = { + .init = each_cpu_init, +}; + +static const struct cpu_device_id cpu_table[] = { + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_D}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E0}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E2}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E3}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_E4}, + {X86_VENDOR_INTEL, CPUID_SAPPHIRERAPIDS_SP_Ex}, + {0, 0}, +}; + +static const struct cpu_driver driver __cpu_driver = { + .ops = &cpu_dev_ops, + .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) * CONFIG_CPU_BCLK_MHZ); + FUNC_EXIT(); +} + +/* + * Do essential initialization tasks before APs can be fired up + */ +static void pre_mp_init(void) +{ + x86_setup_mtrrs_with_detect(); + x86_mtrr_check(); +} + +static int get_thread_count(void) +{ + unsigned int num_phys = 0, num_virts = 0; + + cpu_read_topology(&num_phys, &num_virts); + printk(BIOS_SPEW, "Detected %u cores and %u threads\n", num_phys, num_virts); + return num_virts * soc_get_num_cpus(); +} + +static void post_mp_init(void) +{ + /* Set Max Ratio */ + set_max_turbo_freq(); + + if (CONFIG(HAVE_SMI_HANDLER)) { + global_smi_enable(); + if (get_lockdown_config() == CHIPSET_LOCKDOWN_COREBOOT) + pmc_lock_smi(); + } +} + +static const struct mp_ops mp_ops = { + .pre_mp_init = pre_mp_init, + .get_cpu_count = get_thread_count, +#if CONFIG(HAVE_SMI_HANDLER) + .get_smm_info = get_smm_info, + .pre_mp_smm_init = smm_southbridge_clear_state, + .relocation_handler = smm_relocation_handler, +#endif + .get_microcode_info = get_microcode_info, + .post_mp_init = post_mp_init, +}; + +void mp_init_cpus(struct bus *bus) +{ + /* + * 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 = bus->dev->chip_info; + + microcode_patch = intel_microcode_find(); + + if (!microcode_patch) + printk(BIOS_ERR, "microcode not found in CBFS!\n"); + + intel_microcode_load_unlocked(microcode_patch); + + if (mp_init_with_smm(bus, &mp_ops) < 0) + printk(BIOS_ERR, "MP initialization failure.\n"); + + /* update numa domain for all cpu devices */ + xeonsp_init_cpu_config(); +} diff --git a/src/soc/intel/xeon_sp/spr/crashlog.c b/src/soc/intel/xeon_sp/spr/crashlog.c new file mode 100644 index 0000000000..8c41258d23 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/crashlog.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/pci_ops.h> +#include <soc/crashlog.h> +#include <soc/pci_devs.h> + +static uint32_t read_msm_config_reg(uint32_t func, uint32_t reg) +{ + uint32_t pcie_offset = PCI_DEV(MSM_BUS, MSM_DEV, func); + return pci_s_read_config32(pcie_offset, reg); +} + +static void write_msm_config_reg(uint32_t func, uint32_t reg, uint32_t value) +{ + uint32_t pcie_offset = PCI_DEV(MSM_BUS, MSM_DEV, func); + pci_s_write_config32(pcie_offset, reg, value); +} + +void disable_cpu_crashlog(void) +{ + uint32_t ctl; + ctl = read_msm_config_reg(MSM_FUN, CRASHLOG_CTL); + ctl |= CRASHLOG_CTL_DIS; + write_msm_config_reg(MSM_FUN, CRASHLOG_CTL, ctl); + ctl = read_msm_config_reg(MSM_FUN_PMON, BIOS_CRASHLOG_CTL); + ctl |= CRASHLOG_CTL_DIS; + write_msm_config_reg(MSM_FUN_PMON, BIOS_CRASHLOG_CTL, ctl); +} diff --git a/src/soc/intel/xeon_sp/spr/numa.c b/src/soc/intel/xeon_sp/spr/numa.c new file mode 100644 index 0000000000..6aba7ccad5 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/numa.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <commonlib/stdlib.h> +#include <device/device.h> +#include <device/pci_ops.h> +#include <device/pci.h> +#include <device/pciexp.h> +#include <soc/numa.h> +#include <soc/soc_util.h> +#include <soc/util.h> +#include <types.h> + +void dump_pds(void) +{ + printk(BIOS_DEBUG, "====== Proximity Domain Dump ======\n"); + printk(BIOS_DEBUG, "number of proximity domains: %d\n", pds.num_pds); + for (uint8_t i = 0; i < pds.num_pds; i++) { + printk(BIOS_DEBUG, "\tproximity domain %d:\n", i); + printk(BIOS_DEBUG, "\t\ttype:%d\n", pds.pds[i].pd_type); + printk(BIOS_DEBUG, "\t\tsocket_bitmap:0x%x\n", pds.pds[i].socket_bitmap); + printk(BIOS_DEBUG, "\t\tdevice_handle:0x%x\n", pds.pds[i].device_handle); + printk(BIOS_DEBUG, "\t\tbase(64MB):0x%x\n", pds.pds[i].base); + printk(BIOS_DEBUG, "\t\tsize(64MB):0x%x\n", pds.pds[i].size); + } +} + +enum cb_err fill_pds(void) +{ + uint8_t num_sockets = soc_get_num_cpus(); + uint8_t num_cxlnodes = get_cxl_node_count(); + + /* + * Rules/assumptions: + * 1. Each processor has a processor proximity domain regardless whether + * a processor has DIMM attached to it or not. + * 2. All system memory map elements are either from processor attached memory, + * or from CXL memory. Each CXL node info entry has a corresponding entry + * in system memory map elements. + * 3. Each CXL device may have multiple HDMs (Host-managed Device Memory). Each + * HDM has one and only one CXL node info entry. Each CXL node info entry + * represents a generic initiator proximity domain. + */ + pds.num_pds = num_cxlnodes + num_sockets; + pds.pds = xmalloc(sizeof(struct proximity_domain) * pds.num_pds); + if (!pds.pds) + die("%s %s out of memory.", __FILE__, __LINE__); + + memset(pds.pds, 0, sizeof(struct proximity_domain) * pds.num_pds); + + /* Fill in processor domains */ + uint8_t i, j; + struct device *dev; + for (i = 0; i < num_sockets; i++) { + pds.pds[i].pd_type = PD_TYPE_PROCESSOR; + pds.pds[i].socket_bitmap = 1 << i; + pds.pds[i].distances = malloc(sizeof(uint8_t) * pds.num_pds); + if (!pds.pds[i].distances) + die("%s %s out of memory.", __FILE__, __LINE__); + /* hard code the distances for now, till we know how to calculate them. */ + for (j = 0; j < pds.num_pds; j++) { + if (j == i) + pds.pds[i].distances[j] = 0x0a; + else + pds.pds[i].distances[j] = 0x0e; + } + } + + /* If there are no CXL nodes, we are done */ + if (num_cxlnodes == 0) + return CB_SUCCESS; + + /* There are CXL nodes, fill in generic initiator domain after the processors pds */ + uint8_t skt_id, cxl_id; + const CXL_NODE_SOCKET *cxl_hob = get_cxl_node(); + for (skt_id = 0, i = num_sockets; skt_id < MAX_SOCKET; skt_id++, i++) { + for (cxl_id = 0; cxl_id < cxl_hob[skt_id].CxlNodeCount; ++cxl_id) { + const CXL_NODE_INFO node = cxl_hob[skt_id].CxlNodeInfo[cxl_id]; + pds.pds[i].pd_type = PD_TYPE_GENERIC_INITIATOR; + pds.pds[i].socket_bitmap = node.SocketBitmap; + pds.pds[i].base = node.Address; + pds.pds[i].size = node.Size; + dev = pcie_find_dsn(node.SerialNumber, node.VendorId, 0); + pds.pds[i].device_handle = PCI_BDF(dev); + pds.pds[i].distances = malloc(sizeof(uint8_t) * pds.num_pds); + if (!pds.pds[i].distances) + die("%s %s out of memory.", __FILE__, __LINE__); + /* hard code the distances until we know how to calculate them */ + for (j = 0; j < pds.num_pds; j++) { + if (j == i) + pds.pds[i].distances[j] = 0x0a; + else + pds.pds[i].distances[j] = 0x0e; + } + } + } + + return CB_SUCCESS; +} + +/* + * Return the total size of memory regions in generic initiator affinity domains. + * The size is in unit of 64MB. + */ +uint32_t get_generic_initiator_mem_size(void) +{ + uint8_t i; + uint32_t size = 0; + + for (i = 0; i < pds.num_pds; i++) { + if (pds.pds[i].pd_type == PD_TYPE_PROCESSOR) + continue; + size += pds.pds[i].size; + } + + return size; +} diff --git a/src/soc/intel/xeon_sp/spr/ramstage.c b/src/soc/intel/xeon_sp/spr/ramstage.c new file mode 100644 index 0000000000..6ac3efe252 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/ramstage.c @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <cpu/x86/smm.h> +#include <drivers/ocp/include/vpd.h> +#include <soc/ramstage.h> +#include <soc/soc_util.h> +#include <soc/util.h> +#include <soc/msr.h> + +unsigned int smbios_cpu_get_voltage(void) +{ + return 16; /* Per SMBIOS spec, voltage times 10 */ +} + +unsigned int smbios_cpu_get_current_speed_mhz(void) +{ + msr_t msr; + msr = rdmsr(MSR_PLATFORM_INFO); + return ((msr.lo >> 8) & 0xff) * CONFIG_CPU_BCLK_MHZ; +} + +__weak void mainboard_override_fsp_gpio(void) +{ + /* Default weak implementation */ +} + +__weak void mainboard_override_usb_oc(void) +{ + /* Default weak implementation */ +} diff --git a/src/soc/intel/xeon_sp/spr/reset.c b/src/soc/intel/xeon_sp/spr/reset.c new file mode 100644 index 0000000000..bc5815ac7a --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/reset.c @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <cf9_reset.h> +#include <intelblocks/cse.h> +#include <intelblocks/pmclib.h> +#include <soc/intel/common/reset.h> + +void do_global_reset(void) +{ + /* Ask CSE to do the global reset */ + if (cse_request_global_reset()) + return; + + /* global reset if CSE fail to reset */ + pmc_global_reset_enable(1); + do_full_reset(); +} diff --git a/src/soc/intel/xeon_sp/spr/xhci.c b/src/soc/intel/xeon_sp/spr/xhci.c new file mode 100644 index 0000000000..544ea16ba9 --- /dev/null +++ b/src/soc/intel/xeon_sp/spr/xhci.c @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <device/pci.h> +#include <soc/pci_devs.h> +#include <soc/xhci.h> +#include <types.h> + +static uint8_t *get_xhci_bar(void) +{ + const struct resource *res; + res = probe_resource(PCH_DEV_XHCI, PCI_BASE_ADDRESS_0); + if (!res) { + printk(BIOS_ERR, "XHCI BAR is not found\n"); + return NULL; + } + return (void *)(uintptr_t)res->base; +} + +void write_usb_oc_mapping(const struct usb_oc_mapping *config, uint8_t pins) +{ + uint8_t *mbar = get_xhci_bar(); + uint8_t i; + + if (mbar == NULL) { + printk(BIOS_ERR, "XHCI BAR is invalid, skip USB OC mapping configuration\n"); + return; + } + for (i = 0; i < pins; i++) + write32(mbar + config[i].pin, config[i].port); +} + +void lock_oc_cfg(bool lock) +{ + uint32_t cfg = pci_read_config32(PCH_DEV_XHCI, SYS_BUS_CFG2); + + if (lock) + cfg |= OCCFGDONE; + else + cfg &= ~(OCCFGDONE); + pci_write_config32(PCH_DEV_XHCI, SYS_BUS_CFG2, cfg); +} |