summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/meteorlake/Kconfig130
-rw-r--r--src/soc/intel/meteorlake/Makefile.inc37
-rw-r--r--src/soc/intel/meteorlake/acpi.c257
-rw-r--r--src/soc/intel/meteorlake/chip.c185
-rw-r--r--src/soc/intel/meteorlake/cpu.c161
-rw-r--r--src/soc/intel/meteorlake/elog.c220
-rw-r--r--src/soc/intel/meteorlake/finalize.c88
-rw-r--r--src/soc/intel/meteorlake/fsp_params.c486
-rw-r--r--src/soc/intel/meteorlake/gspi.c15
-rw-r--r--src/soc/intel/meteorlake/i2c.c43
-rw-r--r--src/soc/intel/meteorlake/include/soc/cpu.h25
-rw-r--r--src/soc/intel/meteorlake/include/soc/iomap.h8
-rw-r--r--src/soc/intel/meteorlake/include/soc/irq.h16
-rw-r--r--src/soc/intel/meteorlake/include/soc/itss.h13
-rw-r--r--src/soc/intel/meteorlake/include/soc/me.h45
-rw-r--r--src/soc/intel/meteorlake/include/soc/nvs.h8
-rw-r--r--src/soc/intel/meteorlake/include/soc/p2sb.h2
-rw-r--r--src/soc/intel/meteorlake/include/soc/pci_devs.h2
-rw-r--r--src/soc/intel/meteorlake/include/soc/pcie.h10
-rw-r--r--src/soc/intel/meteorlake/include/soc/ramstage.h14
-rw-r--r--src/soc/intel/meteorlake/include/soc/serialio.h35
-rw-r--r--src/soc/intel/meteorlake/include/soc/soc_info.h11
-rw-r--r--src/soc/intel/meteorlake/include/soc/tcss.h16
-rw-r--r--src/soc/intel/meteorlake/include/soc/usb.h154
-rw-r--r--src/soc/intel/meteorlake/lockdown.c60
-rw-r--r--src/soc/intel/meteorlake/me.c167
-rw-r--r--src/soc/intel/meteorlake/p2sb.c14
-rw-r--r--src/soc/intel/meteorlake/pcie_rp.c29
-rw-r--r--src/soc/intel/meteorlake/pmc.c195
-rw-r--r--src/soc/intel/meteorlake/pmutil.c265
-rw-r--r--src/soc/intel/meteorlake/retimer.c32
-rw-r--r--src/soc/intel/meteorlake/smihandler.c30
-rw-r--r--src/soc/intel/meteorlake/soc_info.c71
-rw-r--r--src/soc/intel/meteorlake/soundwire.c72
-rw-r--r--src/soc/intel/meteorlake/spi.c25
-rw-r--r--src/soc/intel/meteorlake/systemagent.c102
-rw-r--r--src/soc/intel/meteorlake/tcss.c8
-rw-r--r--src/soc/intel/meteorlake/uart.c12
-rw-r--r--src/soc/intel/meteorlake/xhci.c39
39 files changed, 3095 insertions, 7 deletions
diff --git a/src/soc/intel/meteorlake/Kconfig b/src/soc/intel/meteorlake/Kconfig
index ae612ec7e3..cd543ee922 100644
--- a/src/soc/intel/meteorlake/Kconfig
+++ b/src/soc/intel/meteorlake/Kconfig
@@ -1,36 +1,86 @@
config SOC_INTEL_METEORLAKE
bool
+ help
+ Intel Meteorlake support
if SOC_INTEL_METEORLAKE
config CPU_SPECIFIC_OPTIONS
def_bool y
+ select ACPI_INTEL_HARDWARE_SLEEP_VALUES
select ARCH_X86
select BOOT_DEVICE_SUPPORTS_WRITES
- select INTEL_DESCRIPTOR_MODE_CAPABLE
select CACHE_MRC_SETTINGS
select CPU_INTEL_COMMON
+ select CPU_INTEL_FIRMWARE_INTERFACE_TABLE
+ select CPU_SUPPORTS_INTEL_TME
+ select CPU_SUPPORTS_PM_TIMER_EMULATION
+ select DRIVERS_INTEL_USB4_RETIMER
+ select FSP_COMPRESS_FSP_S_LZ4
+ select FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW
select FSP_M_XIP
+ select FSP_STATUS_GLOBAL_RESET_REQUIRED_3
+ select GENERIC_GPIO_LIB
+ select HAVE_FSP_GOP
+ select INTEL_DESCRIPTOR_MODE_CAPABLE
+ select HAVE_SMI_HANDLER
select IDT_IN_EVERY_STAGE
select INTEL_CAR_NEM
+ select INTEL_GMA_ACPI
select INTEL_GMA_ADD_VBT if RUN_FSP_GOP
select IOAPIC
- select MICROCODE_BLOB_UNDISCLOSED
+ select INTEL_TME
+ select USE_INTEL_FSP_MP_INIT
select MRC_SETTINGS_PROTECT
+ select PARALLEL_MP_AP_WORK
+ select MICROCODE_BLOB_UNDISCLOSED
+ select PLATFORM_USES_FSP2_3
+ select PMC_GLOBAL_RESET_ENABLE_LOCK
select SOC_INTEL_COMMON
select SOC_INTEL_COMMON_BLOCK
select SOC_INTEL_COMMON_BLOCK_CAR
select SOC_INTEL_COMMON_BLOCK_CHIP_CONFIG
select SOC_INTEL_COMMON_BLOCK_CPU
+ select SOC_INTEL_COMMON_BLOCK_CPU_MPINIT
+ select SOC_INTEL_COMMON_BLOCK_CPU_SMMRELOCATE
+ select SOC_INTEL_COMMON_BLOCK_DTT
+ select SOC_INTEL_COMMON_BLOCK_GPIO_DUAL_ROUTE_SUPPORT
select SOC_INTEL_COMMON_BLOCK_GSPI_VERSION_2
+ select SOC_INTEL_COMMON_BLOCK_HDA
+ select SOC_INTEL_COMMON_BLOCK_HECI1_DISABLE_USING_PMC_IPC if DISABLE_HECI1_AT_PRE_BOOT
+ select SOC_INTEL_COMMON_BLOCK_IPU
+ select SOC_INTEL_COMMON_BLOCK_IOE_P2SB
select SOC_INTEL_COMMON_BLOCK_MEMINIT
+ select SOC_INTEL_COMMON_BLOCK_PCIE_RTD3
+ select SOC_INTEL_COMMON_BLOCK_PMC_EPOC
+ select SOC_INTEL_COMMON_BLOCK_POWER_LIMIT
select SOC_INTEL_COMMON_BLOCK_SA
+ select SOC_INTEL_COMMON_BLOCK_SMM
+ select SOC_INTEL_COMMON_BLOCK_SMM_IO_TRAP
+ select SOC_INTEL_COMMON_BLOCK_TCSS
+ select SOC_INTEL_COMMON_BLOCK_THERMAL_BEHIND_PMC
+ select SOC_INTEL_COMMON_BLOCK_USB4
+ select SOC_INTEL_COMMON_BLOCK_USB4_PCIE
+ select SOC_INTEL_COMMON_BLOCK_USB4_XHCI
+ select SOC_INTEL_COMMON_BLOCK_XHCI
+ select SOC_INTEL_COMMON_BLOCK_XHCI_ELOG
+ select SOC_INTEL_COMMON_BASECODE
+ select SOC_INTEL_COMMON_FSP_RESET
select SOC_INTEL_COMMON_PCH_BASE
select SOC_INTEL_COMMON_RESET
+ select SOC_INTEL_COMMON_BLOCK_IOC
+ select SOC_INTEL_CSE_SET_EOP
+ select SOC_INTEL_MEM_MAPPED_PM_CONFIGURATION
select SSE2
select SUPPORT_CPU_UCODE_IN_CBFS
select TSC_MONOTONIC_TIMER
select UDELAY_TSC
+ select UDK_202111_BINDING
+ select DISPLAY_FSP_VERSION_INFO
+
+config MAX_CPUS
+ int
+ default 22
config DCACHE_RAM_BASE
default 0xfef00000
@@ -58,9 +108,19 @@ config FSP_TEMP_RAM_SIZE
Refer to Platform FSP integration guide document to know
the exact FSP requirement for Heap setup.
+config CHIPSET_DEVICETREE
+ string
+ default "soc/intel/meteorlake/chipset.cb"
+
+config EXT_BIOS_WIN_BASE
+ default 0xf8000000
+
+config EXT_BIOS_WIN_SIZE
+ default 0x2000000
+
config IFD_CHIPSET
string
- default "mtl"
+ default "ifd2"
config IED_REGION_SIZE
hex
@@ -70,6 +130,47 @@ config HEAP_SIZE
hex
default 0x10000
+# Intel recommends reserving the following resources per PCIe TBT root port,
+# from ADL BIOS Spec (doc #627270) Revision 0.6.0 Section 7.2.5.1.5
+# - 42 buses
+# - 194 MiB Non-prefetchable memory
+# - 448 MiB Prefetchable memory
+if SOC_INTEL_ENABLE_USB4_PCIE_RESOURCES
+
+config PCIEXP_HOTPLUG_BUSES
+ int
+ default 42
+
+config PCIEXP_HOTPLUG_MEM
+ hex
+ default 0xc200000
+
+config PCIEXP_HOTPLUG_PREFETCH_MEM
+ hex
+ default 0x1c000000
+
+endif # SOC_INTEL_ENABLE_USB4_PCIE_RESOURCES
+
+config MAX_TBT_ROOT_PORTS
+ int
+ default 4
+
+config MAX_ROOT_PORTS
+ int
+ default 12
+
+config MAX_PCIE_CLOCK_SRC
+ int
+ default 9
+
+config SMM_TSEG_SIZE
+ hex
+ default 0x800000
+
+config SMM_RESERVED_SIZE
+ hex
+ default 0x200000
+
config PCR_BASE_ADDRESS
hex
default 0xe0000000
@@ -106,11 +207,23 @@ config SOC_INTEL_UART_DEV_MAX
int
default 3
+config SOC_INTEL_USB2_DEV_MAX
+ int
+ default 10
+
+config SOC_INTEL_USB3_DEV_MAX
+ int
+ default 2
+
config CONSOLE_UART_BASE_ADDRESS
hex
- default 0xfe03e000
+ default 0xfe02c000
depends on INTEL_LPSS_UART_FOR_CONSOLE
+config VBT_DATA_SIZE_KB
+ int
+ default 9
+
# Clock divider parameters for 115200 baud rate
# Baudrate = (UART source clock * M) /(N *16)
# MTL UART source clock: 120MHz
@@ -123,6 +236,7 @@ config SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL
default 0x7fff
config VBOOT
+ select VBOOT_SEPARATE_VERSTAGE
select VBOOT_MUST_REQUEST_DISPLAY
select VBOOT_STARTS_IN_BOOTBLOCK
select VBOOT_VBNV_CMOS
@@ -141,7 +255,7 @@ config CBFS_SIZE
config PRERAM_CBMEM_CONSOLE_SIZE
hex
- default 0x2000
+ default 0x1400
config FSP_HEADER_PATH
string "Location of FSP headers"
@@ -156,7 +270,7 @@ config SOC_INTEL_METEORLAKE_DEBUG_CONSENT
int "Debug Consent for MTL"
# USB DBC is more common for developers so make this default to 3 if
# SOC_INTEL_DEBUG_CONSENT=y
- default 3 if SOC_INTEL_DEBUG_CONSENT
+ default 5 if SOC_INTEL_DEBUG_CONSENT
default 0
help
This is to control debug interface on SOC.
@@ -180,4 +294,8 @@ config MRC_CHANNEL_WIDTH
int
default 16
+config SOC_INTEL_GFX_FRAMEBUFFER_OFFSET
+ hex
+ default 0x800000
+
endif
diff --git a/src/soc/intel/meteorlake/Makefile.inc b/src/soc/intel/meteorlake/Makefile.inc
index cedb8b4756..3c0754d42b 100644
--- a/src/soc/intel/meteorlake/Makefile.inc
+++ b/src/soc/intel/meteorlake/Makefile.inc
@@ -4,18 +4,55 @@ subdirs-y += romstage
subdirs-y += ../../../cpu/intel/microcode
subdirs-y += ../../../cpu/intel/turbo
+# all (bootblock, verstage, romstage, postcar, ramstage)
+all-y += gspi.c
+all-y += i2c.c
+all-y += pmutil.c
+all-y += spi.c
+all-y += uart.c
+
bootblock-y += bootblock/bootblock.c
bootblock-y += bootblock/ioe_die.c
bootblock-y += bootblock/report_platform.c
bootblock-y += bootblock/soc_die.c
bootblock-y += espi.c
bootblock-y += p2sb.c
+bootblock-y += soc_info.c
romstage-y += espi.c
romstage-y += meminit.c
+romstage-y += pcie_rp.c
romstage-y += reset.c
+romstage-y += soc_info.c
+ramstage-y += acpi.c
+ramstage-y += chip.c
+ramstage-y += cpu.c
+ramstage-y += elog.c
+ramstage-y += espi.c
+ramstage-y += finalize.c
+ramstage-y += fsp_params.c
+ramstage-y += lockdown.c
+ramstage-y += me.c
+ramstage-y += p2sb.c
+ramstage-y += pcie_rp.c
+ramstage-y += pmc.c
+ramstage-y += reset.c
+ramstage-y += retimer.c
+ramstage-y += soundwire.c
+ramstage-y += systemagent.c
+ramstage-y += tcss.c
+ramstage-y += xhci.c
+ramstage-y += soc_info.c
+smm-y += elog.c
+smm-y += p2sb.c
+smm-y += pmutil.c
+smm-y += smihandler.c
+smm-y += soc_info.c
+smm-y += uart.c
+smm-y += xhci.c
CPPFLAGS_common += -I$(src)/soc/intel/meteorlake
CPPFLAGS_common += -I$(src)/soc/intel/meteorlake/include
+CFLAGS_common += -fshort-wchar
endif
diff --git a/src/soc/intel/meteorlake/acpi.c b/src/soc/intel/meteorlake/acpi.c
new file mode 100644
index 0000000000..a14ff429a1
--- /dev/null
+++ b/src/soc/intel/meteorlake/acpi.c
@@ -0,0 +1,257 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpi.h>
+#include <acpi/acpi_gnvs.h>
+#include <acpi/acpigen.h>
+#include <device/mmio.h>
+#include <arch/smp/mpspec.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci_ops.h>
+#include <fw_config.h>
+#include <intelblocks/cpulib.h>
+#include <intelblocks/pmclib.h>
+#include <intelblocks/acpi.h>
+#include <soc/cpu.h>
+#include <soc/iomap.h>
+#include <soc/nvs.h>
+#include <soc/pci_devs.h>
+#include <soc/pm.h>
+#include <soc/soc_chip.h>
+#include <soc/systemagent.h>
+#include <string.h>
+#include <types.h>
+
+/*
+ * List of supported C-states in this processor.
+ */
+enum {
+ C_STATE_C0, /* 0 */
+ C_STATE_C1, /* 1 */
+ C_STATE_C1E, /* 2 */
+ C_STATE_C6_SHORT_LAT, /* 3 */
+ C_STATE_C6_LONG_LAT, /* 4 */
+ C_STATE_C7_SHORT_LAT, /* 5 */
+ C_STATE_C7_LONG_LAT, /* 6 */
+ C_STATE_C7S_SHORT_LAT, /* 7 */
+ C_STATE_C7S_LONG_LAT, /* 8 */
+ C_STATE_C8, /* 9 */
+ C_STATE_C9, /* 10 */
+ C_STATE_C10, /* 11 */
+ NUM_C_STATES
+};
+
+static const acpi_cstate_t cstate_map[NUM_C_STATES] = {
+ [C_STATE_C0] = {},
+ [C_STATE_C1] = {
+ .latency = C1_LATENCY,
+ .power = C1_POWER,
+ .resource = MWAIT_RES(0, 0),
+ },
+ [C_STATE_C1E] = {
+ .latency = C1_LATENCY,
+ .power = C1_POWER,
+ .resource = MWAIT_RES(0, 1),
+ },
+ [C_STATE_C6_SHORT_LAT] = {
+ .latency = C6_LATENCY,
+ .power = C6_POWER,
+ .resource = MWAIT_RES(2, 0),
+ },
+ [C_STATE_C6_LONG_LAT] = {
+ .latency = C6_LATENCY,
+ .power = C6_POWER,
+ .resource = MWAIT_RES(2, 1),
+ },
+ [C_STATE_C7_SHORT_LAT] = {
+ .latency = C7_LATENCY,
+ .power = C7_POWER,
+ .resource = MWAIT_RES(3, 0),
+ },
+ [C_STATE_C7_LONG_LAT] = {
+ .latency = C7_LATENCY,
+ .power = C7_POWER,
+ .resource = MWAIT_RES(3, 1),
+ },
+ [C_STATE_C7S_SHORT_LAT] = {
+ .latency = C7_LATENCY,
+ .power = C7_POWER,
+ .resource = MWAIT_RES(3, 2),
+ },
+ [C_STATE_C7S_LONG_LAT] = {
+ .latency = C7_LATENCY,
+ .power = C7_POWER,
+ .resource = MWAIT_RES(3, 3),
+ },
+ [C_STATE_C8] = {
+ .latency = C8_LATENCY,
+ .power = C8_POWER,
+ .resource = MWAIT_RES(4, 0),
+ },
+ [C_STATE_C9] = {
+ .latency = C9_LATENCY,
+ .power = C9_POWER,
+ .resource = MWAIT_RES(5, 0),
+ },
+ [C_STATE_C10] = {
+ .latency = C10_LATENCY,
+ .power = C10_POWER,
+ .resource = MWAIT_RES(6, 0),
+ },
+};
+
+static int cstate_set_non_s0ix[] = {
+ C_STATE_C1,
+ C_STATE_C6_LONG_LAT,
+ C_STATE_C7S_LONG_LAT
+};
+
+static int cstate_set_s0ix[] = {
+ C_STATE_C1,
+ C_STATE_C7S_LONG_LAT,
+ C_STATE_C10
+};
+
+const acpi_cstate_t *soc_get_cstate_map(size_t *entries)
+{
+ static acpi_cstate_t map[MAX(ARRAY_SIZE(cstate_set_s0ix),
+ ARRAY_SIZE(cstate_set_non_s0ix))];
+ int *set;
+ int i;
+
+ config_t *config = config_of_soc();
+
+ int is_s0ix_enable = config->s0ix_enable;
+
+ if (is_s0ix_enable) {
+ *entries = ARRAY_SIZE(cstate_set_s0ix);
+ set = cstate_set_s0ix;
+ } else {
+ *entries = ARRAY_SIZE(cstate_set_non_s0ix);
+ set = cstate_set_non_s0ix;
+ }
+
+ for (i = 0; i < *entries; i++) {
+ map[i] = cstate_map[set[i]];
+ map[i].ctype = i + 1;
+ }
+ return map;
+}
+
+void soc_power_states_generation(int core_id, int cores_per_package)
+{
+ config_t *config = config_of_soc();
+
+ if (config->eist_enable)
+ /* Generate P-state tables */
+ generate_p_state_entries(core_id, cores_per_package);
+}
+
+void soc_fill_fadt(acpi_fadt_t *fadt)
+{
+ const uint16_t pmbase = ACPI_BASE_ADDRESS;
+
+ config_t *config = config_of_soc();
+
+ fadt->pm_tmr_blk = pmbase + PM1_TMR;
+ fadt->pm_tmr_len = 4;
+ fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8;
+ fadt->x_pm_tmr_blk.bit_offset = 0;
+ fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+ fadt->x_pm_tmr_blk.addrl = pmbase + PM1_TMR;
+ fadt->x_pm_tmr_blk.addrh = 0x0;
+
+ if (config->s0ix_enable)
+ fadt->flags |= ACPI_FADT_LOW_PWR_IDLE_S0;
+}
+
+uint32_t soc_read_sci_irq_select(void)
+{
+ return read32((void *)soc_read_pmc_base() + IRQ_REG);
+}
+
+static unsigned long soc_fill_dmar(unsigned long current)
+{
+ unsigned long tmp;
+ const struct device *const igfx_dev = pcidev_path_on_root(PCI_DEVFN_IGD);
+ const uint64_t gfxvtbar = MCHBAR64(GFXVTBAR) & VTBAR_MASK;
+ const bool gfxvten = MCHBAR32(GFXVTBAR) & VTBAR_ENABLED;
+
+ printk(BIOS_DEBUG, "%s - gfxvtbar:0x%llx 0x%x\n",
+ __func__, gfxvtbar, MCHBAR32(GFXVTBAR));
+ if (is_dev_enabled(igfx_dev) && gfxvtbar && gfxvten) {
+ tmp = current;
+ current += acpi_create_dmar_drhd(current, 0, 0, gfxvtbar);
+ current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0);
+
+ acpi_dmar_drhd_fixup(tmp, current);
+ }
+
+ tmp = current;
+ current += acpi_create_dmar_drhd(current,
+ DRHD_INCLUDE_PCI_ALL, 0, VTVC0_BASE_ADDRESS);
+ current += acpi_create_dmar_ds_ioapic(current,
+ 2, V_P2SB_CFG_IBDF_BUS, V_P2SB_CFG_IBDF_DEV,
+ V_P2SB_CFG_IBDF_FUNC);
+ current += acpi_create_dmar_ds_msi_hpet(current,
+ 0, V_P2SB_CFG_HBDF_BUS, V_P2SB_CFG_HBDF_DEV,
+ V_P2SB_CFG_HBDF_FUNC);
+ acpi_dmar_drhd_fixup(tmp, current);
+
+ /* Add RMRR entry */
+ if (is_dev_enabled(igfx_dev) && gfxvtbar && gfxvten) {
+ tmp = current;
+ current += acpi_create_dmar_rmrr(current, 0,
+ sa_get_gsm_base(), sa_get_tolud_base() - 1);
+ current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0);
+ acpi_dmar_rmrr_fixup(tmp, current);
+ }
+
+ tmp = current;
+ current += acpi_create_dmar_satc(current, ATC_REQUIRED, 0);
+ current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0);
+ current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IPU, 0);
+ acpi_dmar_satc_fixup(tmp, current);
+
+ return current;
+}
+
+unsigned long sa_write_acpi_tables(const struct device *dev, unsigned long current,
+ struct acpi_rsdp *rsdp)
+{
+ acpi_dmar_t *const dmar = (acpi_dmar_t *)current;
+
+ /*
+ * Create DMAR table only if we have VT-d capability and FSP does not override its
+ * feature.
+ */
+ if ((pci_read_config32(dev, CAPID0_A) & VTD_DISABLE) ||
+ !(MCHBAR32(GFXVTBAR) & VTBAR_ENABLED))
+ return current;
+
+ printk(BIOS_DEBUG, "ACPI: * DMAR\n");
+ acpi_create_dmar(dmar, DMAR_INTR_REMAP | DMA_CTRL_PLATFORM_OPT_IN_FLAG, soc_fill_dmar);
+ current += dmar->header.length;
+ current = acpi_align_current(current);
+ acpi_add_table(rsdp, dmar);
+
+ return current;
+}
+
+void soc_fill_gnvs(struct global_nvs *gnvs)
+{
+ config_t *config = config_of_soc();
+
+ /* Enable DPTF based on mainboard configuration */
+ gnvs->dpte = config->dptf_enable;
+
+ /* Set USB2/USB3 wake enable bitmaps. */
+ gnvs->u2we = config->usb2_wake_enable_bitmap;
+ gnvs->u3we = config->usb3_wake_enable_bitmap;
+}
+
+int soc_madt_sci_irq_polarity(int sci)
+{
+ return MP_IRQ_POLARITY_HIGH;
+}
diff --git a/src/soc/intel/meteorlake/chip.c b/src/soc/intel/meteorlake/chip.c
new file mode 100644
index 0000000000..8139b5b3af
--- /dev/null
+++ b/src/soc/intel/meteorlake/chip.c
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/device.h>
+#include <device/pci.h>
+#include <fsp/api.h>
+#include <fsp/util.h>
+#include <intelblocks/acpi.h>
+#include <intelblocks/cfg.h>
+#include <intelblocks/gpio.h>
+#include <intelblocks/itss.h>
+#include <intelblocks/pcie_rp.h>
+#include <intelblocks/systemagent.h>
+#include <intelblocks/xdci.h>
+#include <soc/intel/common/vbt.h>
+#include <soc/itss.h>
+#include <soc/p2sb.h>
+#include <soc/pci_devs.h>
+#include <soc/pcie.h>
+#include <soc/ramstage.h>
+#include <soc/soc_chip.h>
+
+#if CONFIG(HAVE_ACPI_TABLES)
+const char *soc_acpi_name(const struct device *dev)
+{
+ if (dev->path.type == DEVICE_PATH_DOMAIN)
+ return "PCI0";
+
+ if (dev->path.type == DEVICE_PATH_USB) {
+ switch (dev->path.usb.port_type) {
+ case 0:
+ /* Root Hub */
+ return "RHUB";
+ case 2:
+ /* USB2 ports */
+ switch (dev->path.usb.port_id) {
+ case 0: return "HS01";
+ case 1: return "HS02";
+ case 2: return "HS03";
+ case 3: return "HS04";
+ case 4: return "HS05";
+ case 5: return "HS06";
+ case 6: return "HS07";
+ case 7: return "HS08";
+ case 8: return "HS09";
+ case 9: return "HS10";
+ }
+ break;
+ case 3:
+ /* USB3 ports */
+ switch (dev->path.usb.port_id) {
+ case 0: return "SS01";
+ case 1: return "SS02";
+ case 2: return "SS03";
+ case 3: return "SS04";
+ }
+ break;
+ }
+ printk(BIOS_DEBUG, "dev->path.type=%x\n", dev->path.usb.port_type);
+ return NULL;
+ }
+ if (dev->path.type != DEVICE_PATH_PCI) {
+ printk(BIOS_DEBUG, "dev->path.type=%x\n", dev->path.type);
+ return NULL;
+ }
+
+ switch (dev->path.pci.devfn) {
+ case PCI_DEVFN_ROOT: return "MCHC";
+ case PCI_DEVFN_TCSS_XHCI: return "TXHC";
+ case PCI_DEVFN_TCSS_XDCI: return "TXDC";
+ case PCI_DEVFN_TCSS_DMA0: return "TDM0";
+ case PCI_DEVFN_TCSS_DMA1: return "TDM1";
+ case PCI_DEVFN_TBT0: return "TRP0";
+ case PCI_DEVFN_TBT1: return "TRP1";
+ case PCI_DEVFN_TBT2: return "TRP2";
+ case PCI_DEVFN_TBT3: return "TRP3";
+ case PCI_DEVFN_IPU: return "IPU0";
+ case PCI_DEVFN_ISH: return "ISHB";
+ case PCI_DEVFN_XHCI: return "XHCI";
+ case PCI_DEVFN_I2C0: return "I2C0";
+ case PCI_DEVFN_I2C1: return "I2C1";
+ case PCI_DEVFN_I2C2: return "I2C2";
+ case PCI_DEVFN_I2C3: return "I2C3";
+ case PCI_DEVFN_I2C4: return "I2C4";
+ case PCI_DEVFN_I2C5: return "I2C5";
+ case PCI_DEVFN_SATA: return "SATA";
+ case PCI_DEVFN_PCIE1: return "RP01";
+ case PCI_DEVFN_PCIE2: return "RP02";
+ case PCI_DEVFN_PCIE3: return "RP03";
+ case PCI_DEVFN_PCIE4: return "RP04";
+ case PCI_DEVFN_PCIE5: return "RP05";
+ case PCI_DEVFN_PCIE6: return "RP06";
+ case PCI_DEVFN_PCIE7: return "RP07";
+ case PCI_DEVFN_PCIE8: return "RP08";
+ case PCI_DEVFN_PCIE9: return "RP09";
+ case PCI_DEVFN_PCIE10: return "RP10";
+ case PCI_DEVFN_PCIE11: return "RP11";
+ case PCI_DEVFN_PCIE12: return "RP12";
+ case PCI_DEVFN_PMC: return "PMC";
+ case PCI_DEVFN_UART0: return "UAR0";
+ case PCI_DEVFN_UART1: return "UAR1";
+ case PCI_DEVFN_UART2: return "UAR2";
+ case PCI_DEVFN_GSPI0: return "SPI0";
+ case PCI_DEVFN_GSPI1: return "SPI1";
+ /* Keeping ACPI device name coherent with ec.asl */
+ case PCI_DEVFN_ESPI: return "LPCB";
+ case PCI_DEVFN_HDA: return "HDAS";
+ case PCI_DEVFN_SMBUS: return "SBUS";
+ case PCI_DEVFN_GBE: return "GLAN";
+ }
+ printk(BIOS_DEBUG, "dev->path.devfn=%x\n", dev->path.pci.devfn);
+ return NULL;
+}
+#endif
+
+/* SoC routine to fill GPIO PM mask and value for GPIO_MISCCFG register */
+static void soc_fill_gpio_pm_configuration(void)
+{
+ uint8_t value[TOTAL_GPIO_COMM];
+ const config_t *config = config_of_soc();
+
+ if (config->gpio_override_pm)
+ memcpy(value, config->gpio_pm, sizeof(value));
+ else
+ memset(value, MISCCFG_GPIO_PM_CONFIG_BITS, sizeof(value));
+
+ gpio_pm_configure(value, TOTAL_GPIO_COMM);
+}
+
+void soc_init_pre_device(void *chip_info)
+{
+ /* Perform silicon specific init. */
+ fsp_silicon_init();
+
+ /* Display FIRMWARE_VERSION_INFO_HOB */
+ fsp_display_fvi_version_hob();
+
+ soc_fill_gpio_pm_configuration();
+
+ /* Swap enabled PCI ports in device tree if needed. */
+ pcie_rp_update_devicetree(get_pcie_rp_table());
+}
+
+static struct device_operations pci_domain_ops = {
+ .read_resources = &pci_domain_read_resources,
+ .set_resources = &pci_domain_set_resources,
+ .scan_bus = &pci_domain_scan_bus,
+#if CONFIG(HAVE_ACPI_TABLES)
+ .acpi_name = &soc_acpi_name,
+ .acpi_fill_ssdt = ssdt_set_above_4g_pci,
+#endif
+};
+
+static struct device_operations cpu_bus_ops = {
+ .read_resources = noop_read_resources,
+ .set_resources = noop_set_resources,
+#if CONFIG(HAVE_ACPI_TABLES)
+ .acpi_fill_ssdt = generate_cpu_entries,
+#endif
+};
+
+static void soc_enable(struct device *dev)
+{
+ /*
+ * Set the operations if it is a special bus type or a hidden PCI
+ * device.
+ */
+ if (dev->path.type == DEVICE_PATH_DOMAIN)
+ dev->ops = &pci_domain_ops;
+ else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER)
+ dev->ops = &cpu_bus_ops;
+ else if (dev->path.type == DEVICE_PATH_PCI &&
+ dev->path.pci.devfn == PCI_DEVFN_PMC)
+ dev->ops = &pmc_ops;
+ else if (dev->path.type == DEVICE_PATH_PCI &&
+ dev->path.pci.devfn == PCI_DEVFN_IOE_P2SB)
+ dev->ops = &ioe_p2sb_ops;
+ else if (dev->path.type == DEVICE_PATH_GPIO)
+ block_gpio_enable(dev);
+}
+
+struct chip_operations soc_intel_meteorlake_ops = {
+ CHIP_NAME("Intel Meteorlake")
+ .enable_dev = &soc_enable,
+ .init = &soc_init_pre_device,
+};
diff --git a/src/soc/intel/meteorlake/cpu.c b/src/soc/intel/meteorlake/cpu.c
new file mode 100644
index 0000000000..8213143818
--- /dev/null
+++ b/src/soc/intel/meteorlake/cpu.c
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/cpu.h>
+#include <console/console.h>
+#include <device/pci.h>
+#include <cpu/x86/lapic.h>
+#include <cpu/x86/mp.h>
+#include <cpu/x86/msr.h>
+#include <cpu/intel/smm_reloc.h>
+#include <cpu/intel/turbo.h>
+#include <cpu/intel/common/common.h>
+#include <fsp/api.h>
+#include <intelblocks/cpulib.h>
+#include <intelblocks/mp_init.h>
+#include <intelblocks/msr.h>
+#include <intelblocks/acpi.h>
+#include <soc/cpu.h>
+#include <soc/msr.h>
+#include <soc/pci_devs.h>
+#include <soc/soc_chip.h>
+#include <soc/soc_info.h>
+#include <assert.h>
+
+bool cpu_soc_is_in_untrusted_mode(void)
+{
+ msr_t msr;
+
+ msr = rdmsr(MSR_BIOS_DONE);
+ return !!(msr.lo & ENABLE_IA_UNTRUSTED);
+}
+
+uint8_t get_supported_lpm_mask(void)
+{
+ return LPM_S0i2_0 | LPM_S0i2_1 | LPM_S0i2_2;
+}
+
+static void soc_fsp_load(void)
+{
+ fsps_load();
+}
+
+static void configure_misc(void)
+{
+ msr_t msr;
+
+ config_t *conf = (config_t *)config_of_soc();
+
+ msr = rdmsr(IA32_MISC_ENABLE);
+ msr.lo |= (1 << 0); /* Fast String enable */
+ msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
+ wrmsr(IA32_MISC_ENABLE, msr);
+
+ /* Set EIST status */
+ cpu_set_eist(conf->eist_enable);
+
+ /* Disable Thermal interrupts */
+ msr.lo = 0;
+ msr.hi = 0;
+ wrmsr(IA32_THERM_INTERRUPT, msr);
+
+ /* Enable package critical interrupt only */
+ msr.lo = 1 << 4;
+ msr.hi = 0;
+ wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
+
+ /* Enable PROCHOT */
+ msr = rdmsr(MSR_POWER_CTL);
+ msr.lo |= (1 << 0); /* Enable Bi-directional PROCHOT as an input*/
+ msr.lo |= (1 << 23); /* Lock it */
+ wrmsr(MSR_POWER_CTL, msr);
+}
+
+enum core_type get_soc_cpu_type(void)
+{
+ if (cpu_is_hybrid_supported())
+ return cpu_get_cpu_type();
+ else
+ return CPUID_CORE_TYPE_INTEL_CORE;
+}
+
+void soc_get_scaling_factor(u16 *big_core_scal_factor, u16 *small_core_scal_factor)
+{
+ *big_core_scal_factor = 127;
+ *small_core_scal_factor = 100;
+}
+
+bool soc_is_nominal_freq_supported(void)
+{
+ return true;
+}
+
+/* All CPUs including BSP will run the following function. */
+void soc_core_init(struct device *cpu)
+{
+ /* Clear out pending MCEs */
+ /* TODO(adurbin): This should only be done on a cold boot. Also, some
+ * of these banks are core vs package scope. For now every CPU clears
+ * every bank. */
+ mca_configure();
+
+ enable_lapic_tpr();
+
+ /* Configure Enhanced SpeedStep and Thermal Sensors */
+ configure_misc();
+
+ enable_pm_timer_emulation();
+
+ /* Enable Direct Cache Access */
+ configure_dca_cap();
+
+ /* Set energy policy */
+ set_energy_perf_bias(ENERGY_POLICY_NORMAL);
+
+ /* Enable Turbo */
+ enable_turbo();
+}
+
+static void per_cpu_smm_trigger(void)
+{
+ /* Relocate the SMM handler. */
+ smm_relocate();
+}
+
+static void post_mp_init(void)
+{
+ /* Set Max Ratio */
+ cpu_set_max_ratio();
+
+ /*
+ * 1. Now that all APs have been relocated as well as the BSP let SMIs
+ * start flowing.
+ * 2. Skip enabling power button SMI and enable it after BS_CHIPS_INIT
+ * to avoid shutdown hang due to lack of init on certain IP in FSP-S.
+ */
+ global_smi_enable_no_pwrbtn();
+}
+
+static const struct mp_ops mp_ops = {
+ /*
+ * Skip Pre MP init MTRR programming as MTRRs are mirrored from BSP,
+ * that are set prior to ramstage.
+ * Real MTRRs programming are being done after resource allocation.
+ */
+ .pre_mp_init = soc_fsp_load,
+ .get_cpu_count = get_cpu_count,
+ .get_smm_info = smm_info,
+ .get_microcode_info = get_microcode_info,
+ .pre_mp_smm_init = smm_initialize,
+ .per_cpu_smm_trigger = per_cpu_smm_trigger,
+ .relocation_handler = smm_relocation_handler,
+ .post_mp_init = post_mp_init,
+};
+
+void soc_init_cpus(struct bus *cpu_bus)
+{
+ if (mp_init_with_smm(cpu_bus, &mp_ops))
+ printk(BIOS_ERR, "MP initialization failure.\n");
+
+ /* Thermal throttle activation offset */
+ configure_tcc_thermal_target();
+}
diff --git a/src/soc/intel/meteorlake/elog.c b/src/soc/intel/meteorlake/elog.c
new file mode 100644
index 0000000000..35100f9ad1
--- /dev/null
+++ b/src/soc/intel/meteorlake/elog.c
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <bootstate.h>
+#include <console/console.h>
+#include <device/pci_ops.h>
+#include <elog.h>
+#include <intelblocks/pmclib.h>
+#include <intelblocks/xhci.h>
+#include <soc/pci_devs.h>
+#include <soc/pm.h>
+#include <soc/soc_info.h>
+#include <stdint.h>
+#include <types.h>
+
+struct pme_map {
+ unsigned int devfn;
+ unsigned int wake_source;
+};
+
+static void pch_log_gpio_gpe(u32 gpe0_sts, u32 gpe0_en, int start)
+{
+ int i;
+
+ gpe0_sts &= gpe0_en;
+
+ for (i = 0; i <= 31; i++) {
+ if (gpe0_sts & (1 << i))
+ elog_add_event_wake(ELOG_WAKE_SOURCE_GPE, i + start);
+ }
+}
+
+static void pch_log_rp_wake_source(void)
+{
+ size_t i;
+ uint8_t max_port = get_max_pcie_port();
+
+ const struct pme_map pme_map[] = {
+ { PCI_DEVFN_PCIE1, ELOG_WAKE_SOURCE_PME_PCIE1 },
+ { PCI_DEVFN_PCIE2, ELOG_WAKE_SOURCE_PME_PCIE2 },
+ { PCI_DEVFN_PCIE3, ELOG_WAKE_SOURCE_PME_PCIE3 },
+ { PCI_DEVFN_PCIE4, ELOG_WAKE_SOURCE_PME_PCIE4 },
+ { PCI_DEVFN_PCIE5, ELOG_WAKE_SOURCE_PME_PCIE5 },
+ { PCI_DEVFN_PCIE6, ELOG_WAKE_SOURCE_PME_PCIE6 },
+ { PCI_DEVFN_PCIE7, ELOG_WAKE_SOURCE_PME_PCIE7 },
+ { PCI_DEVFN_PCIE8, ELOG_WAKE_SOURCE_PME_PCIE8 },
+ { PCI_DEVFN_PCIE9, ELOG_WAKE_SOURCE_PME_PCIE9 },
+ { PCI_DEVFN_PCIE10, ELOG_WAKE_SOURCE_PME_PCIE10 },
+ { PCI_DEVFN_PCIE11, ELOG_WAKE_SOURCE_PME_PCIE11 },
+ { PCI_DEVFN_PCIE12, ELOG_WAKE_SOURCE_PME_PCIE12 },
+ };
+
+ for (i = 0; i < MIN(max_port, ARRAY_SIZE(pme_map)); ++i) {
+ if (pci_dev_is_wake_source(PCI_DEV(0, PCI_SLOT(pme_map[i].devfn),
+ PCI_FUNC(pme_map[i].devfn))))
+ elog_add_event_wake(pme_map[i].wake_source, 0);
+ }
+}
+
+static void pch_log_pme_internal_wake_source(void)
+{
+ const struct pme_map ipme_map[] = {
+ { PCI_DEVFN_HDA, ELOG_WAKE_SOURCE_PME_HDA },
+ { PCI_DEVFN_GBE, ELOG_WAKE_SOURCE_PME_GBE },
+ { PCI_DEVFN_SATA, ELOG_WAKE_SOURCE_PME_SATA },
+ { PCI_DEVFN_CSE, ELOG_WAKE_SOURCE_PME_CSE },
+ { PCI_DEVFN_XHCI, ELOG_WAKE_SOURCE_PME_XHCI },
+ { PCI_DEVFN_USBOTG, ELOG_WAKE_SOURCE_PME_XDCI },
+ { PCI_DEVFN_CNVI_WIFI, ELOG_WAKE_SOURCE_PME_WIFI },
+ { PCI_DEVFN_TCSS_XDCI, ELOG_WAKE_SOURCE_PME_TCSS_XDCI },
+ };
+ const struct xhci_wake_info xhci_wake_info[] = {
+ { PCI_DEVFN_XHCI, ELOG_WAKE_SOURCE_PME_XHCI },
+ { PCI_DEVFN_TCSS_XHCI, ELOG_WAKE_SOURCE_PME_TCSS_XHCI },
+ };
+ bool dev_found = false;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(ipme_map); i++) {
+ unsigned int devfn = ipme_map[i].devfn;
+ if (pci_dev_is_wake_source(PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn)))) {
+ elog_add_event_wake(ipme_map[i].wake_source, 0);
+ dev_found = true;
+ }
+ }
+
+ /* Check Thunderbolt ports */
+ for (i = 0; i < NUM_TBT_FUNCTIONS; i++) {
+ unsigned int devfn = PCI_DEVFN_TBT(i);
+ if (pci_dev_is_wake_source(PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn)))) {
+ elog_add_event_wake(ELOG_WAKE_SOURCE_PME_TBT, i);
+ dev_found = true;
+ }
+ }
+
+ /* Check DMA devices */
+ for (i = 0; i < NUM_TCSS_DMA_FUNCTIONS; i++) {
+ unsigned int devfn = PCI_DEVFN_TCSS_DMA(i);
+ if (pci_dev_is_wake_source(PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn)))) {
+ elog_add_event_wake(ELOG_WAKE_SOURCE_PME_TCSS_DMA, i);
+ dev_found = true;
+ }
+ }
+
+ /*
+ * Probe the XHCI controllers and their USB2 and USB3 ports to determine
+ * if any of them were wake sources.
+ */
+ dev_found |= xhci_update_wake_event(xhci_wake_info, ARRAY_SIZE(xhci_wake_info));
+
+ if (!dev_found)
+ elog_add_event_wake(ELOG_WAKE_SOURCE_PME_INTERNAL, 0);
+}
+
+static void pch_log_wake_source(struct chipset_power_state *ps)
+{
+ /* Power Button */
+ if (ps->pm1_sts & PWRBTN_STS)
+ elog_add_event_wake(ELOG_WAKE_SOURCE_PWRBTN, 0);
+
+ /* RTC */
+ if (ps->pm1_sts & RTC_STS)
+ elog_add_event_wake(ELOG_WAKE_SOURCE_RTC, 0);
+
+ /* PCI Express */
+ if (ps->pm1_sts & PCIEXPWAK_STS)
+ pch_log_rp_wake_source();
+
+ /* PME (TODO: determine wake device) */
+ if (ps->gpe0_sts[GPE_STD] & PME_STS)
+ elog_add_event_wake(ELOG_WAKE_SOURCE_PME, 0);
+
+ /* Internal PME */
+ if (ps->gpe0_sts[GPE_STD] & PME_B0_STS)
+ pch_log_pme_internal_wake_source();
+
+ /* SMBUS Wake */
+ if (ps->gpe0_sts[GPE_STD] & SMB_WAK_STS)
+ elog_add_event_wake(ELOG_WAKE_SOURCE_SMBUS, 0);
+
+ /* Log GPIO events in set 1-3 */
+ pch_log_gpio_gpe(ps->gpe0_sts[GPE_31_0], ps->gpe0_en[GPE_31_0], 0);
+ pch_log_gpio_gpe(ps->gpe0_sts[GPE_63_32], ps->gpe0_en[GPE_63_32], 32);
+ pch_log_gpio_gpe(ps->gpe0_sts[GPE_95_64], ps->gpe0_en[GPE_95_64], 64);
+ /* Treat the STD as an extension of GPIO to obtain visibility. */
+ pch_log_gpio_gpe(ps->gpe0_sts[GPE_STD], ps->gpe0_en[GPE_STD], 96);
+}
+
+static void pch_log_power_and_resets(const struct chipset_power_state *ps)
+{
+ /* Thermal Trip */
+ if (ps->gblrst_cause[0] & GBLRST_CAUSE0_THERMTRIP)
+ elog_add_event(ELOG_TYPE_THERM_TRIP);
+
+ /* CSME-Initiated Host Reset with power down */
+ if (ps->hpr_cause0 & HPR_CAUSE0_MI_HRPD)
+ elog_add_event(ELOG_TYPE_MI_HRPD);
+
+ /* CSME-Initiated Host Reset with power cycle */
+ if (ps->hpr_cause0 & HPR_CAUSE0_MI_HRPC)
+ elog_add_event(ELOG_TYPE_MI_HRPC);
+
+ /* CSME-Initiated Host Reset without power cycle */
+ if (ps->hpr_cause0 & HPR_CAUSE0_MI_HR)
+ elog_add_event(ELOG_TYPE_MI_HR);
+
+ /* PWR_FLR Power Failure */
+ if (ps->gen_pmcon_a & PWR_FLR)
+ elog_add_event(ELOG_TYPE_POWER_FAIL);
+
+ /* SUS Well Power Failure */
+ if (ps->gen_pmcon_a & SUS_PWR_FLR)
+ elog_add_event(ELOG_TYPE_SUS_POWER_FAIL);
+
+ /* TCO Timeout */
+ if (ps->prev_sleep_state != ACPI_S3 &&
+ ps->tco2_sts & TCO_STS_SECOND_TO)
+ elog_add_event(ELOG_TYPE_TCO_RESET);
+
+ /* Power Button Override */
+ if (ps->pm1_sts & PRBTNOR_STS)
+ elog_add_event(ELOG_TYPE_POWER_BUTTON_OVERRIDE);
+
+ /* RTC reset */
+ if (ps->gen_pmcon_b & RTC_BATTERY_DEAD)
+ elog_add_event(ELOG_TYPE_RTC_RESET);
+
+ /* Host Reset Status */
+ if (ps->gen_pmcon_a & HOST_RST_STS)
+ elog_add_event(ELOG_TYPE_SYSTEM_RESET);
+
+ /* ACPI Wake Event */
+ if (ps->prev_sleep_state != ACPI_S0)
+ elog_add_event_byte(ELOG_TYPE_ACPI_WAKE, ps->prev_sleep_state);
+}
+
+static void pch_log_state(void *unused)
+{
+ struct chipset_power_state *ps = pmc_get_power_state();
+
+ if (!ps) {
+ printk(BIOS_ERR, "chipset_power_state not found!\n");
+ return;
+ }
+
+ /* Power and Reset */
+ pch_log_power_and_resets(ps);
+
+ /* Wake Sources */
+ if (ps->prev_sleep_state > ACPI_S0)
+ pch_log_wake_source(ps);
+}
+
+BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, pch_log_state, NULL);
+
+void elog_gsmi_cb_platform_log_wake_source(void)
+{
+ struct chipset_power_state ps;
+ pmc_fill_pm_reg_info(&ps);
+ pch_log_wake_source(&ps);
+}
diff --git a/src/soc/intel/meteorlake/finalize.c b/src/soc/intel/meteorlake/finalize.c
new file mode 100644
index 0000000000..d3ae16a5fc
--- /dev/null
+++ b/src/soc/intel/meteorlake/finalize.c
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/io.h>
+#include <device/mmio.h>
+#include <bootstate.h>
+#include <console/console.h>
+#include <cpu/x86/smm.h>
+#include <delay.h>
+#include <device/pci.h>
+#include <intelblocks/cse.h>
+#include <intelblocks/gpio.h>
+#include <intelblocks/lpc_lib.h>
+#include <intelblocks/pcr.h>
+#include <intelblocks/pmclib.h>
+#include <intelblocks/systemagent.h>
+#include <intelblocks/tco.h>
+#include <intelblocks/thermal.h>
+#include <spi-generic.h>
+#include <intelpch/lockdown.h>
+#include <soc/p2sb.h>
+#include <soc/pci_devs.h>
+#include <soc/pcr_ids.h>
+#include <soc/pm.h>
+#include <soc/smbus.h>
+#include <soc/soc_chip.h>
+#include <soc/systemagent.h>
+#include <timer.h>
+
+static void pch_handle_sideband(config_t *config)
+{
+
+}
+
+static void pch_finalize(void)
+{
+ config_t *config = config_of_soc();
+
+ /* TCO Lock down */
+ tco_lockdown();
+
+ /* TODO: Add Thermal Configuration */
+
+ pch_handle_sideband(config);
+
+ pmc_clear_pmcon_sts();
+}
+
+static void tbt_finalize(void)
+{
+ int i;
+ const struct device *dev;
+
+ /* Disable Thunderbolt PCIe root ports bus master */
+ for (i = 0; i < NUM_TBT_FUNCTIONS; i++) {
+ dev = pcidev_path_on_root(PCI_DEVFN_TBT(i));
+ if (dev)
+ pci_dev_disable_bus_master(dev);
+ }
+}
+
+static void sa_finalize(void)
+{
+ if (get_lockdown_config() == CHIPSET_LOCKDOWN_COREBOOT)
+ sa_lock_pam();
+}
+
+static void soc_finalize(void *unused)
+{
+ printk(BIOS_DEBUG, "Finalizing chipset.\n");
+
+ pch_finalize();
+ apm_control(APM_CNT_FINALIZE);
+ tbt_finalize();
+ sa_finalize();
+ heci_set_to_d0i3();
+ if (CONFIG(DISABLE_HECI1_AT_PRE_BOOT))
+ heci1_disable();
+
+ /* Indicate finalize step with post code */
+ post_code(POST_OS_BOOT);
+}
+
+BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, soc_finalize, NULL);
+/*
+ * The purpose of this change is to accommodate more time to push out sending
+ * CSE EOP messages at post.
+ */
+BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, soc_finalize, NULL);
diff --git a/src/soc/intel/meteorlake/fsp_params.c b/src/soc/intel/meteorlake/fsp_params.c
new file mode 100644
index 0000000000..ad02ac58ab
--- /dev/null
+++ b/src/soc/intel/meteorlake/fsp_params.c
@@ -0,0 +1,486 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <assert.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <cpu/intel/cpu_ids.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <fsp/api.h>
+#include <fsp/ppi/mp_service_ppi.h>
+#include <fsp/util.h>
+#include <intelblocks/cse.h>
+#include <intelblocks/lpss.h>
+#include <intelblocks/xdci.h>
+#include <intelpch/lockdown.h>
+#include <intelblocks/tcss.h>
+#include <security/vboot/vboot_common.h>
+#include <soc/gpio_soc_defs.h>
+#include <soc/intel/common/vbt.h>
+#include <soc/pci_devs.h>
+#include <soc/pcie.h>
+#include <soc/ramstage.h>
+#include <soc/soc_chip.h>
+#include <soc/soc_info.h>
+#include <soc/cpu.h>
+#include <string.h>
+
+/* THC assignment definition */
+#define THC_NONE 0
+#define THC_0 1
+#define THC_1 2
+
+/* SATA DEVSLP idle timeout default values */
+#define DEF_DMVAL 15
+#define DEF_DITOVAL 625
+
+/*
+ * ME End of Post configuration
+ * 0 - Disable EOP.
+ * 1 - Send in PEI (Applicable for FSP in API mode)
+ * 2 - Send in DXE (Not applicable for FSP in API mode)
+ */
+enum fsp_end_of_post {
+ EOP_DISABLE = 0,
+ EOP_PEI = 1,
+ EOP_DXE = 2,
+};
+
+static const pci_devfn_t i2c_dev[] = {
+ PCI_DEVFN_I2C0,
+ PCI_DEVFN_I2C1,
+ PCI_DEVFN_I2C2,
+ PCI_DEVFN_I2C3,
+ PCI_DEVFN_I2C4,
+ PCI_DEVFN_I2C5,
+};
+
+static const pci_devfn_t gspi_dev[] = {
+ PCI_DEVFN_GSPI0,
+ PCI_DEVFN_GSPI1,
+};
+
+static const pci_devfn_t uart_dev[] = {
+ PCI_DEVFN_UART0,
+ PCI_DEVFN_UART1,
+ PCI_DEVFN_UART2
+};
+
+/*
+ * Chip config parameter PcieRpL1Substates uses (UPD value + 1)
+ * because UPD value of 0 for PcieRpL1Substates means disabled for FSP.
+ * In order to ensure that mainboard setting does not disable L1 substates
+ * incorrectly, chip config parameter values are offset by 1 with 0 meaning
+ * use FSP UPD default. get_l1_substate_control() ensures that the right UPD
+ * value is set in fsp_params.
+ * 0: Use FSP UPD default
+ * 1: Disable L1 substates
+ * 2: Use L1.1
+ * 3: Use L1.2 (FSP UPD default)
+ */
+static int get_l1_substate_control(enum L1_substates_control ctl)
+{
+ if ((ctl > L1_SS_L1_2) || (ctl == L1_SS_FSP_DEFAULT))
+ ctl = L1_SS_L1_2;
+ return ctl - 1;
+}
+
+__weak void mainboard_update_soc_chip_config(struct soc_intel_meteorlake_config *config)
+{
+ /* Override settings per board. */
+}
+
+static void fill_fsps_lpss_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ int max_port, i;
+
+ max_port = get_max_i2c_port();
+ for (i = 0; i < max_port; i++) {
+ s_cfg->SerialIoI2cMode[i] = is_devfn_enabled(i2c_dev[i]) ?
+ config->serial_io_i2c_mode[i] : 0;
+ }
+
+ max_port = get_max_gspi_port();
+ for (i = 0; i < max_port; i++) {
+ s_cfg->SerialIoSpiCsMode[i] = config->serial_io_gspi_cs_mode[i];
+ s_cfg->SerialIoSpiCsState[i] = config->serial_io_gspi_cs_state[i];
+ s_cfg->SerialIoSpiMode[i] = is_devfn_enabled(gspi_dev[i]) ?
+ config->serial_io_gspi_mode[i] : 0;
+ }
+
+ max_port = get_max_uart_port();
+ for (i = 0; i < max_port; i++) {
+ s_cfg->SerialIoUartMode[i] = is_devfn_enabled(uart_dev[i]) ?
+ config->serial_io_uart_mode[i] : 0;
+ }
+}
+
+static void fill_fsps_cpu_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ const struct microcode *microcode_file;
+ size_t microcode_len;
+
+ /* Locate microcode and pass to FSP-S for 2nd microcode loading */
+ microcode_file = cbfs_map("cpu_microcode_blob.bin", &microcode_len);
+
+ if ((microcode_file != NULL) && (microcode_len != 0)) {
+ /* Update CPU Microcode patch base address/size */
+ s_cfg->MicrocodeRegionBase = (uint32_t)microcode_file;
+ s_cfg->MicrocodeRegionSize = (uint32_t)microcode_len;
+ }
+
+ /* Use coreboot MP PPI services if Kconfig is enabled */
+ if (CONFIG(USE_INTEL_FSP_TO_CALL_COREBOOT_PUBLISH_MP_PPI))
+ s_cfg->CpuMpPpi = (uintptr_t) mp_fill_ppi_services_data();
+}
+
+
+static void fill_fsps_igd_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* Load VBT before devicetree-specific config. */
+ s_cfg->GraphicsConfigPtr = (uintptr_t)vbt_get();
+
+ /* Check if IGD is present and fill Graphics init param accordingly */
+ s_cfg->PeiGraphicsPeimInit = CONFIG(RUN_FSP_GOP) && is_devfn_enabled(PCI_DEVFN_IGD);
+ s_cfg->LidStatus = CONFIG(RUN_FSP_GOP);
+}
+
+static void fill_fsps_tcss_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ const struct device *tcss_port_arr[] = {
+ DEV_PTR(tcss_usb3_port1),
+ DEV_PTR(tcss_usb3_port2),
+ DEV_PTR(tcss_usb3_port3),
+ DEV_PTR(tcss_usb3_port4),
+ };
+
+ s_cfg->TcssAuxOri = config->tcss_aux_ori;
+
+ /* Explicitly clear this field to avoid using defaults */
+ memset(s_cfg->IomTypeCPortPadCfg, 0, sizeof(s_cfg->IomTypeCPortPadCfg));
+
+ /* D3Hot and D3Cold for TCSS */
+ s_cfg->D3HotEnable = !config->tcss_d3_hot_disable;
+ s_cfg->D3ColdEnable = !config->tcss_d3_cold_disable;
+ s_cfg->UsbTcPortEn = 0;
+
+ for (int i = 0; i < MAX_TYPE_C_PORTS; i++) {
+ if (is_dev_enabled(tcss_port_arr[i]))
+ s_cfg->UsbTcPortEn |= BIT(i);
+ }
+}
+
+static void fill_fsps_chipset_lockdown_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* Chipset Lockdown */
+ const bool lockdown_by_fsp = get_lockdown_config() == CHIPSET_LOCKDOWN_FSP;
+ s_cfg->PchLockDownGlobalSmi = lockdown_by_fsp;
+ s_cfg->PchLockDownBiosInterface = lockdown_by_fsp;
+ s_cfg->PchUnlockGpioPads = !lockdown_by_fsp;
+ s_cfg->RtcMemoryLock = lockdown_by_fsp;
+ s_cfg->SkipPamLock = !lockdown_by_fsp;
+
+ /* coreboot will send EOP before loading payload */
+ s_cfg->EndOfPostMessage = EOP_DISABLE;
+}
+
+static void fill_fsps_xhci_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ int i, max_port;
+
+ max_port = get_max_usb20_port();
+ for (i = 0; i < max_port; i++) {
+ s_cfg->PortUsb20Enable[i] = config->usb2_ports[i].enable;
+ s_cfg->Usb2PhyPetxiset[i] = config->usb2_ports[i].pre_emp_bias;
+ s_cfg->Usb2PhyTxiset[i] = config->usb2_ports[i].tx_bias;
+ s_cfg->Usb2PhyPredeemp[i] = config->usb2_ports[i].tx_emp_enable;
+ s_cfg->Usb2PhyPehalfbit[i] = config->usb2_ports[i].pre_emp_bit;
+
+ if (config->usb2_ports[i].enable)
+ s_cfg->Usb2OverCurrentPin[i] = config->usb2_ports[i].ocpin;
+ else
+ s_cfg->Usb2OverCurrentPin[i] = OC_SKIP;
+ }
+
+ max_port = get_max_usb30_port();
+ for (i = 0; i < max_port; i++) {
+ s_cfg->PortUsb30Enable[i] = config->usb3_ports[i].enable;
+ if (config->usb3_ports[i].enable)
+ s_cfg->Usb3OverCurrentPin[i] = config->usb3_ports[i].ocpin;
+ else
+ s_cfg->Usb3OverCurrentPin[i] = OC_SKIP;
+
+ if (config->usb3_ports[i].tx_de_emp) {
+ s_cfg->Usb3HsioTxDeEmphEnable[i] = 1;
+ s_cfg->Usb3HsioTxDeEmph[i] = config->usb3_ports[i].tx_de_emp;
+ }
+ if (config->usb3_ports[i].tx_downscale_amp) {
+ s_cfg->Usb3HsioTxDownscaleAmpEnable[i] = 1;
+ s_cfg->Usb3HsioTxDownscaleAmp[i] =
+ config->usb3_ports[i].tx_downscale_amp;
+ }
+ }
+
+ max_port = get_max_tcss_port();
+ for (i = 0; i < max_port; i++) {
+ s_cfg->PortUsb30Enable[i] = config->tcss_ports[i].enable;
+ if (config->tcss_ports[i].enable)
+ s_cfg->CpuUsb3OverCurrentPin[i] = config->tcss_ports[i].ocpin;
+ }
+}
+
+static void fill_fsps_xdci_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ s_cfg->XdciEnable = xdci_can_enable(PCI_DEVFN_USBOTG);
+}
+
+static void fill_fsps_sata_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* SATA */
+ s_cfg->SataEnable = is_devfn_enabled(PCI_DEVFN_SATA);
+ if (s_cfg->SataEnable) {
+ s_cfg->SataMode = config->sata_mode;
+ s_cfg->SataSalpSupport = config->sata_salp_support;
+ memcpy(s_cfg->SataPortsEnable, config->sata_ports_enable,
+ sizeof(s_cfg->SataPortsEnable));
+ memcpy(s_cfg->SataPortsDevSlp, config->sata_ports_dev_slp,
+ sizeof(s_cfg->SataPortsDevSlp));
+ }
+
+ /*
+ * Power Optimizer for SATA.
+ * SataPwrOptimizeDisable is default to 0.
+ * Boards not needing the optimizers explicitly disables them by setting
+ * these disable variables to 1 in devicetree overrides.
+ */
+ s_cfg->SataPwrOptEnable = !(config->sata_pwr_optimize_disable);
+ /*
+ * Enable DEVSLP Idle Timeout settings DmVal and DitoVal.
+ * SataPortsDmVal is the DITO multiplier. Default is 15.
+ * SataPortsDitoVal is the DEVSLP Idle Timeout (DITO), Default is 625ms.
+ * The default values can be changed from devicetree.
+ */
+ for (size_t i = 0; i < ARRAY_SIZE(config->sata_ports_enable_dito_config); i++) {
+ if (config->sata_ports_enable_dito_config[i]) {
+ s_cfg->SataPortsDmVal[i] = config->sata_ports_dm_val[i];
+ s_cfg->SataPortsDitoVal[i] = config->sata_ports_dito_val[i];
+ }
+ }
+}
+
+static void fill_fsps_thermal_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* Enable TCPU for processor thermal control */
+ s_cfg->Device4Enable = is_devfn_enabled(PCI_DEVFN_DPTF);
+
+ /* Set TccActivationOffset */
+ s_cfg->TccActivationOffset = config->tcc_offset;
+}
+
+static void fill_fsps_lan_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* LAN */
+ s_cfg->PchLanEnable = is_devfn_enabled(PCI_DEVFN_GBE);
+}
+
+static void fill_fsps_cnvi_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* CNVi */
+ s_cfg->CnviMode = is_devfn_enabled(PCI_DEVFN_CNVI_WIFI);
+ s_cfg->CnviBtCore = config->cnvi_bt_core;
+ s_cfg->CnviBtAudioOffload = config->cnvi_bt_audio_offload;
+ /* Assert if CNVi BT is enabled without CNVi being enabled. */
+ assert(s_cfg->CnviMode || !s_cfg->CnviBtCore);
+ /* Assert if CNVi BT offload is enabled without CNVi BT being enabled. */
+ assert(s_cfg->CnviBtCore || !s_cfg->CnviBtAudioOffload);
+}
+
+static void fill_fsps_vmd_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* VMD */
+ s_cfg->VmdEnable = is_devfn_enabled(PCI_DEVFN_VMD);
+}
+
+static void fill_fsps_tbt_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ int max_port = get_max_tbt_pcie_port();
+
+ memset(s_cfg->ITbtPcieRootPortEn, 0, sizeof(s_cfg->ITbtPcieRootPortEn));
+ for (int i = 0; i < max_port; i++)
+ s_cfg->ITbtPcieRootPortEn[i] = !(config->tbt_pcie_port_disable[i]);
+}
+
+static void fill_fsps_8254_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* Legacy 8254 timer support */
+ s_cfg->Enable8254ClockGating = !CONFIG(USE_LEGACY_8254_TIMER);
+ s_cfg->Enable8254ClockGatingOnS3 = !CONFIG(USE_LEGACY_8254_TIMER);
+}
+
+static void fill_fsps_storage_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ /* Enable Hybrid storage auto detection */
+ if (CONFIG(SOC_INTEL_CSE_LITE_SKU) && cse_is_hfs3_fw_sku_lite()
+ && vboot_recovery_mode_enabled() && !cse_is_hfs1_com_normal()) {
+ /*
+ * CSE Lite SKU does not support hybrid storage dynamic configuration
+ * in CSE RO boot, and FSP does not allow to send the strap override
+ * HECI commands if CSE is not in normal mode; hence, hybrid storage
+ * mode is disabled on CSE RO boot in recovery boot mode.
+ */
+ printk(BIOS_INFO, "cse_lite: CSE RO boot. HybridStorageMode disabled\n");
+ s_cfg->HybridStorageMode = 0;
+ } else {
+ s_cfg->HybridStorageMode = config->hybrid_storage_mode;
+ }
+}
+
+static void fill_fsps_pcie_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ int max_port = get_max_pcie_port();
+ uint32_t enable_mask = pcie_rp_enable_mask(get_pcie_rp_table());
+ for (int i = 0; i < max_port; i++) {
+ if (!(enable_mask & BIT(i)))
+ continue;
+ const struct pcie_rp_config *rp_cfg = &config->pcie_rp[i];
+ s_cfg->PcieRpL1Substates[i] =
+ get_l1_substate_control(rp_cfg->PcieRpL1Substates);
+ s_cfg->PcieRpLtrEnable[i] = !!(rp_cfg->flags & PCIE_RP_LTR);
+ s_cfg->PcieRpAdvancedErrorReporting[i] = !!(rp_cfg->flags & PCIE_RP_AER);
+ s_cfg->PcieRpHotPlug[i] = !!(rp_cfg->flags & PCIE_RP_HOTPLUG);
+ s_cfg->PcieRpClkReqDetect[i] = !!(rp_cfg->flags & PCIE_RP_CLK_REQ_DETECT);
+ }
+}
+
+static void fill_fsps_misc_power_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ s_cfg->Hwp = 1;
+ s_cfg->Cx = 1;
+ s_cfg->PsOnEnable = 1;
+ /* Enable the energy efficient turbo mode */
+ s_cfg->EnergyEfficientTurbo = 1;
+
+ /*
+ * UPDATEME: This is WA for HFPGA
+ * Disable Pch Pm Energy Report
+ * Energy Report is disabled to enhance boottime with HFPGA.
+ */
+ s_cfg->PchPmDisableEnergyReport = 1;
+
+ s_cfg->PmcLpmS0ixSubStateEnableMask = get_supported_lpm_mask();
+}
+
+
+static void fill_fsps_ufs_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ s_cfg->UfsEnable[0] = is_devfn_enabled(PCI_DEVFN_UFS);
+}
+
+static void fill_fsps_ai_params(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config)
+{
+ s_cfg->GnaEnable = is_devfn_enabled(PCI_DEVFN_GNA);
+}
+
+static void arch_silicon_init_params(FSPS_ARCH_UPD *s_arch_cfg)
+{
+ /* UPDATEME: Disable for VP
+ * EnableMultiPhaseSiliconInit for running MultiPhaseSiInit
+ */
+ s_arch_cfg->EnableMultiPhaseSiliconInit = 0;
+}
+
+static void soc_silicon_init_params(FSP_S_CONFIG *s_cfg,
+ struct soc_intel_meteorlake_config *config)
+{
+ /* Override settings per board if required. */
+ mainboard_update_soc_chip_config(config);
+
+ const void (*fill_fsps_params[])(FSP_S_CONFIG *s_cfg,
+ const struct soc_intel_meteorlake_config *config) = {
+ fill_fsps_lpss_params,
+ fill_fsps_cpu_params,
+ fill_fsps_igd_params,
+ fill_fsps_tcss_params,
+ fill_fsps_chipset_lockdown_params,
+ fill_fsps_xhci_params,
+ fill_fsps_xdci_params,
+ fill_fsps_sata_params,
+ fill_fsps_thermal_params,
+ fill_fsps_lan_params,
+ fill_fsps_cnvi_params,
+ fill_fsps_vmd_params,
+ fill_fsps_tbt_params,
+ fill_fsps_8254_params,
+ fill_fsps_storage_params,
+ fill_fsps_pcie_params,
+ fill_fsps_misc_power_params,
+ fill_fsps_ufs_params,
+ fill_fsps_ai_params,
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(fill_fsps_params); i++)
+ fill_fsps_params[i](s_cfg, config);
+}
+
+/* UPD parameters to be initialized before SiliconInit */
+void platform_fsp_silicon_init_params_cb(FSPS_UPD *supd)
+{
+ struct soc_intel_meteorlake_config *config;
+ FSP_S_CONFIG *s_cfg = &supd->FspsConfig;
+ FSPS_ARCH_UPD *s_arch_cfg = &supd->FspsArchUpd;
+
+ config = config_of_soc();
+ arch_silicon_init_params(s_arch_cfg);
+ soc_silicon_init_params(s_cfg, config);
+ mainboard_silicon_init_params(s_cfg);
+}
+
+/*
+ * Callbacks for SoC/Mainboard specific overrides for FspMultiPhaseSiInit
+ * This platform supports below MultiPhaseSIInit Phase(s):
+ * Phase | FSP return point | Purpose
+ * ------- + ------------------------------------------------ + -------------------------------
+ * 1 | After TCSS initialization completed | for TCSS specific init
+ */
+void platform_fsp_multi_phase_init_cb(uint32_t phase_index)
+{
+ switch (phase_index) {
+ case 1:
+ /* TCSS specific initialization here */
+ printk(BIOS_DEBUG, "FSP MultiPhaseSiInit %s/%s called\n",
+ __FILE__, __func__);
+
+ if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCSS)) {
+ const config_t *config = config_of_soc();
+ tcss_configure(config->typec_aux_bias_pads);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* Mainboard GPIO Configuration */
+__weak void mainboard_silicon_init_params(FSP_S_CONFIG *s_cfg)
+{
+ printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__);
+}
diff --git a/src/soc/intel/meteorlake/gspi.c b/src/soc/intel/meteorlake/gspi.c
new file mode 100644
index 0000000000..2a34ab6fdf
--- /dev/null
+++ b/src/soc/intel/meteorlake/gspi.c
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <intelblocks/gspi.h>
+#include <soc/pci_devs.h>
+
+int gspi_soc_bus_to_devfn(unsigned int gspi_bus)
+{
+ switch (gspi_bus) {
+ case 0:
+ return PCI_DEVFN_GSPI0;
+ case 1:
+ return PCI_DEVFN_GSPI1;
+ }
+ return -1;
+}
diff --git a/src/soc/intel/meteorlake/i2c.c b/src/soc/intel/meteorlake/i2c.c
new file mode 100644
index 0000000000..50ab4a73eb
--- /dev/null
+++ b/src/soc/intel/meteorlake/i2c.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/device.h>
+#include <drivers/i2c/designware/dw_i2c.h>
+#include <soc/pci_devs.h>
+
+int dw_i2c_soc_devfn_to_bus(unsigned int devfn)
+{
+ switch (devfn) {
+ case PCI_DEVFN_I2C0:
+ return 0;
+ case PCI_DEVFN_I2C1:
+ return 1;
+ case PCI_DEVFN_I2C2:
+ return 2;
+ case PCI_DEVFN_I2C3:
+ return 3;
+ case PCI_DEVFN_I2C4:
+ return 4;
+ case PCI_DEVFN_I2C5:
+ return 5;
+ }
+ return -1;
+}
+
+int dw_i2c_soc_bus_to_devfn(unsigned int bus)
+{
+ switch (bus) {
+ case 0:
+ return PCI_DEVFN_I2C0;
+ case 1:
+ return PCI_DEVFN_I2C1;
+ case 2:
+ return PCI_DEVFN_I2C2;
+ case 3:
+ return PCI_DEVFN_I2C3;
+ case 4:
+ return PCI_DEVFN_I2C4;
+ case 5:
+ return PCI_DEVFN_I2C5;
+ }
+ return -1;
+}
diff --git a/src/soc/intel/meteorlake/include/soc/cpu.h b/src/soc/intel/meteorlake/include/soc/cpu.h
new file mode 100644
index 0000000000..1a6cd6a69e
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/cpu.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_METEORLAKE_CPU_H_
+#define _SOC_METEORLAKE_CPU_H_
+
+/* Latency times in us */
+#define C1_LATENCY 1
+#define C6_LATENCY 127
+#define C7_LATENCY 253
+#define C8_LATENCY 260
+#define C9_LATENCY 487
+#define C10_LATENCY 1048
+
+/* Power in units of mW */
+#define C1_POWER 0x3e8
+#define C6_POWER 0x15e
+#define C7_POWER 0xc8
+#define C8_POWER 0xc8
+#define C9_POWER 0xc8
+#define C10_POWER 0xc8
+
+/* Get a bitmask of supported LPM states */
+uint8_t get_supported_lpm_mask(void);
+
+#endif /* _SOC_METEORLAKE_CPU_H_ */
diff --git a/src/soc/intel/meteorlake/include/soc/iomap.h b/src/soc/intel/meteorlake/include/soc/iomap.h
index c50fdb26f3..a2df40ccb4 100644
--- a/src/soc/intel/meteorlake/include/soc/iomap.h
+++ b/src/soc/intel/meteorlake/include/soc/iomap.h
@@ -61,6 +61,14 @@
#define P2SB_BAR CONFIG_PCR_BASE_ADDRESS
#define P2SB_SIZE (16 * MiB)
+#define IOE_PCR_ABOVE_4G_BASE_ADDR 0x3fff0000000
+#define IOE_P2SB_BAR IOE_PCR_ABOVE_4G_BASE_ADDR
+#define IOE_P2SB_SIZE (256 * MiB)
+
+#define IOM_BASE_ADDR 0x3fff0aa0000
+#define IOM_BASE_SIZE 0x1600
+#define IOM_BASE_ADDR_MAX 0x3fff0aa15ff
+
/*
* I/O port address space
*/
diff --git a/src/soc/intel/meteorlake/include/soc/irq.h b/src/soc/intel/meteorlake/include/soc/irq.h
new file mode 100644
index 0000000000..edc09a1332
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/irq.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_IRQ_H_
+#define _SOC_IRQ_H_
+
+#define GPIO_IRQ14 14
+#define GPIO_IRQ15 15
+
+#define PCH_IRQ10 10
+#define PCH_IRQ11 11
+
+#define LPSS_UART0_IRQ 16
+#define LPSS_UART1_IRQ 17
+#define LPSS_UART2_IRQ 31
+
+#endif
diff --git a/src/soc/intel/meteorlake/include/soc/itss.h b/src/soc/intel/meteorlake/include/soc/itss.h
new file mode 100644
index 0000000000..74ee5ab8c8
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/itss.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SOC_INTEL_MTL_ITSS_H
+#define SOC_INTEL_MTL_ITSS_H
+
+#define GPIO_IRQ_START 50
+#define GPIO_IRQ_END ITSS_MAX_IRQ
+
+#define ITSS_MAX_IRQ 119
+#define IRQS_PER_IPC 32
+#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1)/IRQS_PER_IPC)
+
+#endif /* SOC_INTEL_ADL_ITSS_H */
diff --git a/src/soc/intel/meteorlake/include/soc/me.h b/src/soc/intel/meteorlake/include/soc/me.h
new file mode 100644
index 0000000000..17cf5cd60b
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/me.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _METEORLAKE_ME_H_
+#define _METEORLAKE_ME_H_
+
+#include <stdint.h>
+
+/* ME Host Firmware Status register 1 */
+union me_hfsts1 {
+ u32 data;
+ struct {
+ u32 working_state: 4;
+ u32 mfg_mode: 1;
+ u32 fpt_bad: 1;
+ u32 operation_state: 3;
+ u32 fw_init_complete: 1;
+ u32 ft_bup_ld_flr: 1;
+ u32 update_in_progress: 1;
+ u32 error_code: 4;
+ u32 operation_mode: 4;
+ u32 reset_count: 4;
+ u32 boot_options_present: 1;
+ u32 invoke_enhance_dbg_mode: 1;
+ u32 bist_test_state: 1;
+ u32 bist_reset_request: 1;
+ u32 current_power_source: 2;
+ u32 reserved: 1;
+ u32 d0i3_support_valid: 1;
+ } __packed fields;
+};
+
+/* ME Host Firmware Status Register 3 */
+union me_hfsts3 {
+ u32 data;
+ struct {
+ u32 reserved_0: 4;
+ u32 fw_sku: 3;
+ u32 reserved_7: 2;
+ u32 reserved_9: 2;
+ u32 resered_11: 3;
+ u32 resered_14: 16;
+ u32 reserved_30: 2;
+ } __packed fields;
+};
+#endif
diff --git a/src/soc/intel/meteorlake/include/soc/nvs.h b/src/soc/intel/meteorlake/include/soc/nvs.h
new file mode 100644
index 0000000000..512945898e
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/nvs.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_NVS_H_
+#define _SOC_NVS_H_
+
+#include <intelblocks/nvs.h>
+
+#endif
diff --git a/src/soc/intel/meteorlake/include/soc/p2sb.h b/src/soc/intel/meteorlake/include/soc/p2sb.h
index c515475f1b..79ec2b1737 100644
--- a/src/soc/intel/meteorlake/include/soc/p2sb.h
+++ b/src/soc/intel/meteorlake/include/soc/p2sb.h
@@ -8,4 +8,6 @@
#define PCH_P2SB_EPMASK0 0x220
+extern struct device_operations ioe_p2sb_ops;
+
#endif
diff --git a/src/soc/intel/meteorlake/include/soc/pci_devs.h b/src/soc/intel/meteorlake/include/soc/pci_devs.h
index 4d0e3438b5..b139da4f4f 100644
--- a/src/soc/intel/meteorlake/include/soc/pci_devs.h
+++ b/src/soc/intel/meteorlake/include/soc/pci_devs.h
@@ -8,7 +8,7 @@
#define _PCI_DEVFN(slot, func) PCI_DEVFN(PCI_DEV_SLOT_ ## slot, func)
#if !defined(__SIMPLE_DEVICE__)
#include <device/device.h>
-#define _PCI_DEV(slot, func) pcidev_path_on_root(_PCI_DEVFN(slot, func), __func__)
+#define _PCI_DEV(slot, func) pcidev_path_on_root_debug(_PCI_DEVFN(slot, func), __func__)
#else
#define _PCI_DEV(slot, func) PCI_DEV(0, PCI_DEV_SLOT_ ## slot, func)
#endif
diff --git a/src/soc/intel/meteorlake/include/soc/pcie.h b/src/soc/intel/meteorlake/include/soc/pcie.h
new file mode 100644
index 0000000000..f97543c916
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/pcie.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_METEORLAKE_PCIE_H__
+#define __SOC_METEORLAKE_PCIE_H__
+
+#include <intelblocks/pcie_rp.h>
+
+const struct pcie_rp_group *get_pcie_rp_table(void);
+
+#endif /* __SOC_METEORLAKE_PCIE_H__ */
diff --git a/src/soc/intel/meteorlake/include/soc/ramstage.h b/src/soc/intel/meteorlake/include/soc/ramstage.h
new file mode 100644
index 0000000000..8f40f46b23
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/ramstage.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_RAMSTAGE_H_
+#define _SOC_RAMSTAGE_H_
+
+#include <fsp/api.h>
+#include <fsp/util.h>
+#include <soc/soc_chip.h>
+
+void mainboard_silicon_init_params(FSP_S_CONFIG *params);
+void mainboard_update_soc_chip_config(struct soc_intel_meteorlake_config *config);
+void soc_init_pre_device(void *chip_info);
+
+#endif
diff --git a/src/soc/intel/meteorlake/include/soc/serialio.h b/src/soc/intel/meteorlake/include/soc/serialio.h
new file mode 100644
index 0000000000..d34164c620
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/serialio.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SERIALIO_H_
+#define _SERIALIO_H_
+
+enum {
+ PchSerialIoDisabled,
+ PchSerialIoPci,
+ PchSerialIoHidden,
+ PchSerialIoLegacyUart,
+ PchSerialIoSkipInit
+};
+
+enum {
+ PchSerialIoIndexI2C0,
+ PchSerialIoIndexI2C1,
+ PchSerialIoIndexI2C2,
+ PchSerialIoIndexI2C3,
+ PchSerialIoIndexI2C4,
+ PchSerialIoIndexI2C5
+};
+
+enum {
+ PchSerialIoIndexGSPI0,
+ PchSerialIoIndexGSPI1,
+ PchSerialIoIndexGSPI2,
+};
+
+enum {
+ PchSerialIoIndexUART0,
+ PchSerialIoIndexUART1,
+ PchSerialIoIndexUART2
+};
+
+#endif
diff --git a/src/soc/intel/meteorlake/include/soc/soc_info.h b/src/soc/intel/meteorlake/include/soc/soc_info.h
new file mode 100644
index 0000000000..99ab1b5888
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/soc_info.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+uint8_t get_max_usb20_port(void);
+uint8_t get_max_usb30_port(void);
+uint8_t get_max_tcss_port(void);
+uint8_t get_max_tbt_pcie_port(void);
+uint8_t get_max_pcie_port(void);
+uint8_t get_max_pcie_clock(void);
+uint8_t get_max_uart_port(void);
+uint8_t get_max_i2c_port(void);
+uint8_t get_max_gspi_port(void);
diff --git a/src/soc/intel/meteorlake/include/soc/tcss.h b/src/soc/intel/meteorlake/include/soc/tcss.h
new file mode 100644
index 0000000000..014e3076e6
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/tcss.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _SOC_TCSS_H_
+#define _SOC_TCSS_H_
+
+/* Thunderbolt firmware IMR status */
+#define IOM_CSME_IMR_TBT_STATUS 0x14
+#define TBT_VALID_AUTHENTICATION (1 << 30)
+
+/* IOM aux bias control registers in REGBAR MMIO space */
+#define IOM_AUX_BIAS_CTRL_PULLUP_OFFSET_0 0x1070
+#define IOM_AUX_BIAS_CTRL_PULLUP_OFFSET(x) (IOM_AUX_BIAS_CTRL_PULLUP_OFFSET_0 + (x) * 4)
+#define IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET_0 0x1088
+#define IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET(x) (IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET_0 + (x) * 4)
+
+#endif /* _SOC_TCSS_H_ */
diff --git a/src/soc/intel/meteorlake/include/soc/usb.h b/src/soc/intel/meteorlake/include/soc/usb.h
new file mode 100644
index 0000000000..e339c7261e
--- /dev/null
+++ b/src/soc/intel/meteorlake/include/soc/usb.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_USB_H_
+#define _SOC_USB_H_
+
+#include <stdint.h>
+
+/* Per Port HS Transmitter Emphasis */
+#define USB2_EMP_OFF 0
+#define USB2_DE_EMP_ON 1
+#define USB2_PRE_EMP_ON 2
+#define USB2_DE_EMP_ON_PRE_EMP_ON 3
+
+/* Per Port Half Bit Pre-emphasis */
+#define USB2_FULL_BIT_PRE_EMP 0
+#define USB2_HALF_BIT_PRE_EMP 1
+
+/* Per Port HS Preemphasis Bias */
+#define USB2_BIAS_0MV 0
+#define USB2_BIAS_11P25MV 1
+#define USB2_BIAS_16P9MV 2
+#define USB2_BIAS_28P15MV 3
+#define USB2_BIAS_39P35MV 5
+#define USB2_BIAS_45MV 6
+#define USB2_BIAS_56P3MV 7
+
+struct usb2_port_config {
+ uint8_t enable;
+ uint8_t ocpin;
+ uint8_t tx_bias;
+ uint8_t tx_emp_enable;
+ uint8_t pre_emp_bias;
+ uint8_t pre_emp_bit;
+};
+
+/* USB Overcurrent pins definition */
+enum {
+ OC0 = 0,
+ OC1,
+ OC2,
+ OC3,
+ OC4,
+ OC5,
+ OC6,
+ OC7,
+ OCMAX,
+ OC_SKIP = 0xff, /* Skip OC programming */
+};
+
+/* Standard USB Port based on length:
+ * - External
+ * - Back Panel
+ * - OTG
+ * - M.2
+ * - Internal device down */
+
+#define USB2_PORT_EMPTY { \
+ .enable = 0, \
+ .ocpin = OC_SKIP, \
+ .tx_bias = USB2_BIAS_0MV, \
+ .tx_emp_enable = USB2_EMP_OFF, \
+ .pre_emp_bias = USB2_BIAS_0MV, \
+ .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \
+}
+
+/* Length = 11.5"-12" */
+#define USB2_PORT_LONG(pin) { \
+ .enable = 1, \
+ .ocpin = (pin), \
+ .tx_bias = USB2_BIAS_39P35MV, \
+ .tx_emp_enable = USB2_PRE_EMP_ON, \
+ .pre_emp_bias = USB2_BIAS_56P3MV, \
+ .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \
+}
+
+/* Length = 6"-11.49" */
+#define USB2_PORT_MID(pin) { \
+ .enable = 1, \
+ .ocpin = (pin), \
+ .tx_bias = USB2_BIAS_0MV, \
+ .tx_emp_enable = USB2_DE_EMP_ON_PRE_EMP_ON, \
+ .pre_emp_bias = USB2_BIAS_45MV, \
+ .pre_emp_bit = USB2_FULL_BIT_PRE_EMP, \
+}
+
+/* Length = 3"-5.99" */
+#define USB2_PORT_SHORT(pin) { \
+ .enable = 1, \
+ .ocpin = (pin), \
+ .tx_bias = USB2_BIAS_39P35MV, \
+ .tx_emp_enable = USB2_PRE_EMP_ON | USB2_DE_EMP_ON, \
+ .pre_emp_bias = USB2_BIAS_39P35MV, \
+ .pre_emp_bit = USB2_FULL_BIT_PRE_EMP, \
+}
+
+/* Max TX and Pre-emp settings */
+#define USB2_PORT_MAX(pin) { \
+ .enable = 1, \
+ .ocpin = (pin), \
+ .tx_bias = USB2_BIAS_56P3MV, \
+ .tx_emp_enable = USB2_PRE_EMP_ON, \
+ .pre_emp_bias = USB2_BIAS_56P3MV, \
+ .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \
+}
+
+/* Type-C Port, no BC1.2 charge detect module / MUX
+ * Length = 3.0" - 9.00" */
+#define USB2_PORT_TYPE_C(pin) { \
+ .enable = 1, \
+ .ocpin = (pin), \
+ .tx_bias = USB2_BIAS_0MV, \
+ .tx_emp_enable = USB2_PRE_EMP_ON, \
+ .pre_emp_bias = USB2_BIAS_56P3MV, \
+ .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \
+}
+
+struct usb3_port_config {
+ uint8_t enable;
+ uint8_t ocpin;
+ uint8_t tx_de_emp;
+ uint8_t tx_downscale_amp;
+};
+
+#define USB3_PORT_EMPTY { \
+ .enable = 0, \
+ .ocpin = OC_SKIP, \
+ .tx_de_emp = 0x00, \
+ .tx_downscale_amp = 0x00, \
+}
+
+#define USB3_PORT_DEFAULT(pin) { \
+ .enable = 1, \
+ .ocpin = (pin), \
+ .tx_de_emp = 0x0, \
+ .tx_downscale_amp = 0x00, \
+}
+
+struct tcss_port_config {
+ uint8_t enable;
+ uint8_t ocpin;
+};
+
+#define TCSS_PORT_EMPTY { \
+ .enable = 0, \
+ .ocpin = OC_SKIP, \
+}
+
+#define TCSS_PORT_DEFAULT(pin) { \
+ .enable = 1, \
+ .ocpin = (pin), \
+}
+
+
+#endif
diff --git a/src/soc/intel/meteorlake/lockdown.c b/src/soc/intel/meteorlake/lockdown.c
new file mode 100644
index 0000000000..678e63a15c
--- /dev/null
+++ b/src/soc/intel/meteorlake/lockdown.c
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/mmio.h>
+#include <intelblocks/cfg.h>
+#include <intelpch/lockdown.h>
+#include <soc/pm.h>
+#include <stdint.h>
+
+static void pmc_lock_pmsync(void)
+{
+ uint8_t *pmcbase;
+ uint32_t pmsyncreg;
+
+ pmcbase = pmc_mmio_regs();
+
+ pmsyncreg = read32(pmcbase + PMSYNC_TPR_CFG);
+ pmsyncreg |= PCH2CPU_TPR_CFG_LOCK;
+ write32(pmcbase + PMSYNC_TPR_CFG, pmsyncreg);
+}
+
+static void pmc_lock_abase(void)
+{
+ uint8_t *pmcbase;
+ uint32_t reg32;
+
+ pmcbase = pmc_mmio_regs();
+
+ reg32 = read32(pmcbase + GEN_PMCON_B);
+ reg32 |= (SLP_STR_POL_LOCK | ACPI_BASE_LOCK);
+ write32(pmcbase + GEN_PMCON_B, reg32);
+}
+
+static void pmc_lock_smi(void)
+{
+ uint8_t *pmcbase;
+ uint8_t reg8;
+
+ pmcbase = pmc_mmio_regs();
+
+ reg8 = read8(pmcbase + GEN_PMCON_B);
+ reg8 |= SMI_LOCK;
+ write8(pmcbase + GEN_PMCON_B, reg8);
+}
+
+static void pmc_lockdown_cfg(int chipset_lockdown)
+{
+ /* PMSYNC */
+ pmc_lock_pmsync();
+ /* Lock down ABASE and sleep stretching policy */
+ pmc_lock_abase();
+
+ if (chipset_lockdown == CHIPSET_LOCKDOWN_COREBOOT)
+ pmc_lock_smi();
+}
+
+void soc_lockdown_config(int chipset_lockdown)
+{
+ /* PMC lock down configuration */
+ pmc_lockdown_cfg(chipset_lockdown);
+}
diff --git a/src/soc/intel/meteorlake/me.c b/src/soc/intel/meteorlake/me.c
new file mode 100644
index 0000000000..ea949025a7
--- /dev/null
+++ b/src/soc/intel/meteorlake/me.c
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <bootstate.h>
+#include <intelblocks/cse.h>
+#include <console/console.h>
+#include <soc/me.h>
+#include <stdint.h>
+
+/* Host Firmware Status Register 2 */
+union me_hfsts2 {
+ uint32_t data;
+ struct {
+ uint32_t nftp_load_failure : 1;
+ uint32_t icc_prog_status : 2;
+ uint32_t invoke_mebx : 1;
+ uint32_t cpu_replaced : 1;
+ uint32_t rsvd0 : 1;
+ uint32_t mfs_failure : 1;
+ uint32_t warm_reset_rqst : 1;
+ uint32_t cpu_replaced_valid : 1;
+ uint32_t low_power_state : 1;
+ uint32_t me_power_gate : 1;
+ uint32_t ipu_needed : 1;
+ uint32_t forced_safe_boot : 1;
+ uint32_t rsvd1 : 2;
+ uint32_t listener_change : 1;
+ uint32_t status_data : 8;
+ uint32_t current_pmevent : 4;
+ uint32_t phase : 4;
+ } __packed fields;
+};
+
+/* Host Firmware Status Register 4 */
+union me_hfsts4 {
+ uint32_t data;
+ struct {
+ uint32_t rsvd0 : 9;
+ uint32_t enforcement_flow : 1;
+ uint32_t sx_resume_type : 1;
+ uint32_t rsvd1 : 1;
+ uint32_t tpms_disconnected : 1;
+ uint32_t rvsd2 : 1;
+ uint32_t fwsts_valid : 1;
+ uint32_t boot_guard_self_test : 1;
+ uint32_t rsvd3 : 16;
+ } __packed fields;
+};
+
+/* Host Firmware Status Register 5 */
+union me_hfsts5 {
+ uint32_t data;
+ struct {
+ uint32_t acm_active : 1;
+ uint32_t valid : 1;
+ uint32_t result_code_source : 1;
+ uint32_t error_status_code : 5;
+ uint32_t acm_done_sts : 1;
+ uint32_t timeout_count : 7;
+ uint32_t scrtm_indicator : 1;
+ uint32_t inc_boot_guard_acm : 4;
+ uint32_t inc_key_manifest : 4;
+ uint32_t inc_boot_policy : 4;
+ uint32_t rsvd0 : 2;
+ uint32_t start_enforcement : 1;
+ } __packed fields;
+};
+
+/* Host Firmware Status Register 6 */
+union me_hfsts6 {
+ uint32_t data;
+ struct {
+ uint32_t force_boot_guard_acm : 1;
+ uint32_t cpu_debug_disable : 1;
+ uint32_t bsp_init_disable : 1;
+ uint32_t protect_bios_env : 1;
+ uint32_t rsvd0 : 2;
+ uint32_t error_enforce_policy : 2;
+ uint32_t measured_boot : 1;
+ uint32_t verified_boot : 1;
+ uint32_t boot_guard_acmsvn : 4;
+ uint32_t kmsvn : 4;
+ uint32_t bpmsvn : 4;
+ uint32_t key_manifest_id : 4;
+ uint32_t boot_policy_status : 1;
+ uint32_t error : 1;
+ uint32_t boot_guard_disable : 1;
+ uint32_t fpf_disable : 1;
+ uint32_t fpf_soc_lock : 1;
+ uint32_t txt_support : 1;
+ } __packed fields;
+};
+
+static void dump_me_status(void *unused)
+{
+ union me_hfsts1 hfsts1;
+ union me_hfsts2 hfsts2;
+ union me_hfsts3 hfsts3;
+ union me_hfsts4 hfsts4;
+ union me_hfsts5 hfsts5;
+ union me_hfsts6 hfsts6;
+
+ if (!is_cse_enabled())
+ return;
+
+ hfsts1.data = me_read_config32(PCI_ME_HFSTS1);
+ hfsts2.data = me_read_config32(PCI_ME_HFSTS2);
+ hfsts3.data = me_read_config32(PCI_ME_HFSTS3);
+ hfsts4.data = me_read_config32(PCI_ME_HFSTS4);
+ hfsts5.data = me_read_config32(PCI_ME_HFSTS5);
+ hfsts6.data = me_read_config32(PCI_ME_HFSTS6);
+
+ printk(BIOS_DEBUG, "ME: HFSTS1 : 0x%08X\n", hfsts1.data);
+ printk(BIOS_DEBUG, "ME: HFSTS2 : 0x%08X\n", hfsts2.data);
+ printk(BIOS_DEBUG, "ME: HFSTS3 : 0x%08X\n", hfsts3.data);
+ printk(BIOS_DEBUG, "ME: HFSTS4 : 0x%08X\n", hfsts4.data);
+ printk(BIOS_DEBUG, "ME: HFSTS5 : 0x%08X\n", hfsts5.data);
+ printk(BIOS_DEBUG, "ME: HFSTS6 : 0x%08X\n", hfsts6.data);
+
+ /*
+ * Lock Descriptor, and Fuses must be programmed on a
+ * production system to indicate ME Manufacturing mode is disabled.
+ */
+ printk(BIOS_DEBUG, "ME: Manufacturing Mode : %s\n",
+ ((hfsts1.fields.mfg_mode == 0) &&
+ (hfsts6.fields.fpf_soc_lock == 1)) ? "NO" : "YES");
+ /*
+ * The SPI Protection Mode bit reflects SPI descriptor
+ * locked(0) or unlocked(1).
+ */
+ printk(BIOS_DEBUG, "ME: SPI Protection Mode Enabled : %s\n",
+ hfsts1.fields.mfg_mode ? "NO" : "YES");
+ printk(BIOS_DEBUG, "ME: FW Partition Table : %s\n",
+ hfsts1.fields.fpt_bad ? "BAD" : "OK");
+ printk(BIOS_DEBUG, "ME: Bringup Loader Failure : %s\n",
+ hfsts1.fields.ft_bup_ld_flr ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: Firmware Init Complete : %s\n",
+ hfsts1.fields.fw_init_complete ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: Boot Options Present : %s\n",
+ hfsts1.fields.boot_options_present ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: Update In Progress : %s\n",
+ hfsts1.fields.update_in_progress ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: D0i3 Support : %s\n",
+ hfsts1.fields.d0i3_support_valid ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: Low Power State Enabled : %s\n",
+ hfsts2.fields.low_power_state ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: CPU Replaced : %s\n",
+ hfsts2.fields.cpu_replaced ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: CPU Replacement Valid : %s\n",
+ hfsts2.fields.cpu_replaced_valid ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: Current Working State : %u\n",
+ hfsts1.fields.working_state);
+ printk(BIOS_DEBUG, "ME: Current Operation State : %u\n",
+ hfsts1.fields.operation_state);
+ printk(BIOS_DEBUG, "ME: Current Operation Mode : %u\n",
+ hfsts1.fields.operation_mode);
+ printk(BIOS_DEBUG, "ME: Error Code : %u\n",
+ hfsts1.fields.error_code);
+ printk(BIOS_DEBUG, "ME: Enhanced Debug Mode : %s\n",
+ hfsts1.fields.invoke_enhance_dbg_mode ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: CPU Debug Disabled : %s\n",
+ hfsts6.fields.cpu_debug_disable ? "YES" : "NO");
+ printk(BIOS_DEBUG, "ME: TXT Support : %s\n",
+ hfsts6.fields.txt_support ? "YES" : "NO");
+}
+
+BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_EXIT, print_me_fw_version, NULL);
+BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_EXIT, dump_me_status, NULL);
diff --git a/src/soc/intel/meteorlake/p2sb.c b/src/soc/intel/meteorlake/p2sb.c
index 169cde6147..7809dd35aa 100644
--- a/src/soc/intel/meteorlake/p2sb.c
+++ b/src/soc/intel/meteorlake/p2sb.c
@@ -1,7 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
+#include <device/device.h>
#include <intelblocks/p2sb.h>
+#include <soc/iomap.h>
void p2sb_soc_get_sb_mask(uint32_t *ep_mask, size_t count)
{
@@ -28,3 +30,15 @@ void p2sb_soc_get_sb_mask(uint32_t *ep_mask, size_t count)
ep_mask[P2SB_EP_MASK_7_REG] = mask;
}
+
+static void ioe_p2sb_read_resources(struct device *dev)
+{
+ /* Add the fixed MMIO resource for IOM */
+ mmio_resource_kb(dev, 0, IOM_BASE_ADDR / KiB, IOM_BASE_SIZE / KiB);
+}
+
+struct device_operations ioe_p2sb_ops = {
+ .read_resources = ioe_p2sb_read_resources,
+ .set_resources = noop_set_resources,
+ .scan_bus = scan_static_bus,
+};
diff --git a/src/soc/intel/meteorlake/pcie_rp.c b/src/soc/intel/meteorlake/pcie_rp.c
new file mode 100644
index 0000000000..1b4045ec43
--- /dev/null
+++ b/src/soc/intel/meteorlake/pcie_rp.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <intelblocks/pcie_rp.h>
+#include <soc/pci_devs.h>
+#include <soc/pcie.h>
+#include <soc/soc_info.h>
+#include <console/console.h>
+
+static const struct pcie_rp_group mtlp_rp_groups[] = {
+ { .slot = PCI_DEV_SLOT_PCIE_1, .start = 0, .count = 8, .lcap_port_base = 1 },
+ { .slot = PCI_DEV_SLOT_PCIE_2, .start = 0, .count = 3, .lcap_port_base = 1 },
+ { .slot = PCI_DEV_SLOT_PCIE_3, .start = 0, .count = 1, .lcap_port_base = 1 },
+ { 0 }
+};
+
+const struct pcie_rp_group *get_pcie_rp_table(void)
+{
+ return mtlp_rp_groups;
+}
+
+enum pcie_rp_type soc_get_pcie_rp_type(const struct device *dev)
+{
+ return PCIE_RP_PCH;
+}
+
+int soc_get_cpu_rp_vw_idx(const struct device *dev)
+{
+ return -1;
+}
diff --git a/src/soc/intel/meteorlake/pmc.c b/src/soc/intel/meteorlake/pmc.c
new file mode 100644
index 0000000000..0ab15c4f5b
--- /dev/null
+++ b/src/soc/intel/meteorlake/pmc.c
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+
+#include <acpi/acpigen.h>
+#include <console/console.h>
+#include <device/mmio.h>
+#include <device/device.h>
+#include <drivers/intel/pmc_mux/chip.h>
+#include <intelblocks/acpi.h>
+#include <intelblocks/pmc.h>
+#include <intelblocks/pmc_ipc.h>
+#include <intelblocks/pmclib.h>
+#include <intelblocks/rtc.h>
+#include <soc/cpu.h>
+#include <soc/pci_devs.h>
+#include <soc/pm.h>
+#include <soc/soc_chip.h>
+#include <stdint.h>
+#include <bootstate.h>
+
+#define PMC_HID "INTC1026"
+
+static void config_deep_sX(uint32_t offset, uint32_t mask, int sx, int enable)
+{
+ uint32_t reg;
+ uint8_t *pmcbase = pmc_mmio_regs();
+
+ printk(BIOS_DEBUG, "%sabling Deep S%c\n",
+ enable ? "En" : "Dis", sx + '0');
+ reg = read32(pmcbase + offset);
+ if (enable)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ write32(pmcbase + offset, reg);
+}
+
+static void config_deep_s5(int on_ac, int on_dc)
+{
+ /* Treat S4 the same as S5. */
+ config_deep_sX(S4_PWRGATE_POL, S4AC_GATE_SUS, 4, on_ac);
+ config_deep_sX(S4_PWRGATE_POL, S4DC_GATE_SUS, 4, on_dc);
+ config_deep_sX(S5_PWRGATE_POL, S5AC_GATE_SUS, 5, on_ac);
+ config_deep_sX(S5_PWRGATE_POL, S5DC_GATE_SUS, 5, on_dc);
+}
+
+static void config_deep_s3(int on_ac, int on_dc)
+{
+ config_deep_sX(S3_PWRGATE_POL, S3AC_GATE_SUS, 3, on_ac);
+ config_deep_sX(S3_PWRGATE_POL, S3DC_GATE_SUS, 3, on_dc);
+}
+
+static void config_deep_sx(uint32_t deepsx_config)
+{
+ uint32_t reg;
+ uint8_t *pmcbase = pmc_mmio_regs();
+
+ reg = read32(pmcbase + DSX_CFG);
+ reg &= ~DSX_CFG_MASK;
+ reg |= deepsx_config;
+ write32(pmcbase + DSX_CFG, reg);
+}
+
+static void soc_pmc_enable(struct device *dev)
+{
+ const config_t *config = config_of_soc();
+
+ rtc_init();
+
+ pmc_set_power_failure_state(true);
+ pmc_gpe_init();
+
+ config_deep_s3(config->deep_s3_enable_ac, config->deep_s3_enable_dc);
+ config_deep_s5(config->deep_s5_enable_ac, config->deep_s5_enable_dc);
+ config_deep_sx(config->deep_sx_config);
+}
+
+static void soc_pmc_read_resources(struct device *dev)
+{
+ struct resource *res;
+
+ /* Add the fixed MMIO resource */
+ mmio_resource_kb(dev, 0, PCH_PWRM_BASE_ADDRESS / KiB, PCH_PWRM_BASE_SIZE / KiB);
+
+ /* Add the fixed I/O resource */
+ res = new_resource(dev, 1);
+ res->base = (resource_t)ACPI_BASE_ADDRESS;
+ res->size = (resource_t)ACPI_BASE_SIZE;
+ res->limit = res->base + res->size - 1;
+ res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+}
+
+static void soc_pmc_fill_ssdt(const struct device *dev)
+{
+ const char *scope = acpi_device_scope(dev);
+ const char *name = acpi_device_name(dev);
+ if (!scope || !name)
+ return;
+
+ acpigen_write_scope(scope);
+ acpigen_write_device(name);
+
+ acpigen_write_name_string("_HID", PMC_HID);
+ acpigen_write_name_string("_DDN", "Intel(R) Meteor Lake IPC Controller");
+
+ /*
+ * Part of the PCH's reserved 32 MB MMIO range (0xFC800000 - 0xFE7FFFFF).
+ * The PMC gets 0xFE000000 - 0xFE00FFFF.
+ */
+ acpigen_write_name("_CRS");
+ acpigen_write_resourcetemplate_header();
+ acpigen_write_mem32fixed(1, PCH_PWRM_BASE_ADDRESS, PCH_PWRM_BASE_SIZE);
+ acpigen_write_resourcetemplate_footer();
+
+ /* Define IPC Write Method */
+ if (CONFIG(PMC_IPC_ACPI_INTERFACE))
+ pmc_ipc_acpi_fill_ssdt();
+
+ acpigen_pop_len(); /* PMC Device */
+ acpigen_pop_len(); /* Scope */
+
+ if (CONFIG(SOC_INTEL_COMMON_BLOCK_ACPI_PEP)) {
+ const struct soc_pmc_lpm mtl_pmc_lpm = {
+ .num_substates = 8,
+ .num_req_regs = 6,
+ .lpm_ipc_offset = 0x1000,
+ .req_reg_stride = 0x30,
+ .lpm_enable_mask = get_supported_lpm_mask(),
+ };
+
+ generate_acpi_power_engine_with_lpm(&mtl_pmc_lpm);
+ }
+
+ printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
+ dev_path(dev));
+}
+
+static void soc_pmc_init(struct device *dev)
+{
+ /*
+ * pmc_set_acpi_mode() should be delayed until BS_DEV_INIT in order
+ * to ensure the ordering does not break the assumptions that other
+ * drivers make about ACPI mode (e.g. Chrome EC). Since it disables
+ * ACPI mode, other drivers may take different actions based on this
+ * (e.g. Chrome EC will flush any pending hostevent bits). Because
+ * TGL has its PMC device available for device_operations, it can be
+ * done from the "ops->init" callback.
+ */
+ pmc_set_acpi_mode();
+
+ /*
+ * Disable ACPI PM timer based on Kconfig
+ *
+ * Disabling ACPI PM timer is necessary for XTAL OSC shutdown.
+ * Disabling ACPI PM timer also switches off TCO
+ */
+ if (!CONFIG(USE_PM_ACPI_TIMER))
+ setbits8(pmc_mmio_regs() + PCH_PWRM_ACPI_TMR_CTL, ACPI_TIM_DIS);
+}
+
+static void pm1_enable_pwrbtn_smi(void *unused)
+{
+ /* Enable power button SMI after BS_DEV_INIT_CHIPS (FSP-S) is done. */
+ pmc_update_pm1_enable(PWRBTN_EN);
+}
+
+BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, pm1_enable_pwrbtn_smi, NULL);
+
+/*
+ * `pmc_final` function is native implementation of equivalent events performed by
+ * each FSP NotifyPhase() API invocations.
+ *
+ *
+ * Clear PMCON status bits (Global Reset/Power Failure/Host Reset Status bits)
+ *
+ * Perform the PMCON status bit clear operation from `.final`
+ * to cover any such chances where later boot stage requested a global
+ * reset and PMCON status bit remains set.
+ */
+static void pmc_final(struct device *dev)
+{
+ pmc_clear_pmcon_sts();
+}
+
+struct device_operations pmc_ops = {
+ .read_resources = soc_pmc_read_resources,
+ .set_resources = noop_set_resources,
+ .init = soc_pmc_init,
+ .enable = soc_pmc_enable,
+#if CONFIG(HAVE_ACPI_TABLES)
+ .acpi_fill_ssdt = soc_pmc_fill_ssdt,
+#endif
+ .scan_bus = scan_static_bus,
+ .final = pmc_final,
+};
diff --git a/src/soc/intel/meteorlake/pmutil.c b/src/soc/intel/meteorlake/pmutil.c
new file mode 100644
index 0000000000..b9f28dedc4
--- /dev/null
+++ b/src/soc/intel/meteorlake/pmutil.c
@@ -0,0 +1,265 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Helper functions for dealing with power management registers
+ * and the differences between PCH variants.
+ */
+
+#define __SIMPLE_DEVICE__
+
+#include <acpi/acpi_pm.h>
+#include <device/mmio.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_def.h>
+#include <console/console.h>
+#include <intelblocks/pmclib.h>
+#include <intelblocks/rtc.h>
+#include <intelblocks/tco.h>
+#include <security/vboot/vbnv.h>
+#include <soc/espi.h>
+#include <soc/gpe.h>
+#include <soc/gpio.h>
+#include <soc/iomap.h>
+#include <soc/pci_devs.h>
+#include <soc/pm.h>
+#include <soc/smbus.h>
+#include <soc/soc_chip.h>
+#include <types.h>
+
+/*
+ * SMI
+ */
+const char *const *soc_smi_sts_array(size_t *a)
+{
+ static const char *const smi_sts_bits[] = {
+ [BIOS_STS_BIT] = "BIOS",
+ [LEGACY_USB_STS_BIT] = "LEGACY_USB",
+ [SMI_ON_SLP_EN_STS_BIT] = "SLP_SMI",
+ [APM_STS_BIT] = "APM",
+ [SWSMI_TMR_STS_BIT] = "SWSMI_TMR",
+ [PM1_STS_BIT] = "PM1",
+ [GPE0_STS_BIT] = "GPE0",
+ [GPIO_STS_BIT] = "GPI",
+ [MCSMI_STS_BIT] = "MCSMI",
+ [DEVMON_STS_BIT] = "DEVMON",
+ [TCO_STS_BIT] = "TCO",
+ [PERIODIC_STS_BIT] = "PERIODIC",
+ [SERIRQ_SMI_STS_BIT] = "SERIRQ_SMI",
+ [SMBUS_SMI_STS_BIT] = "SMBUS_SMI",
+ [PCI_EXP_SMI_STS_BIT] = "PCI_EXP_SMI",
+ [MONITOR_STS_BIT] = "MONITOR",
+ [SPI_SMI_STS_BIT] = "SPI",
+ [GPIO_UNLOCK_SMI_STS_BIT] = "GPIO_UNLOCK",
+ [ESPI_SMI_STS_BIT] = "ESPI_SMI",
+ };
+
+ *a = ARRAY_SIZE(smi_sts_bits);
+ return smi_sts_bits;
+}
+
+/*
+ * TCO
+ */
+const char *const *soc_tco_sts_array(size_t *a)
+{
+ static const char *const tco_sts_bits[] = {
+ [0] = "NMI2SMI",
+ [1] = "SW_TCO",
+ [2] = "TCO_INT",
+ [3] = "TIMEOUT",
+ [7] = "NEWCENTURY",
+ [8] = "BIOSWR",
+ [9] = "DMISCI",
+ [10] = "DMISMI",
+ [12] = "DMISERR",
+ [13] = "SLVSEL",
+ [16] = "INTRD_DET",
+ [17] = "SECOND_TO",
+ [18] = "BOOT",
+ [20] = "SMLINK_SLV"
+ };
+
+ *a = ARRAY_SIZE(tco_sts_bits);
+ return tco_sts_bits;
+}
+
+/*
+ * GPE0
+ */
+const char *const *soc_std_gpe_sts_array(size_t *a)
+{
+ static const char *const gpe_sts_bits[] = {
+ [1] = "HOTPLUG",
+ [2] = "SWGPE",
+ [6] = "TCO_SCI",
+ [7] = "SMB_WAK",
+ [9] = "PCI_EXP",
+ [10] = "BATLOW",
+ [11] = "PME",
+ [12] = "ME",
+ [13] = "PME_B0",
+ [14] = "eSPI",
+ [15] = "GPIO Tier-2",
+ [16] = "LAN_WAKE",
+ [18] = "WADT"
+ };
+
+ *a = ARRAY_SIZE(gpe_sts_bits);
+ return gpe_sts_bits;
+}
+
+void pmc_set_disb(void)
+{
+ /* Set the DISB after DRAM init */
+ uint8_t disb_val;
+ /* Only care about bits [23:16] of register GEN_PMCON_A */
+ uint8_t *addr = (uint8_t *)(pmc_mmio_regs() + GEN_PMCON_A + 2);
+
+ disb_val = read8(addr);
+ disb_val |= (DISB >> 16);
+
+ /* Don't clear bits that are write-1-to-clear */
+ disb_val &= ~((MS4V | SUS_PWR_FLR) >> 16);
+ write8(addr, disb_val);
+}
+
+/*
+ * PMC controller gets hidden from PCI bus
+ * during FSP-Silicon init call. Hence PWRMBASE
+ * can't be accessible using PCI configuration space
+ * read/write.
+ */
+uint8_t *pmc_mmio_regs(void)
+{
+ return (void *)(uintptr_t)PCH_PWRM_BASE_ADDRESS;
+}
+
+uintptr_t soc_read_pmc_base(void)
+{
+ return (uintptr_t)pmc_mmio_regs();
+}
+
+uint32_t *soc_pmc_etr_addr(void)
+{
+ return (uint32_t *)(soc_read_pmc_base() + ETR);
+}
+
+void soc_get_gpi_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2)
+{
+ DEVTREE_CONST struct soc_intel_meteorlake_config *config;
+
+ config = config_of_soc();
+
+ /* Assign to out variable */
+ *dw0 = config->pmc_gpe0_dw0;
+ *dw1 = config->pmc_gpe0_dw1;
+ *dw2 = config->pmc_gpe0_dw2;
+}
+
+static int rtc_failed(uint32_t gen_pmcon_b)
+{
+ return !!(gen_pmcon_b & RTC_BATTERY_DEAD);
+}
+
+int soc_get_rtc_failed(void)
+{
+ const struct chipset_power_state *ps;
+
+ if (acpi_pm_state_for_rtc(&ps) < 0)
+ return 1;
+
+ return rtc_failed(ps->gen_pmcon_b);
+}
+
+int vbnv_cmos_failed(void)
+{
+ return rtc_failed(read32(pmc_mmio_regs() + GEN_PMCON_B));
+}
+
+static inline int deep_s3_enabled(void)
+{
+ uint32_t deep_s3_pol;
+
+ deep_s3_pol = read32(pmc_mmio_regs() + S3_PWRGATE_POL);
+ return !!(deep_s3_pol & (S3DC_GATE_SUS | S3AC_GATE_SUS));
+}
+
+/* Return 0, 3, or 5 to indicate the previous sleep state. */
+int soc_prev_sleep_state(const struct chipset_power_state *ps, int prev_sleep_state)
+{
+ /*
+ * Check for any power failure to determine if this a wake from
+ * S5 because the PCH does not set the WAK_STS bit when waking
+ * from a true G3 state.
+ */
+ if (ps->gen_pmcon_a & (PWR_FLR | SUS_PWR_FLR))
+ prev_sleep_state = ACPI_S5;
+
+ /*
+ * If waking from S3 determine if deep S3 is enabled. If not,
+ * need to check both deep sleep well and normal suspend well.
+ * Otherwise just check deep sleep well.
+ */
+ if (prev_sleep_state == ACPI_S3) {
+ /* PWR_FLR represents deep sleep power well loss. */
+ uint32_t mask = PWR_FLR;
+
+ /* If deep s3 isn't enabled check the suspend well too. */
+ if (!deep_s3_enabled())
+ mask |= SUS_PWR_FLR;
+
+ if (ps->gen_pmcon_a & mask)
+ prev_sleep_state = ACPI_S5;
+ }
+
+ return prev_sleep_state;
+}
+
+void soc_fill_power_state(struct chipset_power_state *ps)
+{
+ uint8_t *pmc;
+
+ ps->tco1_sts = tco_read_reg(TCO1_STS);
+ ps->tco2_sts = tco_read_reg(TCO2_STS);
+
+ printk(BIOS_DEBUG, "TCO_STS: %04x %04x\n", ps->tco1_sts, ps->tco2_sts);
+
+ pmc = pmc_mmio_regs();
+ ps->gen_pmcon_a = read32(pmc + GEN_PMCON_A);
+ ps->gen_pmcon_b = read32(pmc + GEN_PMCON_B);
+ ps->gblrst_cause[0] = read32(pmc + GBLRST_CAUSE0);
+ ps->gblrst_cause[1] = read32(pmc + GBLRST_CAUSE1);
+ ps->hpr_cause0 = read32(pmc + HPR_CAUSE0);
+
+ printk(BIOS_DEBUG, "GEN_PMCON: %08x %08x\n",
+ ps->gen_pmcon_a, ps->gen_pmcon_b);
+
+ printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n",
+ ps->gblrst_cause[0], ps->gblrst_cause[1]);
+
+ printk(BIOS_DEBUG, "HPR_CAUSE0: %08x\n", ps->hpr_cause0);
+}
+
+/* STM Support */
+uint16_t get_pmbase(void)
+{
+ return (uint16_t) ACPI_BASE_ADDRESS;
+}
+
+/*
+ * Set which power state system will be after reapplying
+ * the power (from G3 State)
+ */
+void pmc_soc_set_afterg3_en(const bool on)
+{
+ uint8_t reg8;
+ uint8_t *const pmcbase = pmc_mmio_regs();
+
+ reg8 = read8(pmcbase + GEN_PMCON_A);
+ if (on)
+ reg8 &= ~SLEEP_AFTER_POWER_FAIL;
+ else
+ reg8 |= SLEEP_AFTER_POWER_FAIL;
+ write8(pmcbase + GEN_PMCON_A, reg8);
+}
diff --git a/src/soc/intel/meteorlake/retimer.c b/src/soc/intel/meteorlake/retimer.c
new file mode 100644
index 0000000000..09bf112160
--- /dev/null
+++ b/src/soc/intel/meteorlake/retimer.c
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <drivers/intel/usb4/retimer/retimer.h>
+#include <intelblocks/tcss.h>
+
+int retimer_get_index_for_typec(uint8_t typec_port)
+{
+ int ec_port = 0;
+
+ const struct device *tcss_port_arr[] = {
+ DEV_PTR(tcss_usb3_port1),
+ DEV_PTR(tcss_usb3_port2),
+ DEV_PTR(tcss_usb3_port3),
+ DEV_PTR(tcss_usb3_port4),
+ };
+
+ for (uint8_t i = 0; i < MAX_TYPE_C_PORTS; i++) {
+ if (i == typec_port) {
+ printk(BIOS_ERR, "USB Type-C %d mapped to EC port %d\n", typec_port,
+ ec_port);
+ return ec_port;
+ }
+
+ if (is_dev_enabled(tcss_port_arr[i]))
+ ec_port++;
+ }
+
+ // Code should not come here if typec_port input is correct
+ return -1;
+}
diff --git a/src/soc/intel/meteorlake/smihandler.c b/src/soc/intel/meteorlake/smihandler.c
new file mode 100644
index 0000000000..6a21f0a757
--- /dev/null
+++ b/src/soc/intel/meteorlake/smihandler.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/pci_def.h>
+#include <intelblocks/smihandler.h>
+#include <soc/soc_chip.h>
+#include <soc/pci_devs.h>
+#include <soc/pm.h>
+
+int smihandler_soc_disable_busmaster(pci_devfn_t dev)
+{
+ /* Skip disabling PMC bus master to keep IO decode enabled */
+ if (dev == PCI_DEV_PMC)
+ return 0;
+ return 1;
+}
+
+const smi_handler_t southbridge_smi[SMI_STS_BITS] = {
+ [SMI_ON_SLP_EN_STS_BIT] = smihandler_southbridge_sleep,
+ [APM_STS_BIT] = smihandler_southbridge_apmc,
+ [PM1_STS_BIT] = smihandler_southbridge_pm1,
+ [GPE0_STS_BIT] = smihandler_southbridge_gpe0,
+ [GPIO_STS_BIT] = smihandler_southbridge_gpi,
+ [ESPI_SMI_STS_BIT] = smihandler_southbridge_espi,
+ [MCSMI_STS_BIT] = smihandler_southbridge_mc,
+#if CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE)
+ [TCO_STS_BIT] = smihandler_southbridge_tco,
+#endif
+ [PERIODIC_STS_BIT] = smihandler_southbridge_periodic,
+ [MONITOR_STS_BIT] = smihandler_southbridge_monitor,
+};
diff --git a/src/soc/intel/meteorlake/soc_info.c b/src/soc/intel/meteorlake/soc_info.c
new file mode 100644
index 0000000000..b5333bd01a
--- /dev/null
+++ b/src/soc/intel/meteorlake/soc_info.c
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <soc/pci_devs.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <soc/soc_info.h>
+#include <intelblocks/tcss.h>
+#include <console/console.h>
+
+uint8_t get_max_usb20_port(void)
+{
+ uint8_t usb20_port = CONFIG_SOC_INTEL_USB2_DEV_MAX;
+ printk(BIOS_DEBUG, "soc_info: max_usb20_port:%d\n", usb20_port);
+ return usb20_port;
+}
+
+uint8_t get_max_usb30_port(void)
+{
+ uint8_t usb30_port = CONFIG_SOC_INTEL_USB3_DEV_MAX;
+ printk(BIOS_DEBUG, "soc_info: max_usb30_port:%d\n", usb30_port);
+ return usb30_port;
+}
+
+uint8_t get_max_tcss_port(void)
+{
+ uint8_t tcss_port = MAX_TYPE_C_PORTS;
+ printk(BIOS_DEBUG, "soc_info: tcss_port:%d\n", tcss_port);
+ return tcss_port;
+}
+
+uint8_t get_max_tbt_pcie_port(void)
+{
+ uint8_t tbt_pcie_port = CONFIG_MAX_TBT_ROOT_PORTS;
+ printk(BIOS_DEBUG, "soc_info: max_tbt_pcie_port:%d\n", tbt_pcie_port);
+ return tbt_pcie_port;
+}
+
+uint8_t get_max_pcie_port(void)
+{
+ uint8_t pcie_port = CONFIG_MAX_ROOT_PORTS;
+ printk(BIOS_DEBUG, "soc_info: max_pcie_port:%d\n", pcie_port);
+ return pcie_port;
+}
+
+uint8_t get_max_pcie_clock(void)
+{
+ uint8_t pcie_clock = CONFIG_MAX_PCIE_CLOCK_SRC;
+ printk(BIOS_DEBUG, "soc_info: max_pcie_clock:%d\n", pcie_clock);
+ return pcie_clock;
+}
+
+uint8_t get_max_uart_port(void)
+{
+ uint8_t uart_port = CONFIG_SOC_INTEL_UART_DEV_MAX;
+ printk(BIOS_DEBUG, "soc_info: max_uart_port:%d\n", uart_port);
+ return uart_port;
+}
+
+uint8_t get_max_i2c_port(void)
+{
+ uint8_t i2c_port = CONFIG_SOC_INTEL_I2C_DEV_MAX;
+ printk(BIOS_DEBUG, "soc_info: max_i2c_port:%d\n", i2c_port);
+ return i2c_port;
+}
+
+uint8_t get_max_gspi_port(void)
+{
+ uint8_t gspi_port = CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX;
+ printk(BIOS_DEBUG, "soc_info: max_gspi_port:%d\n", gspi_port);
+ return gspi_port;
+}
diff --git a/src/soc/intel/meteorlake/soundwire.c b/src/soc/intel/meteorlake/soundwire.c
new file mode 100644
index 0000000000..c3ff05d2e3
--- /dev/null
+++ b/src/soc/intel/meteorlake/soundwire.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpi_soundwire.h>
+#include <console/console.h>
+#include <device/mmio.h>
+#include <device/soundwire.h>
+#include <drivers/intel/soundwire/soundwire.h>
+#include <intelblocks/pmclib.h>
+#include <soc/pmc.h>
+#include <stddef.h>
+#include <string.h>
+
+static const struct soundwire_link link_xtal_38_4 = {
+ .clock_stop_mode0_supported = 1,
+ .clock_stop_mode1_supported = 1,
+ .clock_frequencies_supported_count = 1,
+ .clock_frequencies_supported = { 4800 * KHz },
+ .default_frame_rate = 48 * KHz,
+ .default_frame_row_size = 50,
+ .default_frame_col_size = 4,
+ .dynamic_frame_shape = 1,
+ .command_error_threshold = 16,
+};
+
+static const struct soundwire_link link_xtal_24 = {
+ .clock_stop_mode0_supported = 1,
+ .clock_stop_mode1_supported = 1,
+ .clock_frequencies_supported_count = 1,
+ .clock_frequencies_supported = { 6 * MHz },
+ .default_frame_rate = 48 * KHz,
+ .default_frame_row_size = 125,
+ .default_frame_col_size = 2,
+ .dynamic_frame_shape = 1,
+ .command_error_threshold = 16,
+};
+
+static struct intel_soundwire_controller intel_controller = {
+ .acpi_address = 0x40000000,
+ .sdw = {
+ .master_list_count = 4
+ }
+};
+
+int soc_fill_soundwire_controller(struct intel_soundwire_controller **controller)
+{
+ const struct soundwire_link *link;
+ enum pch_pmc_xtal xtal = pmc_get_xtal_freq();
+ size_t i;
+
+ /* Select link config based on XTAL frequency and set IP clock. */
+ switch (xtal) {
+ case XTAL_24_MHZ:
+ link = &link_xtal_24;
+ intel_controller.ip_clock = 24 * MHz;
+ break;
+ case XTAL_38_4_MHZ:
+ link = &link_xtal_38_4;
+ intel_controller.ip_clock = 38400 * KHz;
+ break;
+ case XTAL_19_2_MHZ:
+ default:
+ printk(BIOS_ERR, "%s: XTAL not supported: 0x%x\n", __func__, xtal);
+ return -1;
+ }
+
+ /* Fill link config in controller map based on selected XTAL. */
+ for (i = 0; i < intel_controller.sdw.master_list_count; i++)
+ memcpy(&intel_controller.sdw.master_list[i], link, sizeof(*link));
+
+ *controller = &intel_controller;
+ return 0;
+}
diff --git a/src/soc/intel/meteorlake/spi.c b/src/soc/intel/meteorlake/spi.c
new file mode 100644
index 0000000000..f2e340087b
--- /dev/null
+++ b/src/soc/intel/meteorlake/spi.c
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <intelblocks/fast_spi.h>
+#include <intelblocks/spi.h>
+#include <soc/pci_devs.h>
+
+#define PSF_SPI_DESTINATION_ID 0x5140
+
+int spi_soc_devfn_to_bus(unsigned int devfn)
+{
+ switch (devfn) {
+ case PCI_DEVFN_SPI:
+ return 0;
+ case PCI_DEVFN_GSPI0:
+ return 1;
+ case PCI_DEVFN_GSPI1:
+ return 2;
+ }
+ return -1;
+}
+
+uint32_t soc_get_spi_psf_destination_id(void)
+{
+ return PSF_SPI_DESTINATION_ID;
+}
diff --git a/src/soc/intel/meteorlake/systemagent.c b/src/soc/intel/meteorlake/systemagent.c
new file mode 100644
index 0000000000..675f9fb2fa
--- /dev/null
+++ b/src/soc/intel/meteorlake/systemagent.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <delay.h>
+#include <intelblocks/power_limit.h>
+#include <intelblocks/systemagent.h>
+#include <soc/iomap.h>
+#include <soc/soc_chip.h>
+#include <soc/systemagent.h>
+
+/*
+ * SoC implementation
+ *
+ * Add all known fixed memory ranges for Host Controller/Memory
+ * controller.
+ */
+void soc_add_fixed_mmio_resources(struct device *dev, int *index)
+{
+ static const struct sa_mmio_descriptor soc_fixed_resources[] = {
+ { PCIEXBAR, CONFIG_ECAM_MMCONF_BASE_ADDRESS, CONFIG_ECAM_MMCONF_LENGTH,
+ "PCIEXBAR" },
+ { DMIBAR, DMI_BASE_ADDRESS, DMI_BASE_SIZE, "DMIBAR" },
+ { EPBAR, EP_BASE_ADDRESS, EP_BASE_SIZE, "EPBAR" },
+ { REGBAR, REG_BASE_ADDRESS, REG_BASE_SIZE, "REGBAR" },
+ { EDRAMBAR, EDRAM_BASE_ADDRESS, EDRAM_BASE_SIZE, "EDRAMBAR" },
+ };
+
+ sa_add_fixed_mmio_resources(dev, index, soc_fixed_resources,
+ ARRAY_SIZE(soc_fixed_resources));
+
+ /* Add Vt-d resources if VT-d is enabled */
+ if ((pci_read_config32(dev, CAPID0_A) & VTD_DISABLE))
+ return;
+
+ sa_add_fixed_mmio_resources(dev, index, soc_vtd_resources,
+ ARRAY_SIZE(soc_vtd_resources));
+}
+
+/*
+ * SoC implementation
+ *
+ * Perform System Agent Initialization during Ramstage phase.
+ */
+void soc_systemagent_init(struct device *dev)
+{
+ struct soc_power_limits_config *soc_config;
+ struct device *sa;
+ uint16_t sa_pci_id;
+ config_t *config;
+
+ /* Enable Power Aware Interrupt Routing */
+ enable_power_aware_intr();
+
+ /* Enable BIOS Reset CPL */
+ enable_bios_reset_cpl();
+
+ /* Configure turbo power limits 1ms after reset complete bit */
+ mdelay(1);
+ config = config_of_soc();
+
+ /* Get System Agent PCI ID */
+ sa = pcidev_path_on_root(PCI_DEVFN_ROOT);
+ sa_pci_id = sa ? pci_read_config16(sa, PCI_DEVICE_ID) : 0xFFFF;
+
+ /* Choose a power limits configuration based on the SoC SKU type,
+ * differentiated here based on SA PCI ID. */
+ switch (sa_pci_id) {
+ case PCI_DID_INTEL_MTL_P_ID_1:
+ soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_1];
+ break;
+ case PCI_DID_INTEL_MTL_P_ID_2:
+ soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_2];
+ break;
+ case PCI_DID_INTEL_MTL_P_ID_3:
+ soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_3];
+ break;
+ default:
+ printk(BIOS_ERR, "unknown SA ID: 0x%4x, skipping power limits configuration\n",
+ sa_pci_id);
+ return;
+ }
+
+ /* UPDATEME: Need to enable later */
+ //set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_config);
+}
+
+uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz)
+{
+ switch (capid0_a_ddrsz) {
+ case 1:
+ return 8192;
+ case 2:
+ return 4096;
+ case 3:
+ return 2048;
+ default:
+ return 65536;
+ }
+}
diff --git a/src/soc/intel/meteorlake/tcss.c b/src/soc/intel/meteorlake/tcss.c
new file mode 100644
index 0000000000..c51fe6c41f
--- /dev/null
+++ b/src/soc/intel/meteorlake/tcss.c
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <intelblocks/tcss.h>
+
+const struct soc_tcss_ops tcss_ops = {
+ .configure_aux_bias_pads = tcss_configure_aux_bias_pads_regbar,
+ .valid_tbt_auth = tcss_valid_tbt_auth,
+};
diff --git a/src/soc/intel/meteorlake/uart.c b/src/soc/intel/meteorlake/uart.c
new file mode 100644
index 0000000000..9f549c5ae8
--- /dev/null
+++ b/src/soc/intel/meteorlake/uart.c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <commonlib/helpers.h>
+#include <soc/pci_devs.h>
+
+const unsigned int uart_devices[] = {
+ PCI_DEVFN_UART0,
+ PCI_DEVFN_UART1,
+ PCI_DEVFN_UART2,
+};
+
+const int uart_devices_size = ARRAY_SIZE(uart_devices);
diff --git a/src/soc/intel/meteorlake/xhci.c b/src/soc/intel/meteorlake/xhci.c
new file mode 100644
index 0000000000..9b4ac1b066
--- /dev/null
+++ b/src/soc/intel/meteorlake/xhci.c
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/pci_type.h>
+#include <intelblocks/xhci.h>
+#include <soc/pci_devs.h>
+
+#define XHCI_USB2_PORT_STATUS_REG 0x480
+#define XHCI_USB3_PORT_STATUS_REG 0x540
+#define XHCI_USB2_PORT_NUM 10
+#define XHCI_USB3_PORT_NUM 4
+
+#define TCSS_XHCI_USB2_PORT_STATUS_REG 0x480
+#define TCSS_XHCI_USB3_PORT_STATUS_REG 0x490
+#define TCSS_XHCI_USB2_PORT_NUM 0
+#define TCSS_XHCI_USB3_PORT_NUM 4
+
+static const struct xhci_usb_info usb_info = {
+ .usb2_port_status_reg = XHCI_USB2_PORT_STATUS_REG,
+ .num_usb2_ports = XHCI_USB2_PORT_NUM,
+ .usb3_port_status_reg = XHCI_USB3_PORT_STATUS_REG,
+ .num_usb3_ports = XHCI_USB3_PORT_NUM,
+};
+
+static const struct xhci_usb_info tcss_usb_info = {
+ .usb2_port_status_reg = TCSS_XHCI_USB2_PORT_STATUS_REG,
+ .num_usb2_ports = TCSS_XHCI_USB2_PORT_NUM,
+ .usb3_port_status_reg = TCSS_XHCI_USB3_PORT_STATUS_REG,
+ .num_usb3_ports = TCSS_XHCI_USB3_PORT_NUM,
+};
+
+const struct xhci_usb_info *soc_get_xhci_usb_info(pci_devfn_t xhci_dev)
+{
+ if (xhci_dev == PCI_DEVFN_XHCI)
+ return &usb_info;
+ else if (xhci_dev == PCI_DEVFN_TCSS_XHCI)
+ return &tcss_usb_info;
+
+ return NULL;
+}