summaryrefslogtreecommitdiff
path: root/src/soc/intel/xeon_sp
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel/xeon_sp')
-rw-r--r--src/soc/intel/xeon_sp/spr/ddr.c93
-rw-r--r--src/soc/intel/xeon_sp/spr/hob_display.c244
-rw-r--r--src/soc/intel/xeon_sp/spr/include/soc/crashlog.h8
-rw-r--r--src/soc/intel/xeon_sp/spr/include/soc/ddr.h57
-rw-r--r--src/soc/intel/xeon_sp/spr/include/soc/pci_devs.h233
-rw-r--r--src/soc/intel/xeon_sp/spr/include/soc/soc_util.h36
-rw-r--r--src/soc/intel/xeon_sp/spr/include/soc/xhci.h53
-rw-r--r--src/soc/intel/xeon_sp/spr/romstage.c319
-rw-r--r--src/soc/intel/xeon_sp/spr/soc_util.c177
-rw-r--r--src/soc/intel/xeon_sp/spr/upd_display.c139
10 files changed, 1359 insertions, 0 deletions
diff --git a/src/soc/intel/xeon_sp/spr/ddr.c b/src/soc/intel/xeon_sp/spr/ddr.c
new file mode 100644
index 0000000000..ff61a7e8a4
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/ddr.c
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <soc/ddr.h>
+
+unsigned int get_ddr_millivolt(unsigned int ddr_voltage)
+{
+ switch (ddr_voltage) {
+ case SPD_VDD_DDR4:
+ return 1200;
+ case SPD_VDD_DDR5:
+ return 1100;
+ default:
+ return 0;
+ }
+}
+
+unsigned int get_max_memory_speed(unsigned int commonTck)
+{
+ if (commonTck <= DDR_8400_TCK_MIN)
+ return 8400;
+ else if (commonTck <= DDR_7600_TCK_MIN)
+ return 7600;
+ else if (commonTck <= DDR_7200_TCK_MIN)
+ return 7200;
+ else if (commonTck <= DDR_6800_TCK_MIN)
+ return 6800;
+ else if (commonTck <= DDR_6400_TCK_MIN)
+ return 6400;
+ else if (commonTck <= DDR_6000_TCK_MIN)
+ return 6000;
+ else if (commonTck <= DDR_5600_TCK_MIN)
+ return 5600;
+ else if (commonTck <= DDR_5200_TCK_MIN)
+ return 5200;
+ else if (commonTck <= DDR_4800_TCK_MIN)
+ return 4800;
+ else if (commonTck <= DDR_4400_TCK_MIN)
+ return 4400;
+ else if (commonTck <= DDR_4266_TCK_MIN)
+ return 4266;
+ else if (commonTck <= DDR_4200_TCK_MIN)
+ return 4200;
+ else if (commonTck <= DDR_4000_TCK_MIN)
+ return 4000;
+ else if (commonTck <= DDR_3800_TCK_MIN)
+ return 3800;
+ else if (commonTck <= DDR_3733_TCK_MIN)
+ return 3733;
+ else if (commonTck <= DDR_3600_TCK_MIN)
+ return 3600;
+ else if (commonTck <= DDR_3466_TCK_MIN)
+ return 3466;
+ else if (commonTck <= DDR_3400_TCK_MIN)
+ return 3400;
+ else if (commonTck <= DDR_3200_TCK_MIN)
+ return 3200;
+ else if (commonTck <= DDR_3000_TCK_MIN)
+ return 3000;
+ else if (commonTck <= DDR_2933_TCK_MIN)
+ return 2933;
+ else if (commonTck <= DDR_2800_TCK_MIN)
+ return 2800;
+ else if (commonTck <= DDR_2666_TCK_MIN)
+ return 2666;
+ else if (commonTck <= DDR_2600_TCK_MIN)
+ return 2600;
+ else if (commonTck <= DDR_2400_TCK_MIN)
+ return 2400;
+ else if (commonTck <= DDR_2200_TCK_MIN)
+ return 2200;
+ else if (commonTck <= DDR_2133_TCK_MIN)
+ return 2133;
+ else if (commonTck <= DDR_2000_TCK_MIN)
+ return 2000;
+ else if (commonTck <= DDR_1866_TCK_MIN)
+ return 1866;
+ else if (commonTck <= DDR_1800_TCK_MIN)
+ return 1800;
+ else if (commonTck <= DDR_1600_TCK_MIN)
+ return 1600;
+ else if (commonTck <= DDR_1400_TCK_MIN)
+ return 1400;
+ else if (commonTck <= DDR_1333_TCK_MIN)
+ return 1333;
+ else if (commonTck <= DDR_1200_TCK_MIN)
+ return 1200;
+ else if (commonTck <= DDR_1066_TCK_MIN)
+ return 1066;
+ else if (commonTck <= DDR_1000_TCK_MIN)
+ return 1000;
+ else
+ return 800;
+}
diff --git a/src/soc/intel/xeon_sp/spr/hob_display.c b/src/soc/intel/xeon_sp/spr/hob_display.c
new file mode 100644
index 0000000000..cba2d9c8e7
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/hob_display.c
@@ -0,0 +1,244 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <fsp/util.h>
+#include <hob_cxlnode.h>
+#include <hob_iiouds.h>
+#include <hob_memmap.h>
+#include <lib.h>
+#include <soc/soc_util.h>
+
+static const uint8_t fsp_hob_iio_uds_guid[16] = FSP_HOB_IIO_UNIVERSAL_DATA_GUID;
+static const uint8_t fsp_hob_memmap_guid[16] = FSP_SYSTEM_MEMORYMAP_HOB_GUID;
+static const uint8_t fsp_hob_cxlnode_guid[16] = FSP_HOB_CXLNODE_GUID;
+
+struct guid_name_map {
+ const void *guid;
+ const char *name;
+};
+
+static const struct guid_name_map guid_names[] = {
+ {fsp_hob_iio_uds_guid, "FSP_HOB_IIO_UNIVERSAL_DATA_GUID"},
+ {fsp_hob_memmap_guid, "FSP_SYSTEM_MEMORYMAP_HOB_GUID"},
+ {fsp_hob_cxlnode_guid, "FSP_HOB_CXLNODE_GUID"},
+};
+
+const char *soc_get_guid_name(const uint8_t *guid)
+{
+ size_t index;
+
+ /* Compare the GUID values in this module */
+ for (index = 0; index < ARRAY_SIZE(guid_names); index++)
+ if (fsp_guid_compare(guid, guid_names[index].guid))
+ return guid_names[index].name;
+
+ return NULL;
+}
+
+void soc_display_memmap_hob(const struct SystemMemoryMapHob **hob_addr)
+{
+ struct SystemMemoryMapHob *hob = (struct SystemMemoryMapHob *)*hob_addr;
+
+ printk(BIOS_DEBUG, "================== MEMORY MAP HOB DATA ==================\n");
+ printk(BIOS_DEBUG, "hob: %p, structure size: 0x%lx\n", hob, sizeof(*hob));
+
+ printk(BIOS_DEBUG,
+ "\tlowMemBase: 0x%x, lowMemSize: 0x%x, highMemBase: 0x%x, "
+ "highMemSize: 0x%x\n",
+ hob->lowMemBase, hob->lowMemSize, hob->highMemBase, hob->highMemSize);
+ printk(BIOS_DEBUG, "\tmemSize: 0x%x, memFreq: 0x%x\n", hob->memSize, hob->memFreq);
+
+ printk(BIOS_DEBUG, "\tNumChPerMC: %d\n", hob->NumChPerMC);
+ printk(BIOS_DEBUG, "\tSystemMemoryMapElement Entries: %d, entry size: %ld\n",
+ hob->numberEntries, sizeof(SYSTEM_MEMORY_MAP_ELEMENT));
+
+ for (int e = 0; e < hob->numberEntries; ++e) {
+ const struct SystemMemoryMapElement *mem_element = &hob->Element[e];
+ printk(BIOS_DEBUG,
+ "\t\tmemory_map %d, SocketId: 0x%x, BaseAddress: 0x%x, ElementSize: 0x%x, Type: 0x%x\n",
+ e, mem_element->SocketId, mem_element->BaseAddress,
+ mem_element->ElementSize, mem_element->Type);
+ }
+
+ printk(BIOS_DEBUG,
+ "^^^ MEMMAP_SOCKET: %ld, ChannelDevice: %ld, MEMMAP_DIMM_DEVICE_INFO_STRUCT: %ld\n",
+ sizeof(MEMMAP_SOCKET), sizeof(struct ChannelDevice),
+ sizeof(MEMMAP_DIMM_DEVICE_INFO_STRUCT));
+ printk(BIOS_DEBUG, "^^^ Element Offset: %ld\n",
+ offsetof(SYSTEM_MEMORY_MAP_HOB, Element));
+ printk(BIOS_DEBUG, "^^^ Socket Offset: %ld\n",
+ offsetof(SYSTEM_MEMORY_MAP_HOB, Socket));
+ printk(BIOS_DEBUG, "^^^ ChannelInfo Offset: %ld\n",
+ offsetof(MEMMAP_SOCKET, ChannelInfo));
+ printk(BIOS_DEBUG, "^^^ DimmInfo Offset: %ld\n",
+ offsetof(struct ChannelDevice, DimmInfo));
+ printk(BIOS_DEBUG, "^^^ DimmSize Offset: %ld\n",
+ offsetof(struct DimmDevice, DimmSize));
+
+ for (int s = 0; s < MAX_SOCKET; ++s) {
+ if (!hob->Socket[s].SocketEnabled)
+ continue;
+ for (int ch = 0; ch < MAX_CH; ++ch) {
+ if (!hob->Socket[s].ChannelInfo[ch].Enabled)
+ continue;
+ for (int dimm = 0; dimm < MAX_DIMM; ++dimm) {
+ if (!hob->Socket[s].ChannelInfo[ch].DimmInfo[dimm].Present)
+ continue;
+ printk(BIOS_DEBUG,
+ "\tsocket: %d, ch: %d, dimm: %d, enabled: %d, DimmSize: 0x%x\n",
+ s, ch, dimm,
+ hob->Socket[s].ChannelInfo[ch].DimmInfo[dimm].Enabled,
+ hob->Socket[s].ChannelInfo[ch].DimmInfo[dimm].DimmSize);
+ }
+ }
+ }
+
+ printk(BIOS_DEBUG, "\tBiosFisVersion: 0x%x\n", hob->BiosFisVersion);
+ printk(BIOS_DEBUG, "\tMmiohBase: 0x%x\n", hob->MmiohBase);
+
+ hexdump(hob, sizeof(*hob));
+}
+
+void soc_display_iio_universal_data_hob(const IIO_UDS *hob)
+{
+ printk(BIOS_DEBUG, "===================== IIO_UDS HOB DATA =====================\n");
+ printk(BIOS_DEBUG, "hob: %p, structure size: 0x%lx\n", hob, sizeof(*hob));
+
+ printk(BIOS_DEBUG, "\t===================== SYSTEM STATUS =====================\n");
+ printk(BIOS_DEBUG, "\tnumCpus: 0x%x\n", hob->SystemStatus.numCpus);
+ printk(BIOS_DEBUG, "\ttolmLimit: 0x%x\n", hob->SystemStatus.tolmLimit);
+
+ printk(BIOS_DEBUG, "\t===================== PLATFORM DATA =====================\n");
+ printk(BIOS_DEBUG, "\tPlatGlobalIoBase: 0x%x\n", hob->PlatformData.PlatGlobalIoBase);
+ printk(BIOS_DEBUG, "\tPlatGlobalIoLimit: 0x%x\n", hob->PlatformData.PlatGlobalIoLimit);
+ printk(BIOS_DEBUG, "\tPlatGlobalMmio32Base: 0x%x\n",
+ hob->PlatformData.PlatGlobalMmio32Base);
+ printk(BIOS_DEBUG, "\tPlatGlobalMmio32Limit: 0x%x\n",
+ hob->PlatformData.PlatGlobalMmio32Limit);
+ printk(BIOS_DEBUG, "\tPlatGlobalMmio64Base: 0x%llx\n",
+ hob->PlatformData.PlatGlobalMmio64Base);
+ printk(BIOS_DEBUG, "\tPlatGlobalMmio64Limit: 0x%llx\n",
+ hob->PlatformData.PlatGlobalMmio64Limit);
+ printk(BIOS_DEBUG, "\tMemTsegSize: 0x%x\n", hob->PlatformData.MemTsegSize);
+ printk(BIOS_DEBUG, "\tPciExpressBase: 0x%llx\n", hob->PlatformData.PciExpressBase);
+ printk(BIOS_DEBUG, "\tPciExpressSize: 0x%x\n", hob->PlatformData.PciExpressSize);
+ printk(BIOS_DEBUG, "\tMemTolm: 0x%x\n", hob->PlatformData.MemTolm);
+ printk(BIOS_DEBUG, "\tnumofIIO: 0x%x\n", hob->PlatformData.numofIIO);
+ printk(BIOS_DEBUG, "\tMaxBusNumber: 0x%x\n", hob->PlatformData.MaxBusNumber);
+ printk(BIOS_DEBUG, "\tIoGranularity: 0x%x\n", hob->PlatformData.IoGranularity);
+ printk(BIOS_DEBUG, "\tMmiolGranularity: 0x%x\n", hob->PlatformData.MmiolGranularity);
+ printk(BIOS_DEBUG, "\tMmiohGranularity: hi: 0x%x, lo:0x%x\n",
+ hob->PlatformData.MmiohGranularity.hi, hob->PlatformData.MmiohGranularity.lo);
+
+ for (uint8_t s = 0; s < hob->PlatformData.numofIIO; ++s) {
+ printk(BIOS_DEBUG, "\t============ Socket %d Info ================\n", s);
+ printk(BIOS_DEBUG, "\tValid: 0x%x\n", hob->PlatformData.IIO_resource[s].Valid);
+ printk(BIOS_DEBUG, "\tSocketID: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].SocketID);
+ printk(BIOS_DEBUG, "\tBusBase: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].BusBase);
+ printk(BIOS_DEBUG, "\tBusLimit: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].BusLimit);
+ printk(BIOS_DEBUG, "\tPciResourceIoBase: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].PciResourceIoBase);
+ printk(BIOS_DEBUG, "\tPciResourceIoLimit: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].PciResourceIoLimit);
+ printk(BIOS_DEBUG, "\tIoApicBase: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].IoApicBase);
+ printk(BIOS_DEBUG, "\tIoApicLimit: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].IoApicLimit);
+ printk(BIOS_DEBUG, "\tMmio32Base: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].Mmio32Base);
+ printk(BIOS_DEBUG, "\tMmio32Limit: 0x%x\n",
+ hob->PlatformData.IIO_resource[s].Mmio32Limit);
+ printk(BIOS_DEBUG, "\tMmio64Base: 0x%llx\n",
+ hob->PlatformData.IIO_resource[s].Mmio64Base);
+ printk(BIOS_DEBUG, "\tMmio64Limit: 0x%llx\n",
+ hob->PlatformData.IIO_resource[s].Mmio64Limit);
+
+ printk(BIOS_DEBUG, "\t============ Stack Info ================\n");
+ for (int x = 0; x < MAX_LOGIC_IIO_STACK; ++x) {
+ const STACK_RES *ri = &hob->PlatformData.IIO_resource[s].StackRes[x];
+ printk(BIOS_DEBUG, "\t\t========== Stack %d ===============\n", x);
+ printk(BIOS_DEBUG, "\t\tPersonality: 0x%x\n", ri->Personality);
+ printk(BIOS_DEBUG, "\t\tBusBase: 0x%x\n", ri->BusBase);
+ printk(BIOS_DEBUG, "\t\tBusLimit: 0x%x\n", ri->BusLimit);
+ printk(BIOS_DEBUG, "\t\tIoBase: 0x%x\n", ri->IoBase);
+ printk(BIOS_DEBUG, "\t\tIoLimit: 0x%x\n", ri->IoLimit);
+ printk(BIOS_DEBUG, "\t\tPciResourceIoBase: 0x%x\n",
+ ri->PciResourceIoBase);
+ printk(BIOS_DEBUG, "\t\tPciResourceIoLimit: 0x%x\n",
+ ri->PciResourceIoLimit);
+ printk(BIOS_DEBUG, "\t\tIoApicBase: 0x%x\n", ri->IoApicBase);
+ printk(BIOS_DEBUG, "\t\tIoApicLimit: 0x%x\n", ri->IoApicLimit);
+ printk(BIOS_DEBUG, "\t\tMmio32Base: 0x%x\n", ri->Mmio32Base);
+ printk(BIOS_DEBUG, "\t\tMmio32Limit: 0x%x\n", ri->Mmio32Limit);
+ printk(BIOS_DEBUG, "\t\tPciResourceMem32Base: 0x%x\n",
+ ri->PciResourceMem32Base);
+ printk(BIOS_DEBUG, "\t\tPciResourceMem32Limit: 0x%x\n",
+ ri->PciResourceMem32Limit);
+ printk(BIOS_DEBUG, "\t\tMmio64Base: 0x%llx\n", ri->Mmio64Base);
+ printk(BIOS_DEBUG, "\t\tMmio64Limit: 0x%llx\n", ri->Mmio64Limit);
+ printk(BIOS_DEBUG, "\t\tPciResourceMem64Base: 0x%llx\n",
+ ri->PciResourceMem64Base);
+ printk(BIOS_DEBUG, "\t\tPciResourceMem64Limit: 0x%llx\n",
+ ri->PciResourceMem64Limit);
+ printk(BIOS_DEBUG, "\t\tVtdBarAddress: 0x%x\n", ri->VtdBarAddress);
+ }
+
+ printk(BIOS_DEBUG, "\t============ PcieInfo ================\n");
+ IIO_RESOURCE_INSTANCE iio_resource = hob->PlatformData.IIO_resource[s];
+ for (int p = 0; p < NUMBER_PORTS_PER_SOCKET; ++p) {
+ printk(BIOS_DEBUG, "\t\tPort: %d, Device: 0x%x, Function: 0x%x\n", p,
+ iio_resource.PcieInfo.PortInfo[p].Device,
+ iio_resource.PcieInfo.PortInfo[p].Function);
+ }
+ }
+
+ hexdump(hob, sizeof(*hob));
+}
+
+static void soc_display_cxlnode_hob(const CXL_NODE_SOCKET *hob)
+{
+ printk(BIOS_DEBUG, "===================== CXLNODE HOB DATA =====================\n");
+ printk(BIOS_DEBUG, "hob: %p, structure size: 0x%lx\n", hob, sizeof(*hob) * MAX_SOCKET);
+
+ for (uint8_t skt_id = 0; skt_id < MAX_SOCKET; skt_id++) {
+ printk(BIOS_DEBUG, "\tSocket:%d, CxlNodeCount: 0x%x\n", skt_id,
+ hob[skt_id].CxlNodeCount);
+ for (uint8_t i = 0; i < hob[skt_id].CxlNodeCount; ++i) {
+ printk(BIOS_DEBUG, "\tCxlNodeInfo[%d]:\n", i);
+ const CXL_NODE_INFO node = hob[skt_id].CxlNodeInfo[i];
+ printk(BIOS_DEBUG, "\t\tSerialNumber: 0x%llx\n", node.SerialNumber);
+ printk(BIOS_DEBUG, "\t\tVendorId: 0x%x\n", node.VendorId);
+ printk(BIOS_DEBUG, "\t\tAttr: 0x%x\n", node.Attr);
+ printk(BIOS_DEBUG, "\t\tAddress: 0x%x\n", node.Address);
+ printk(BIOS_DEBUG, "\t\tSize: 0x%x\n", node.Size);
+ printk(BIOS_DEBUG, "\t\tWays: 0x%x\n", node.Ways);
+ printk(BIOS_DEBUG, "\t\tSocketBitmap: 0x%x\n", node.SocketBitmap);
+ printk(BIOS_DEBUG,
+ "\t\tPerfData format: RdLatency(0.1ns), WrLatency(0.1ns), RdBW(100MB/s), WrBW(100MB/s)\n");
+ printk(BIOS_DEBUG,
+ "\t\tEfiMemType and PerfData are invalid for SPR-SP.\n");
+ }
+ }
+
+ hexdump(hob, sizeof(*hob) * MAX_SOCKET);
+}
+
+void soc_display_hob(const struct hob_header *hob)
+{
+ uint8_t *guid;
+
+ if (hob->type != HOB_TYPE_GUID_EXTENSION)
+ return;
+
+ guid = (uint8_t *)fsp_hob_header_to_resource(hob);
+
+ if (fsp_guid_compare(guid, fsp_hob_iio_uds_guid))
+ soc_display_iio_universal_data_hob((const IIO_UDS *)(guid + 16));
+ else if (fsp_guid_compare(guid, fsp_hob_memmap_guid))
+ soc_display_memmap_hob((const struct SystemMemoryMapHob **)(guid + 16));
+ else if (fsp_guid_compare(guid, fsp_hob_cxlnode_guid))
+ soc_display_cxlnode_hob((const CXL_NODE_SOCKET *)(guid + 16));
+}
diff --git a/src/soc/intel/xeon_sp/spr/include/soc/crashlog.h b/src/soc/intel/xeon_sp/spr/include/soc/crashlog.h
new file mode 100644
index 0000000000..ff47232138
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/include/soc/crashlog.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_CRASHLOG_H_
+#define _SOC_CRASHLOG_H_
+
+void disable_cpu_crashlog(void);
+
+#endif /* _SOC_CRASHLOG_H_ */
diff --git a/src/soc/intel/xeon_sp/spr/include/soc/ddr.h b/src/soc/intel/xeon_sp/spr/include/soc/ddr.h
new file mode 100644
index 0000000000..f2dc5c8998
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/include/soc/ddr.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _SPR_DDR_H_
+#define _SPR_DDR_H_
+
+#include <types.h>
+
+/* SPD Byte 11: Module Nominal Voltage
+ * currently DDR4 only supports 1.2V, DDR5 only supports 1.1V. */
+#define SPD_VDD_DDR4 3
+#define SPD_VDD_DDR5 0
+#define SPD_TYPE_DDR5 0x12
+
+/* DDR_*_TCK_MIN are in picoseconds */
+#define DDR_1000_TCK_MIN 2000
+#define DDR_1066_TCK_MIN 1875
+#define DDR_1200_TCK_MIN 1667
+#define DDR_1333_TCK_MIN 1500
+#define DDR_1400_TCK_MIN 1429
+#define DDR_1600_TCK_MIN 1250
+#define DDR_1800_TCK_MIN 1110
+#define DDR_1866_TCK_MIN 1071
+#define DDR_2000_TCK_MIN 1000
+#define DDR_2133_TCK_MIN 938
+#define DDR_2200_TCK_MIN 909
+#define DDR_2400_TCK_MIN 833
+#define DDR_2600_TCK_MIN 769
+#define DDR_2666_TCK_MIN 750
+#define DDR_2800_TCK_MIN 714
+#define DDR_2933_TCK_MIN 682
+#define DDR_3000_TCK_MIN 667
+#define DDR_3200_TCK_MIN 625
+#define DDR_3400_TCK_MIN 589
+#define DDR_3466_TCK_MIN 577
+#define DDR_3600_TCK_MIN 556
+#define DDR_3733_TCK_MIN 536
+#define DDR_3800_TCK_MIN 527
+#define DDR_4000_TCK_MIN 500
+#define DDR_4200_TCK_MIN 477
+#define DDR_4266_TCK_MIN 469
+#define DDR_4400_TCK_MIN 455
+#define DDR_4800_TCK_MIN 417
+#define DDR_5200_TCK_MIN 385
+#define DDR_5600_TCK_MIN 358
+#define DDR_6000_TCK_MIN 334
+#define DDR_6400_TCK_MIN 313
+#define DDR_6800_TCK_MIN 295
+#define DDR_7200_TCK_MIN 278
+#define DDR_7600_TCK_MIN 264
+#define DDR_8000_TCK_MIN 250
+#define DDR_8400_TCK_MIN 239
+
+unsigned int get_max_memory_speed(unsigned int commonTck);
+unsigned int get_ddr_millivolt(unsigned int ddr_voltage);
+bool mainboard_dimm_slot_exists(uint8_t socket, uint8_t channel, uint8_t slot);
+
+#endif /* _SPR_DDR_H_ */
diff --git a/src/soc/intel/xeon_sp/spr/include/soc/pci_devs.h b/src/soc/intel/xeon_sp/spr/include/soc/pci_devs.h
new file mode 100644
index 0000000000..fba3c683e8
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/include/soc/pci_devs.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_PCI_DEVS_H_
+#define _SOC_PCI_DEVS_H_
+
+#include <device/pci_def.h>
+#include <types.h>
+
+#define _SA_DEVFN(slot) PCI_DEVFN(SA_DEV_SLOT_##slot, 0)
+#define _PCH_DEVFN(slot, func) PCI_DEVFN(PCH_DEV_SLOT_##slot, func)
+
+#if !defined(__SIMPLE_DEVICE__)
+#include <device/device.h>
+#define _SA_DEV(slot) pcidev_path_on_root_debug(_SA_DEVFN(slot), __func__)
+#define _PCH_DEV(slot, func) pcidev_path_on_root_debug(_PCH_DEVFN(slot, func), __func__)
+#else
+#define _SA_DEV(slot) PCI_DEV(0, SA_DEV_SLOT_##slot, 0)
+#define _PCH_DEV(slot, func) PCI_DEV(0, PCH_DEV_SLOT_##slot, func)
+#endif
+
+#define UNCORE_BUS_0 0
+#define UNCORE_BUS_1 1
+
+/* UBOX Registers [B:30, D:0, F:1] */
+#define UBOX_DECS_DEV 0
+#define UBOX_URACU_FUNC 1
+#define SMM_FEATURE_CONTROL 0x8c
+#define SMM_CODE_CHK_EN BIT(2)
+#define SMM_FEATURE_CONTROL_LOCK BIT(0)
+
+/* CHA registers [B:31, D:29, F:0/F:1]
+ * SAD is the previous xeon_sp register name. Keep defines for shared code.
+ */
+#define CHA_DEV 29
+
+#define SAD_ALL_DEV CHA_DEV
+#define SAD_ALL_FUNC 0
+#define SAD_ALL_PAM0123_CSR 0x80
+#define SAD_ALL_PAM456_CSR 0x84
+
+#if !defined(__SIMPLE_DEVICE__)
+#define _PCU_DEV(bus, func) pcidev_path_on_bus(bus, PCI_DEVFN(PCU_DEV, func))
+#else
+#define _PCU_DEV(bus, func) PCI_DEV(bus, PCU_DEV, func)
+#endif
+
+/* PCU [B:31, D:30, F:0->F:6] */
+#define PCU_IIO_STACK UNCORE_BUS_1
+#define PCU_DEV 30
+
+#define PCU_CR0_FUN 0
+#define PCU_DEV_CR0(bus) _PCU_DEV(bus, PCU_CR0_FUN)
+#define PCU_CR0_PLATFORM_INFO 0xa8
+#define PCU_CR0_TURBO_ACTIVATION_RATIO 0xb0
+#define TURBO_ACTIVATION_RATIO_LOCK BIT(31)
+#define PCU_CR0_P_STATE_LIMITS 0xd8
+#define P_STATE_LIMITS_LOCK BIT(31)
+#define PCU_CR0_PACKAGE_RAPL_LIMIT_LWR 0xe8
+#define PCU_CR0_PACKAGE_RAPL_LIMIT_UPR (PCU_CR0_PACKAGE_RAPL_LIMIT_LWR + 4)
+#define PKG_PWR_LIM_LOCK_UPR BIT(31)
+#define PCU_CR0_PMAX 0xf0
+#define PMAX_LOCK BIT(31)
+#define PCU_CR0_VR_CURRENT_CONFIG_CFG 0xf8
+#define VR_CURRENT_CONFIG_LOCK BIT(31)
+
+#define PCU_CR1_FUN 1
+#define PCU_DEV_CR1(bus) _PCU_DEV(bus, PCU_CR1_FUN)
+#define PCU_CR1_BIOS_MB_DATA_REG 0x8c
+
+#define PCU_CR1_BIOS_MB_INTERFACE_REG 0x90
+#define BIOS_MB_RUN_BUSY_MASK BIT(31)
+#define BIOS_MB_CMD_MASK 0xff
+#define BIOS_CMD_READ_PCU_MISC_CFG 0x5
+#define BIOS_CMD_WRITE_PCU_MISC_CFG 0x6
+#define BIOS_ERR_INVALID_CMD 0x01
+
+#define PCU_CR1_BIOS_RESET_CPL_REG 0x94
+#define RST_CPL1_MASK BIT(1)
+#define RST_CPL2_MASK BIT(2)
+#define RST_CPL3_MASK BIT(3)
+#define RST_CPL4_MASK BIT(4)
+#define PCODE_INIT_DONE1_MASK BIT(9)
+#define PCODE_INIT_DONE2_MASK BIT(10)
+#define PCODE_INIT_DONE3_MASK BIT(11)
+#define PCODE_INIT_DONE4_MASK BIT(12)
+
+#define PCU_CR1_DESIRED_CORES_CFG2_REG 0xbc
+#define PCU_CR1_DESIRED_CORES_CFG2_REG_LOCK_MASK BIT(31)
+
+#define PCU_CR2_FUN 2
+#define PCU_DEV_CR2(bus) _PCU_DEV(bus, PCU_CR2_FUN)
+#define PCU_CR2_DRAM_POWER_INFO_LWR 0xa8
+#define PCU_CR2_DRAM_POWER_INFO_UPR (PCU_CR2_DRAM_POWER_INFO_LWR + 4)
+#define DRAM_POWER_INFO_LOCK_UPR BIT(31)
+
+#define PCU_CR2_DRAM_PLANE_POWER_LIMIT_LWR 0xf0
+#define PCU_CR2_DRAM_PLANE_POWER_LIMIT_UPR (PCU_CR2_DRAM_PLANE_POWER_LIMIT_LWR + 4)
+#define PP_PWR_LIM_LOCK_UPR BIT(31)
+
+#define PCU_CR3_FUN 3
+#define PCU_CR3_CAPID4 0x94
+#define ERR_SPOOFING_DIS 1
+#define PCU_DEV_CR3(bus) _PCU_DEV(bus, PCU_CR3_FUN)
+#define PCU_CR3_CONFIG_TDP_CONTROL 0xd8
+#define TDP_LOCK BIT(31)
+#define PCU_CR3_FLEX_RATIO 0xa0
+#define OC_LOCK BIT(20)
+
+#define PCU_CR4_FUN 4
+#define PCU_VIRAL_CONTROL 0x84
+#define PCU_FW_ERR_EN (1 << 10)
+#define PCU_UC_ERR_EN (1 << 9)
+#define PCU_HW_ERR_EN (1 << 8)
+#define PCU_EMCA_MODE (1 << 2)
+
+#define PCU_CR6_FUN 6
+#define PCU_DEV_CR6(bus) _PCU_DEV(bus, PCU_CR6_FUN)
+#define PCU_CR6_PLATFORM_RAPL_LIMIT_CFG_LWR 0xa8
+#define PCU_CR6_PLATFORM_RAPL_LIMIT_CFG_UPR (PCU_CR6_PLATFORM_RAPL_LIMIT_CFG_LWR + 4)
+#define PLT_PWR_LIM_LOCK_UPR BIT(31)
+#define PCU_CR6_PLATFORM_POWER_INFO_CFG_LWR 0xb0
+#define PCU_CR6_PLATFORM_POWER_INFO_CFG_UPR (PCU_CR6_PLATFORM_POWER_INFO_CFG_LWR + 4)
+#define PLT_PWR_INFO_LOCK_UPR BIT(31)
+
+/* Memory Map/VTD Device Functions
+ * These are available in each IIO stack
+ */
+#define MMAP_VTD_DEV 0x0
+#define MMAP_VTD_FUNC 0x0
+
+#define VTD_TOLM_CSR 0xd0
+#define VTD_TSEG_BASE_CSR 0xa8
+#define VTD_TSEG_LIMIT_CSR 0xac
+#define VTD_EXT_CAP_LOW 0x10
+#define VTD_MMCFG_BASE_CSR 0x90
+#define VTD_MMCFG_LIMIT_CSR 0x98
+#define VTD_TOHM_CSR 0xc8
+#define VTD_MMIOL_CSR 0xd8
+#define VTD_NCMEM_BASE_CSR 0xe0
+#define VTD_NCMEM_LIMIT_CSR 0xe8
+#define VTD_LTDPR 0x290
+
+#define VMD_DEV_NUM 0x00
+#define VMD_FUNC_NUM 0x05
+
+#define MMAP_VTD_CFG_REG_DEVID 0x09a2
+#define MMAP_VTD_STACK_CFG_REG_DEVID 0x09a2
+#define VTD_DEV_NUM 0x0
+#define VTD_FUNC_NUM 0x0
+
+#if !defined(__SIMPLE_DEVICE__)
+#define VTD_DEV(bus) pcidev_path_on_bus((bus), PCI_DEVFN(VTD_DEV_NUM, VTD_FUNC_NUM))
+#else
+#define VTD_DEV(bus) PCI_DEV((bus), VTD_DEV_NUM, VTD_FUNC_NUM)
+#endif
+
+/* PCH Device info */
+
+#define XHCI_BUS_NUMBER 0x0
+#define PCH_DEV_SLOT_XHCI 0x14
+#define XHCI_FUNC_NUM 0x0
+#define PCH_DEVFN_XHCI _PCH_DEVFN(XHCI, 0)
+#define PCH_DEV_XHCI _PCH_DEV(XHCI, 0)
+#define PCH_DEVFN_THERMAL _PCH_DEVFN(XHCI, 2)
+
+
+#define PCH_DEV_SLOT_CSE 0x16
+#define PCH_DEVFN_CSE _PCH_DEVFN(CSE, 0)
+#define PCH_DEVFN_CSE_2 _PCH_DEVFN(CSE, 1)
+#define PCH_DEVFN_CSE_3 _PCH_DEVFN(CSE, 4)
+#define PCH_DEV_CSE _PCH_DEV(CSE, 0)
+#define PCH_DEV_CSE_2 _PCH_DEV(CSE, 1)
+#define PCH_DEV_CSE_3 _PCH_DEV(CSE, 4)
+
+#define PCH_DEV_SLOT_LPC 0x1f
+#define PCH_DEVFN_LPC _PCH_DEVFN(LPC, 0)
+#define PCH_DEVFN_P2SB _PCH_DEVFN(LPC, 1)
+#define PCH_DEVFN_PMC _PCH_DEVFN(LPC, 2)
+#define PCH_DEVFN_SMBUS _PCH_DEVFN(LPC, 4)
+#define PCH_DEVFN_SPI _PCH_DEVFN(LPC, 5)
+#define PCH_DEV_LPC _PCH_DEV(LPC, 0)
+#define PCH_DEV_P2SB _PCH_DEV(LPC, 1)
+#define PCH_DEV_PMC _PCH_DEV(LPC, 2)
+#define PCH_DEV_SMBUS _PCH_DEV(LPC, 4)
+#define PCH_DEV_SPI _PCH_DEV(LPC, 5)
+
+#define HPET_BUS_NUM 0x0
+#define HPET_DEV_NUM PCH_DEV_SLOT_LPC
+#define HPET0_FUNC_NUM 0x00
+
+#define PCH_IOAPIC_BUS_NUMBER 0xF0
+#define PCH_IOAPIC_DEV_NUM 0x1F
+#define PCH_IOAPIC_FUNC_NUM 0x00
+
+// ========== IOAPIC Definitions for DMAR/ACPI ========
+#define PCH_IOAPIC_ID 0x08
+
+/* Root port Registers */
+
+/* IEH */
+#define IEH_EXT_CAP_ID 0x7 /* At 0x160 */
+#define GSYSEVTCTL 0x104 /* Offset from IEH_EXT_CAP_ID */
+#define CE_ERR_UNMSK 1
+#define NON_FATAL_UNMSK (1 << 1)
+#define FATAL_UNMSK (1 << 2)
+#define GSYSEVTMAP 0x108 /* Offset from IEH_EXT_CAP_ID */
+#define CE_SMI 1
+#define NF_SMI (1 << 2)
+#define FA_SMI (1 << 4)
+
+
+#define DMIRCBAR 0x50
+#define DMI3_DEVID 0x2020
+#define PCIE_ROOTCTL 0x5c
+#define ERRINJCON 0x198
+
+// IIO DFX Global D7F7 registers
+#define IIO_DFX_TSWCTL0 0x30c
+#define IIO_DFX_LCK_CTL 0x504
+
+// XHCI register
+#define SYS_BUS_CFG2 0x44
+
+/* MSM registers */
+#define MSM_BUS 0xF2
+#define MSM_DEV 3
+#define MSM_FUN 0
+#define MSM_FUN_PMON 1
+#define CRASHLOG_CTL 0x1B8
+#define BIOS_CRASHLOG_CTL 0x158
+#define CRASHLOG_CTL_DIS BIT(2)
+
+#endif /* _SOC_PCI_DEVS_H_ */
diff --git a/src/soc/intel/xeon_sp/spr/include/soc/soc_util.h b/src/soc/intel/xeon_sp/spr/include/soc/soc_util.h
new file mode 100644
index 0000000000..4539991d55
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/include/soc/soc_util.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_UTIL_H_
+#define _SOC_UTIL_H_
+
+#include <hob_iiouds.h>
+#include <hob_memmap.h>
+#include <hob_cxlnode.h>
+#include <hob_systeminfo.h>
+#include <hob_enhancedwarningloglib.h>
+
+const struct SystemMemoryMapHob *get_system_memory_map(void);
+const struct SystemMemoryMapElement *get_system_memory_map_elment(uint8_t *num);
+
+uint32_t get_socket_stack_busno(uint32_t socket, uint32_t stack);
+
+bool is_iio_cxl_stack_res(const STACK_RES *res);
+
+void soc_display_iio_universal_data_hob(const IIO_UDS *hob);
+void soc_display_memmap_hob(const struct SystemMemoryMapHob **hob_addr);
+
+const CXL_NODE_SOCKET *get_cxl_node(void);
+uint8_t get_cxl_node_count(void);
+
+const SYSTEM_INFO_VAR *get_system_info_hob(void);
+
+const EWL_PRIVATE_DATA *get_ewl_hob(void);
+
+uint32_t get_ubox_busno(uint32_t socket, uint8_t offset);
+uint32_t get_socket_ubox_busno(uint32_t socket);
+
+void check_fsp_error(void);
+
+void mainboard_fsp_error_handle(void);
+
+#endif /* _SOC_UTIL_H_ */
diff --git a/src/soc/intel/xeon_sp/spr/include/soc/xhci.h b/src/soc/intel/xeon_sp/spr/include/soc/xhci.h
new file mode 100644
index 0000000000..005a8e1b0b
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/include/soc/xhci.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _XHCI_H_
+#define _XHCI_H_
+
+#include <types.h>
+
+#define USB2_OC_PIN_0 0x90A4
+#define USB2_OC_PIN_1 0x90A8
+#define USB2_OC_PIN_2 0x90AC
+#define USB2_OC_PIN_3 0x90B0
+#define USB2_OC_PIN_4 0x90B4
+#define USB2_OC_PIN_5 0x90B8
+#define USB2_OC_PIN_6 0x90BC
+#define USB2_OC_PIN_7 0x90C0
+
+#define USB3_OC_PIN_0 0x9124
+#define USB3_OC_PIN_1 0x9128
+#define USB3_OC_PIN_2 0x912C
+#define USB3_OC_PIN_3 0x9130
+#define USB3_OC_PIN_4 0x9134
+#define USB3_OC_PIN_5 0x9138
+#define USB3_OC_PIN_6 0x913C
+#define USB3_OC_PIN_7 0x9140
+
+#define USB_PORT_0 BIT(0)
+#define USB_PORT_1 BIT(1)
+#define USB_PORT_2 BIT(2)
+#define USB_PORT_3 BIT(3)
+#define USB_PORT_4 BIT(4)
+#define USB_PORT_5 BIT(5)
+#define USB_PORT_6 BIT(6)
+#define USB_PORT_7 BIT(7)
+#define USB_PORT_8 BIT(8)
+#define USB_PORT_9 BIT(9)
+#define USB_PORT_10 BIT(10)
+#define USB_PORT_11 BIT(11)
+#define USB_PORT_12 BIT(12)
+#define USB_PORT_13 BIT(13)
+#define USB_PORT_14 BIT(14)
+#define USB_PORT_15 BIT(15)
+#define USB_PORT_NONE 0
+#define OCCFGDONE BIT(31)
+
+struct usb_oc_mapping {
+ uint32_t pin;
+ uint32_t port;
+};
+
+void write_usb_oc_mapping(const struct usb_oc_mapping *config, uint8_t pins);
+void lock_oc_cfg(bool lock);
+
+#endif /* _XHCI_H_ */
diff --git a/src/soc/intel/xeon_sp/spr/romstage.c b/src/soc/intel/xeon_sp/spr/romstage.c
new file mode 100644
index 0000000000..b49972eee1
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/romstage.c
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <assert.h>
+#include <cpu/cpu.h>
+#include <cpu/intel/cpu_ids.h>
+#include <arch/romstage.h>
+#include <console/console.h>
+#include <cbmem.h>
+#include <drivers/vpd/vpd.h>
+#include <drivers/ocp/include/vpd.h>
+#include <security/intel/txt/txt.h>
+#include <fsp/api.h>
+#include <fsp/util.h>
+#include <hob_iiouds.h>
+#include <hob_memmap.h>
+#include <soc/romstage.h>
+#include <soc/pci_devs.h>
+#include <soc/intel/common/smbios.h>
+#include <string.h>
+#include <soc/soc_util.h>
+#include <soc/ddr.h>
+
+#include "chip.h"
+
+/* Initialize to all zero first */
+static UPD_IIO_PCIE_PORT_CONFIG spr_iio_bifur_table[CONFIG_MAX_SOCKET_UPD];
+static UINT8 deemphasis_list[CONFIG_MAX_SOCKET_UPD * MAX_IIO_PORTS_PER_SOCKET];
+
+void __weak mainboard_memory_init_params(FSPM_UPD *mupd)
+{
+ /* Default weak implementation */
+}
+
+bool __weak mainboard_dimm_slot_exists(uint8_t socket, uint8_t channel, uint8_t dimm)
+{
+ return false;
+}
+
+/*
+ * Search from VPD_RW first then VPD_RO for UPD config variables,
+ * overwrites them from VPD if it's found.
+ */
+static void config_upd_from_vpd(FSPM_UPD *mupd)
+{
+ uint8_t val;
+ int val_int, cxl_mode;
+
+ /* Send FSP log message to SOL */
+ if (vpd_get_bool(FSP_LOG, VPD_RW_THEN_RO, &val))
+ mupd->FspmConfig.SerialIoUartDebugEnable = val;
+ else {
+ printk(BIOS_INFO,
+ "Not able to get VPD %s, default set "
+ "SerialIoUartDebugEnable to %d\n",
+ FSP_LOG, FSP_LOG_DEFAULT);
+ mupd->FspmConfig.SerialIoUartDebugEnable = FSP_LOG_DEFAULT;
+ }
+
+ if (mupd->FspmConfig.SerialIoUartDebugEnable) {
+ /* FSP memory debug log level */
+ if (vpd_get_int(FSP_MEM_LOG_LEVEL, VPD_RW_THEN_RO, &val_int)) {
+ if (val_int < 0 || val_int > 4) {
+ printk(BIOS_DEBUG,
+ "Invalid serialDebugMsgLvl value from VPD: "
+ "%d\n",
+ val_int);
+ val_int = FSP_MEM_LOG_LEVEL_DEFAULT;
+ }
+ printk(BIOS_DEBUG, "Setting serialDebugMsgLvl to %d\n", val_int);
+ mupd->FspmConfig.serialDebugMsgLvl = (uint8_t)val_int;
+ } else {
+ printk(BIOS_INFO,
+ "Not able to get VPD %s, default set "
+ "DebugPrintLevel to %d\n",
+ FSP_MEM_LOG_LEVEL, FSP_MEM_LOG_LEVEL_DEFAULT);
+ mupd->FspmConfig.serialDebugMsgLvl = FSP_MEM_LOG_LEVEL_DEFAULT;
+ }
+ /* If serialDebugMsgLvl less than 1, disable FSP memory train results */
+ if (mupd->FspmConfig.serialDebugMsgLvl <= 1) {
+ printk(BIOS_DEBUG, "Setting serialDebugMsgLvlTrainResults to 0\n");
+ mupd->FspmConfig.serialDebugMsgLvlTrainResults = 0x0;
+ }
+ }
+
+ /* FSP Dfx PMIC Secure mode */
+ if (vpd_get_int(FSP_PMIC_SECURE_MODE, VPD_RW_THEN_RO, &val_int)) {
+ if (val_int < 0 || val_int > 2) {
+ printk(BIOS_DEBUG,
+ "Invalid PMIC secure mode value from VPD: "
+ "%d\n",
+ val_int);
+ val_int = FSP_PMIC_SECURE_MODE_DEFAULT;
+ }
+ printk(BIOS_DEBUG, "Setting PMIC secure mode to %d\n", val_int);
+ mupd->FspmConfig.DfxPmicSecureMode = (uint8_t)val_int;
+ } else {
+ printk(BIOS_INFO,
+ "Not able to get VPD %s, default set "
+ "PMIC secure mode to %d\n",
+ FSP_PMIC_SECURE_MODE, FSP_PMIC_SECURE_MODE_DEFAULT);
+ mupd->FspmConfig.DfxPmicSecureMode = FSP_PMIC_SECURE_MODE_DEFAULT;
+ }
+
+ cxl_mode = get_cxl_mode_from_vpd();
+ if (cxl_mode == CXL_SYSTEM_MEMORY || cxl_mode == CXL_SPM)
+ mupd->FspmConfig.DfxCxlType3LegacyEn = 1;
+ else /* Disable CXL */
+ mupd->FspmConfig.DfxCxlType3LegacyEn = 0;
+
+ if (CONFIG(INTEL_TXT)) {
+ /* Configure for error injection test */
+ mupd->FspmConfig.DFXEnable = skip_intel_txt_lockdown() ? 1 : 0;
+ }
+}
+
+/* Initialize non-zero default UPD values for IIO */
+static void initialize_iio_upd(FSPM_UPD *mupd)
+{
+ unsigned int port, socket;
+
+ mupd->FspmConfig.IioPcieConfigTablePtr = (UINT32)spr_iio_bifur_table;
+ mupd->FspmConfig.IioPcieConfigTableNumber = CONFIG_MAX_SOCKET_UPD;
+ UPD_IIO_PCIE_PORT_CONFIG *PciePortConfig =
+ (UPD_IIO_PCIE_PORT_CONFIG *)spr_iio_bifur_table;
+
+ /* Initialize non-zero default UPD values */
+ for (socket = 0; socket < CONFIG_MAX_SOCKET_UPD; socket++) {
+ for (port = 0; port < MAX_IIO_PORTS_PER_SOCKET; port++) {
+ PciePortConfig[socket].PcieMaxPayload[port] = 0x7; /* Auto */
+ PciePortConfig[socket].DfxDnTxPresetGen3[port] = 0xff; /* Auto */
+ }
+ PciePortConfig[socket].PcieGlobalAspm = 0x1; /* Enable ASPM */
+ PciePortConfig[socket].PcieMaxReadRequestSize = 0x5;
+ }
+
+ mupd->FspmConfig.DeEmphasisPtr = (UINT32)deemphasis_list;
+ mupd->FspmConfig.DeEmphasisNumber = CONFIG_MAX_SOCKET_UPD * MAX_IIO_PORTS_PER_SOCKET;
+ UINT8 *DeEmphasisConfig = (UINT8 *)deemphasis_list;
+
+ for (port = 0; port < CONFIG_MAX_SOCKET_UPD * MAX_IIO_PORTS_PER_SOCKET; port++)
+ DeEmphasisConfig[port] = 0x1;
+}
+
+void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version)
+{
+ FSP_M_CONFIG *m_cfg = &mupd->FspmConfig;
+ const config_t *config = config_of_soc();
+
+ m_cfg->DebugPrintLevel = 0xF;
+
+ m_cfg->DirectoryModeEn = 0x2;
+ const u8 KtiFpgaEnable[] = {0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1};
+ memcpy(m_cfg->KtiFpgaEnable, KtiFpgaEnable, sizeof(m_cfg->KtiFpgaEnable));
+
+ m_cfg->TscSyncEn = 0x1;
+
+ m_cfg->mmiohBase = 0x2000;
+ m_cfg->mmiohSize = 0x3;
+
+ m_cfg->BoardTypeBitmask = 0x11111133;
+
+ m_cfg->X2apic = config->x2apic;
+
+ printk(BIOS_INFO, "m_cfg->X2apic = 0x%x config->x2apic = 0x%x\n", m_cfg->X2apic,
+ config->x2apic);
+
+
+ m_cfg->serialDebugMsgLvl = 0x3;
+
+ m_cfg->VtdSupport = config->vtd_support;
+
+ m_cfg->SerialIoUartDebugIoBase = 0x3F8;
+
+ mupd->FspmConfig.AttemptFastBoot = 1;
+ mupd->FspmConfig.AttemptFastBootCold = 1;
+
+ /* Set Patrol Scrub UPD */
+ mupd->FspmConfig.PatrolScrubNotify = 0x1; /* 1:Enable at ReadyToBootFsp() */
+ mupd->FspmConfig.PatrolScrub = 0x2; /* 2:Enable during
+ NotifyPhase(EnumInitPhaseReadyToBoot) */
+ mupd->FspmConfig.ErrorCheckScrub = 1; /* Enable/Disable DDR5 Error Check
+ and Scrub (ECS) in FSP */
+ mupd->FspmConfig.PatrolScrubAddrMode = 1; /* 1:System Physical Address */
+ mupd->FspmConfig.PatrolScrubDuration = 24; /* unit is hour */
+
+ /* Disable below UPDs because those features should be implemented by coreboot */
+ mupd->FspmConfig.LockChipset = 0;
+ mupd->FspmConfig.ProcessorMsrLockControl = 0;
+ /* Don't set and signal MSR_BIOS_DONE in FSP since it should be done by coreboot */
+ mupd->FspmConfig.DfxDisableBiosDone = 1;
+
+ u32 cpu_id = cpu_get_cpuid();
+ if (cpu_id == (u32)CPUID_SAPPHIRERAPIDS_SP_D) {
+ printk(BIOS_DEBUG, "CPU is D stepping, setting package C state to C0/C1\n");
+ mupd->FspmConfig.CpuPmPackageCState = 0;
+ }
+ /* Set some common UPDs from VPD, mainboard can still override them if needed */
+ if (CONFIG(VPD))
+ config_upd_from_vpd(mupd);
+ initialize_iio_upd(mupd);
+ mainboard_memory_init_params(mupd);
+}
+
+static uint8_t get_error_correction_type(const uint8_t RasModesEnabled)
+{
+ switch (RasModesEnabled) {
+ case CH_INDEPENDENT:
+ return MEMORY_ARRAY_ECC_SINGLE_BIT;
+ case FULL_MIRROR_1LM:
+ case PARTIAL_MIRROR_1LM:
+ case FULL_MIRROR_2LM:
+ case PARTIAL_MIRROR_2LM:
+ return MEMORY_ARRAY_ECC_MULTI_BIT;
+ case RK_SPARE:
+ return MEMORY_ARRAY_ECC_SINGLE_BIT;
+ case CH_LOCKSTEP:
+ return MEMORY_ARRAY_ECC_SINGLE_BIT;
+ default:
+ return MEMORY_ARRAY_ECC_MULTI_BIT;
+ }
+}
+
+/* Save the DIMM information for SMBIOS table 17 */
+void save_dimm_info(void)
+{
+ struct dimm_info *dest_dimm;
+ struct memory_info *mem_info;
+ const struct SystemMemoryMapHob *hob;
+ MEMMAP_DIMM_DEVICE_INFO_STRUCT src_dimm;
+ int dimm_max, dimm_num = 0;
+ int index = 0;
+ uint8_t mem_dev_type;
+ uint16_t data_width;
+ uint32_t vdd_voltage;
+
+ hob = get_system_memory_map();
+ assert(hob != NULL);
+
+ /*
+ * Allocate CBMEM area for DIMM information used to populate SMBIOS
+ * table 17
+ */
+ mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info));
+ if (mem_info == NULL) {
+ printk(BIOS_ERR, "CBMEM entry for DIMM info missing\n");
+ return;
+ }
+ memset(mem_info, 0, sizeof(*mem_info));
+ /* According to EDS doc#611488, it's 4 TB per processor. */
+ mem_info->max_capacity_mib = 4 * MiB * CONFIG_MAX_SOCKET;
+ mem_info->number_of_devices = CONFIG_DIMM_MAX;
+ mem_info->ecc_type = get_error_correction_type(hob->RasModesEnabled);
+ dimm_max = ARRAY_SIZE(mem_info->dimm);
+ vdd_voltage = get_ddr_millivolt(hob->DdrVoltage);
+ for (int soc = 0; soc < CONFIG_MAX_SOCKET; soc++) {
+ for (int ch = 0; ch < MAX_CH; ch++) {
+ for (int dimm = 0; dimm < MAX_DIMM; dimm++) {
+ if (index >= dimm_max) {
+ printk(BIOS_WARNING, "Too many DIMMs info for %s.\n",
+ __func__);
+ return;
+ }
+
+ src_dimm = hob->Socket[soc].ChannelInfo[ch].DimmInfo[dimm];
+ if (src_dimm.Present) {
+ dest_dimm = &mem_info->dimm[index];
+ index++;
+ } else if (mainboard_dimm_slot_exists(soc, ch, dimm)) {
+ dest_dimm = &mem_info->dimm[index];
+ index++;
+ /* Save DIMM Locator information for SMBIOS Type 17 */
+ dest_dimm->dimm_size = 0;
+ dest_dimm->soc_num = soc;
+ dest_dimm->channel_num = ch;
+ dest_dimm->dimm_num = dimm;
+ continue;
+ } else {
+ /* Ignore DIMM that isn't present and doesn't exist on
+ the board. */
+ continue;
+ }
+ dest_dimm->max_speed_mts =
+ get_max_memory_speed(src_dimm.commonTck);
+ dest_dimm->configured_speed_mts = hob->memFreq;
+ dest_dimm->soc_num = soc;
+
+ if (hob->DramType == SPD_TYPE_DDR5) {
+ /* hard-coded memory device type as DDR5 */
+ mem_dev_type = 0x22;
+ data_width = 64;
+ } else {
+ /* hard-coded memory device type as DDR4 */
+ mem_dev_type = 0x1A;
+ data_width = 64;
+ }
+ dimm_info_fill(
+ dest_dimm, src_dimm.DimmSize << 6, mem_dev_type,
+ hob->memFreq, /* replaced by configured_speed_mts */
+ src_dimm.NumRanks,
+ ch, /* for mainboard locator string override */
+ dimm, /* for mainboard locator string override */
+ (const char *)&src_dimm.PartNumber[0],
+ sizeof(src_dimm.PartNumber),
+ (const uint8_t *)&src_dimm.serialNumber[0], data_width,
+ vdd_voltage, true, /* hard-coded as ECC supported */
+ src_dimm.VendorID, src_dimm.actKeyByte2, 0);
+ dimm_num++;
+ }
+ }
+ }
+
+ mem_info->dimm_cnt = index; /* Number of DIMM slots found */
+ printk(BIOS_DEBUG, "%d Installed DIMMs found\n", dimm_num);
+}
+
+void fsp_check_for_error(void)
+{
+ check_fsp_error();
+}
diff --git a/src/soc/intel/xeon_sp/spr/soc_util.c b/src/soc/intel/xeon_sp/spr/soc_util.c
new file mode 100644
index 0000000000..053b3ebeca
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/soc_util.c
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <assert.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <hob_cxlnode.h>
+#include <intelblocks/cpulib.h>
+#include <soc/cpu.h>
+#include <soc/msr.h>
+#include <soc/numa.h>
+#include <soc/pci_devs.h>
+#include <soc/soc_util.h>
+#include <soc/util.h>
+#include <stdlib.h>
+#include <string.h>
+
+const EWL_PRIVATE_DATA *get_ewl_hob(void)
+{
+ size_t hob_size;
+ static const EWL_PRIVATE_DATA *hob;
+ const uint8_t ewl_id_hob_guid[16] = FSP_HOB_EWLID_GUID;
+
+ if (hob != NULL)
+ return hob;
+
+ hob = fsp_find_extension_hob_by_guid(ewl_id_hob_guid, &hob_size);
+ assert(hob != NULL && hob_size != 0);
+ return hob;
+}
+
+const SYSTEM_INFO_VAR *get_system_info_hob(void)
+{
+ size_t hob_size;
+ static const SYSTEM_INFO_VAR *hob;
+ const uint8_t system_info_hob_guid[16] = FSP_HOB_SYSTEMINFO_GUID;
+
+ if (hob != NULL)
+ return hob;
+
+ hob = fsp_find_extension_hob_by_guid(system_info_hob_guid, &hob_size);
+ assert(hob != NULL && hob_size != 0);
+ return hob;
+}
+
+const struct SystemMemoryMapHob *get_system_memory_map(void)
+{
+ size_t hob_size;
+ const uint8_t mem_hob_guid[16] = FSP_SYSTEM_MEMORYMAP_HOB_GUID;
+ const struct SystemMemoryMapHob **memmap_addr;
+
+ memmap_addr = (const struct SystemMemoryMapHob **)fsp_find_extension_hob_by_guid(
+ mem_hob_guid, &hob_size);
+ /* hob_size is the size of the 8-byte address not the hob data */
+ assert(memmap_addr != NULL && hob_size != 0);
+ /* assert the pointer to the hob is not NULL */
+ assert(*memmap_addr != NULL);
+
+ return *memmap_addr;
+}
+
+const struct SystemMemoryMapElement *get_system_memory_map_elment(uint8_t *num)
+{
+ const struct SystemMemoryMapHob *hob = get_system_memory_map();
+ if (!hob)
+ return NULL;
+
+ *num = hob->numberEntries;
+ return hob->Element;
+}
+
+bool is_iio_stack_res(const STACK_RES *res)
+{
+ return res->Personality == TYPE_UBOX_IIO || res->Personality == TYPE_DINO;
+}
+
+/*
+ * Given a stack resource, figure out whether the corresponding stack has
+ * CXL device.
+ * It goes through pds (proximity domains) structure to see if there is any
+ * generic initiator has device with bus # falls between bus base and
+ * bus limit.
+ */
+bool is_iio_cxl_stack_res(const STACK_RES *res)
+{
+ for (uint8_t i = 0; i < pds.num_pds; i++) {
+ if (pds.pds[i].pd_type == PD_TYPE_PROCESSOR)
+ continue;
+
+ uint32_t bus = pds.pds[i].device_handle >> 20;
+ if (bus >= res->BusBase && bus <= res->BusLimit)
+ return true;
+ }
+
+ return false;
+}
+
+const CXL_NODE_SOCKET *get_cxl_node(void)
+{
+ size_t hob_size;
+ static const CXL_NODE_SOCKET *hob;
+ static bool hob_check = 0;
+ const uint8_t fsp_hob_cxl_node_socket_guid[16] = FSP_HOB_CXLNODE_GUID;
+
+ if (hob_check == 1)
+ return hob;
+
+ hob = fsp_find_extension_hob_by_guid(fsp_hob_cxl_node_socket_guid, &hob_size);
+ hob_check = 1;
+ if (hob == NULL || hob_size == 0)
+ printk(BIOS_DEBUG,
+ "FSP_HOB_CXLNODE_GUID not found: CXL may not be installed\n");
+ return hob;
+}
+
+uint8_t get_cxl_node_count(void)
+{
+ const CXL_NODE_SOCKET *hob = get_cxl_node();
+ uint8_t count = 0;
+
+ if (hob != NULL) {
+ for (uint8_t skt_id = 0; skt_id < MAX_SOCKET; skt_id++)
+ count += hob[skt_id].CxlNodeCount;
+ }
+
+ return count;
+}
+
+uint32_t get_socket_stack_busno(uint32_t socket, uint32_t stack)
+{
+ const IIO_UDS *hob = get_iio_uds();
+
+ assert(socket < hob->SystemStatus.numCpus && stack < MAX_LOGIC_IIO_STACK);
+
+ return hob->PlatformData.IIO_resource[socket].StackRes[stack].BusBase;
+}
+
+uint32_t get_ubox_busno(uint32_t socket, uint8_t offset)
+{
+ const IIO_UDS *hob = get_iio_uds();
+
+ assert(socket < hob->SystemStatus.numCpus);
+ for (int stack = 0; stack < MAX_LOGIC_IIO_STACK; ++stack) {
+ if (hob->PlatformData.IIO_resource[socket].StackRes[stack].Personality
+ == TYPE_UBOX)
+ return (hob->PlatformData.IIO_resource[socket].StackRes[stack].BusBase
+ + offset);
+ }
+ die("Unable to locate UBOX BUS NO");
+}
+
+uint32_t get_socket_ubox_busno(uint32_t socket)
+{
+ return get_ubox_busno(socket, UNCORE_BUS_1);
+}
+
+/* mainboard can override this function for their own handling, such as write a BMC SEL. */
+void __weak mainboard_fsp_error_handle(void)
+{
+ die("ERROR: FSP reported an error(s) after running!");
+}
+
+void check_fsp_error(void)
+{
+ bool fsp_found_error = fsp_find_error_info();
+
+ if (fsp_found_error)
+ mainboard_fsp_error_handle();
+}
+
+void bios_done_msr(void *unused)
+{
+ msr_t msr = rdmsr(MSR_BIOS_DONE);
+ if (!(msr.lo & XEON_SP_ENABLE_IA_UNTRUSTED)) { /* if already locked skip update */
+ msr.lo |= XEON_SP_ENABLE_IA_UNTRUSTED;
+ wrmsr(MSR_BIOS_DONE, msr);
+ }
+}
diff --git a/src/soc/intel/xeon_sp/spr/upd_display.c b/src/soc/intel/xeon_sp/spr/upd_display.c
new file mode 100644
index 0000000000..078624db15
--- /dev/null
+++ b/src/soc/intel/xeon_sp/spr/upd_display.c
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <fsp/util.h>
+#include <lib.h>
+
+#define DUMP_UPD(old, new, field) \
+ fsp_display_upd_value(#field, sizeof(old->field), old->field, new->field)
+
+static void soc_display_fspm_upd_iio(const FSPM_UPD *mupd)
+{
+ int port, socket;
+
+ UPD_IIO_PCIE_PORT_CONFIG *PciePortConfig =
+ (UPD_IIO_PCIE_PORT_CONFIG *)mupd->FspmConfig.IioPcieConfigTablePtr;
+
+ printk(BIOS_SPEW, "UPD values for IIO:\n");
+ for (socket = 0; socket < mupd->FspmConfig.IioPcieConfigTableNumber; socket++) {
+ printk(BIOS_SPEW, "Socket: %d\n", socket);
+ for (port = 0; port < MAX_IIO_PORTS_PER_SOCKET; port++) {
+ printk(BIOS_SPEW, "port: %d\n", port);
+
+ printk(BIOS_SPEW, "\tSLOTEIP: 0x%x\n",
+ PciePortConfig[socket].SLOTEIP[port]);
+ printk(BIOS_SPEW, "\tSLOTHPCAP: 0x%x\n",
+ PciePortConfig[socket].SLOTHPCAP[port]);
+ printk(BIOS_SPEW, "\tSLOTHPSUP: 0x%x\n",
+ PciePortConfig[socket].SLOTHPSUP[port]);
+ printk(BIOS_SPEW, "\tSLOTPIP: 0x%x\n",
+ PciePortConfig[socket].SLOTPIP[port]);
+ printk(BIOS_SPEW, "\tSLOTAIP: 0x%x\n",
+ PciePortConfig[socket].SLOTAIP[port]);
+ printk(BIOS_SPEW, "\tSLOTMRLSP: 0x%x\n",
+ PciePortConfig[socket].SLOTMRLSP[port]);
+ printk(BIOS_SPEW, "\tSLOTPCP: 0x%x\n",
+ PciePortConfig[socket].SLOTPCP[port]);
+ printk(BIOS_SPEW, "\tSLOTABP: 0x%x\n",
+ PciePortConfig[socket].SLOTABP[port]);
+ printk(BIOS_SPEW, "\tSLOTIMP: 0x%x\n",
+ PciePortConfig[socket].SLOTIMP[port]);
+ printk(BIOS_SPEW, "\tSLOTSPLS: 0x%x\n",
+ PciePortConfig[socket].SLOTSPLS[port]);
+ printk(BIOS_SPEW, "\tSLOTSPLV: 0x%x\n",
+ PciePortConfig[socket].SLOTSPLV[port]);
+ printk(BIOS_SPEW, "\tSLOTPSP: 0x%x\n",
+ PciePortConfig[socket].SLOTPSP[port]);
+ printk(BIOS_SPEW, "\tVppEnabled: 0x%x\n",
+ PciePortConfig[socket].VppEnabled[port]);
+ printk(BIOS_SPEW, "\tVppPort: 0x%x\n",
+ PciePortConfig[socket].VppPort[port]);
+ printk(BIOS_SPEW, "\tVppAddress: 0x%x\n",
+ PciePortConfig[socket].VppAddress[port]);
+ printk(BIOS_SPEW, "\tMuxAddress: 0x%x\n",
+ PciePortConfig[socket].MuxAddress[port]);
+ printk(BIOS_SPEW, "\tChannelID: 0x%x\n",
+ PciePortConfig[socket].ChannelID[port]);
+ printk(BIOS_SPEW, "\tPciePortEnable: 0x%x\n",
+ PciePortConfig[socket].PciePortEnable[port]);
+ printk(BIOS_SPEW, "\tPEXPHIDE: 0x%x\n",
+ PciePortConfig[socket].PEXPHIDE[port]);
+ printk(BIOS_SPEW, "\tHidePEXPMenu: 0x%x\n",
+ PciePortConfig[socket].HidePEXPMenu[port]);
+ printk(BIOS_SPEW, "\tPciePortOwnership: 0x%x\n",
+ PciePortConfig[socket].PciePortOwnership[port]);
+ printk(BIOS_SPEW, "\tRetimerConnectCount: 0x%x\n",
+ PciePortConfig[socket].RetimerConnectCount[port]);
+ printk(BIOS_SPEW, "\tPcieHotPlugOnPort: 0x%x\n",
+ PciePortConfig[socket].PcieHotPlugOnPort[port]);
+ printk(BIOS_SPEW, "\tVMDPortEnable: 0x%x\n",
+ PciePortConfig[socket].VMDPortEnable[port]);
+ printk(BIOS_SPEW, "\tPcieMaxPayload: 0x%x\n",
+ PciePortConfig[socket].PcieMaxPayload[port]);
+ printk(BIOS_SPEW, "\tPciePortLinkSpeed: 0x%x\n",
+ PciePortConfig[socket].PciePortLinkSpeed[port]);
+ printk(BIOS_SPEW, "\tDfxDnTxPresetGen3: 0x%x\n",
+ PciePortConfig[socket].DfxDnTxPresetGen3[port]);
+ }
+
+ for (port = 0; port < MAX_VMD_STACKS_PER_SOCKET; port++) {
+ printk(BIOS_SPEW, "port: %d\n", port);
+ printk(BIOS_SPEW, "\tVMDEnabled: 0x%x\n",
+ PciePortConfig[socket].VMDEnabled[port]);
+ printk(BIOS_SPEW, "\tVMDHotPlugEnable: 0x%x\n",
+ PciePortConfig[socket].VMDHotPlugEnable[port]);
+ }
+ printk(BIOS_SPEW, "ConfigIOU[0]: 0x%x\n", PciePortConfig[socket].ConfigIOU[0]);
+ printk(BIOS_SPEW, "ConfigIOU[1]: 0x%x\n", PciePortConfig[socket].ConfigIOU[1]);
+ printk(BIOS_SPEW, "ConfigIOU[2]: 0x%x\n", PciePortConfig[socket].ConfigIOU[2]);
+ printk(BIOS_SPEW, "ConfigIOU[3]: 0x%x\n", PciePortConfig[socket].ConfigIOU[3]);
+ printk(BIOS_SPEW, "ConfigIOU[4]: 0x%x\n", PciePortConfig[socket].ConfigIOU[4]);
+ printk(BIOS_SPEW, "PcieGlobalAspm: 0x%x\n",
+ PciePortConfig[socket].PcieGlobalAspm);
+ printk(BIOS_SPEW, "PcieMaxReadRequestSize: 0x%x\n",
+ PciePortConfig[socket].PcieMaxReadRequestSize);
+ }
+
+ UINT8 *DeEmphasisConfig = (UINT8 *)mupd->FspmConfig.DeEmphasisPtr;
+ for (port = 0; port < mupd->FspmConfig.DeEmphasisNumber; port++) {
+ printk(BIOS_SPEW, "port: %d, DeEmphasisConfig: 0x%x\n", port,
+ DeEmphasisConfig[port]);
+ }
+}
+
+/* Display the UPD parameters for MemoryInit */
+void soc_display_fspm_upd_params(const FSPM_UPD *fspm_old_upd, const FSPM_UPD *fspm_new_upd)
+{
+ const FSP_M_CONFIG *new;
+ const FSP_M_CONFIG *old;
+
+ old = &fspm_old_upd->FspmConfig;
+ new = &fspm_new_upd->FspmConfig;
+
+ printk(BIOS_DEBUG, "UPD values for MemoryInit:\n");
+ DUMP_UPD(old, new, DebugPrintLevel);
+ DUMP_UPD(old, new, DfxCxlHeaderBypass);
+ DUMP_UPD(old, new, DfxCxlSecLvl);
+
+ printk(BIOS_DEBUG, " Dump of original MemoryInit UPD:\n");
+ hexdump(fspm_old_upd, sizeof(*fspm_old_upd));
+
+ printk(BIOS_DEBUG, " Dump of updated MemoryInit UPD:\n");
+ hexdump(fspm_new_upd, sizeof(*fspm_new_upd));
+ if (CONFIG(DISPLAY_UPD_IIO_DATA))
+ soc_display_fspm_upd_iio(fspm_new_upd);
+}
+
+/* Display the UPD parameters for SiliconInit */
+void soc_display_fsps_upd_params(const FSPS_UPD *fsps_old_upd, const FSPS_UPD *fsps_new_upd)
+{
+ const FSP_S_CONFIG *new;
+ const FSP_S_CONFIG *old;
+
+ old = &fsps_old_upd->FspsConfig;
+ new = &fsps_new_upd->FspsConfig;
+
+ printk(BIOS_DEBUG, "UPD values for SiliconInit:\n");
+
+ hexdump(fsps_new_upd, sizeof(*fsps_new_upd));
+}