Ravishankar Sarawadi has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/63364 )
Change subject: soc/intel/meteorlake/ramstage: Do initial SoC commit till ramstage ......................................................................
soc/intel/meteorlake/ramstage: Do initial SoC commit till ramstage
List of changes: 1. Add required SoC programming till ramstage 2. Include only required headers into include/soc 3. Fill required FSP-S UPD to call FSP-S API
TEST= Build mtlrvp board.
Signed-off-by: Ravi Sarawadi ravishankar.sarawadi@intel.com Change-Id: Ie746c0bfcf1f315a4ab6f540cc7c4933157551d7 --- M src/soc/intel/meteorlake/Kconfig M src/soc/intel/meteorlake/Makefile.inc A src/soc/intel/meteorlake/acpi.c A src/soc/intel/meteorlake/chip.c M src/soc/intel/meteorlake/chip.h A src/soc/intel/meteorlake/chipset.cb A src/soc/intel/meteorlake/cpu.c A src/soc/intel/meteorlake/crashlog.c A src/soc/intel/meteorlake/dptf.c A src/soc/intel/meteorlake/elog.c A src/soc/intel/meteorlake/finalize.c A src/soc/intel/meteorlake/fsp_params.c A src/soc/intel/meteorlake/gspi.c A src/soc/intel/meteorlake/i2c.c A src/soc/intel/meteorlake/include/soc/cpu.h A src/soc/intel/meteorlake/include/soc/crashlog.h A src/soc/intel/meteorlake/include/soc/irq.h A src/soc/intel/meteorlake/include/soc/itss.h A src/soc/intel/meteorlake/include/soc/me.h A src/soc/intel/meteorlake/include/soc/meminit.h A src/soc/intel/meteorlake/include/soc/nvs.h M src/soc/intel/meteorlake/include/soc/p2sb.h A src/soc/intel/meteorlake/include/soc/pcie.h A src/soc/intel/meteorlake/include/soc/ramstage.h A src/soc/intel/meteorlake/include/soc/serialio.h A src/soc/intel/meteorlake/include/soc/soc_info.h A src/soc/intel/meteorlake/include/soc/tcss.h A src/soc/intel/meteorlake/include/soc/usb.h A src/soc/intel/meteorlake/lockdown.c A src/soc/intel/meteorlake/me.c A src/soc/intel/meteorlake/pcie_rp.c A src/soc/intel/meteorlake/pmc.c A src/soc/intel/meteorlake/pmutil.c A src/soc/intel/meteorlake/smihandler.c A src/soc/intel/meteorlake/soc_info.c A src/soc/intel/meteorlake/soundwire.c A src/soc/intel/meteorlake/spi.c A src/soc/intel/meteorlake/systemagent.c A src/soc/intel/meteorlake/uart.c A src/soc/intel/meteorlake/xhci.c 40 files changed, 3,778 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/64/63364/1
diff --git a/src/soc/intel/meteorlake/Kconfig b/src/soc/intel/meteorlake/Kconfig index 462d19c..7803675 100644 --- a/src/soc/intel/meteorlake/Kconfig +++ b/src/soc/intel/meteorlake/Kconfig @@ -11,27 +11,92 @@ select BOOT_DEVICE_SUPPORTS_WRITES 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_USB_ACPI + 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 #TODO - Enable INTEL_CAR_NEM_ENHANCED + 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_2 + select REG_SCRIPT + select PMC_GLOBAL_RESET_ENABLE_LOCK + select PMC_LOW_POWER_MODE_PROGRAM + select PMC_EPOC 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_MEMINIT + select SOC_INTEL_COMMON_BLOCK_HDA + select SOC_INTEL_COMMON_BLOCK_IPU +# select SOC_INTEL_COMMON_BLOCK_IRQ + select SOC_INTEL_COMMON_BLOCK_MEMINIT + select SOC_INTEL_COMMON_BLOCK_PCIE_RTD3 + 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_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_FSP_RESET select SOC_INTEL_COMMON_PCH_BASE select SOC_INTEL_COMMON_RESET select SSE2 select SUPPORT_CPU_UCODE_IN_CBFS select TSC_MONOTONIC_TIMER select UDELAY_TSC + select UDK_202005_BINDING + select DISPLAY_FSP_VERSION_INFO + select HECI_DISABLE_USING_SMM +# select DEBUG_GPIO + +choice LAPIC_ACCESS_MODE + prompt "APIC operation mode" + default X2APIC_ONLY + +config XAPIC_ONLY + prompt "Set XAPIC mode" + bool + +config X2APIC_ONLY + prompt "Set X2APIC mode" + bool + depends on PARALLEL_MP + +config X2APIC_RUNTIME + prompt "Support both XAPIC and X2APIC" + bool + depends on PARALLEL_MP +endchoice + +config MAX_CPUS + int + default 22
config DCACHE_RAM_BASE default 0xfef00000 @@ -59,6 +124,16 @@ 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" @@ -71,6 +146,22 @@ hex default 0x10000
+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 @@ -107,11 +198,23 @@ 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 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 clcok * M) /(N *16) # MTL UART source clock: 120MHz @@ -176,4 +279,11 @@ int default 16
+config SOC_INTEL_CRASHLOG + def_bool n + select SOC_INTEL_COMMON_BLOCK_CRASHLOG + select ACPI_BERT + help + Enables CrashLog. + endif diff --git a/src/soc/intel/meteorlake/Makefile.inc b/src/soc/intel/meteorlake/Makefile.inc index aace725..d3e846b 100644 --- a/src/soc/intel/meteorlake/Makefile.inc +++ b/src/soc/intel/meteorlake/Makefile.inc @@ -7,6 +7,13 @@ subdirs-y += ../../../cpu/x86/mtrr subdirs-y += ../../../cpu/x86/tsc
+# 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/pch.c bootblock-y += bootblock/report_platform.c @@ -15,8 +22,38 @@
romstage-y += espi.c romstage-y += meminit.c +romstage-y += pcie_rp.c romstage-y += reset.c
+ramstage-y += acpi.c +ramstage-y += chip.c +ramstage-y += cpu.c +ramstage-y += dptf.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 += soundwire.c +ramstage-y += systemagent.c +ramstage-y += xhci.c +ramstage-$(CONFIG_SOC_INTEL_CRASHLOG) += crashlog.c +ramstage-y += soc_info.c +romstage-y += soc_info.c +bootblock-y += soc_info.c + +smm-y += elog.c +smm-y += p2sb.c +smm-y += pmutil.c +smm-y += smihandler.c +smm-y += uart.c +smm-y += xhci.c + CPPFLAGS_common += -I$(src)/soc/intel/meteorlake CPPFLAGS_common += -I$(src)/soc/intel/meteorlake/include
diff --git a/src/soc/intel/meteorlake/acpi.c b/src/soc/intel/meteorlake/acpi.c new file mode 100644 index 0000000..23f7a8b --- /dev/null +++ b/src/soc/intel/meteorlake/acpi.c @@ -0,0 +1,273 @@ +/* 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 <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 +}; + +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++) { + memcpy(&map[i], &cstate_map[set[i]], sizeof(acpi_cstate_t)); + 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; + + /* Fill in Above 4GB MMIO resource */ + sa_fill_gnvs(gnvs); +} + +uint32_t acpi_fill_soc_wake(uint32_t generic_pm1_en, + const struct chipset_power_state *ps) +{ + /* + * WAK_STS bit is set when the system is in one of the sleep states + * (via the SLP_EN bit) and an enabled wake event occurs. Upon setting + * this bit, the PMC will transition the system to the ON state and + * can only be set by hardware and can only be cleared by writing a one + * to this bit position. + */ + + generic_pm1_en |= WAK_STS | RTC_EN | PWRBTN_EN; + return generic_pm1_en; +} + +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 0000000..22ce2f0 --- /dev/null +++ b/src/soc/intel/meteorlake/chip.c @@ -0,0 +1,176 @@ +/* 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/xdci.h> +#include <soc/intel/common/vbt.h> +#include <soc/itss.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; + } + return NULL; + } + if (dev->path.type != DEVICE_PATH_PCI) + 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"; + } + + 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, +#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_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/chip.h b/src/soc/intel/meteorlake/chip.h index eecd73f..7c72c8d 100644 --- a/src/soc/intel/meteorlake/chip.h +++ b/src/soc/intel/meteorlake/chip.h @@ -7,12 +7,55 @@ #include <intelblocks/cfg.h> #include <intelblocks/gpio.h> #include <intelblocks/gspi.h> +#include <intelblocks/power_limit.h> +#include <intelblocks/pcie_rp.h> #include <intelblocks/tcss.h> #include <soc/gpe.h> #include <soc/pci_devs.h> #include <soc/pmc.h> +#include <soc/serialio.h> +#include <soc/usb.h> #include <stdint.h>
+/* Types of different SKUs */ +enum soc_intel_meteorlake_power_limits { + MTL_M_POWER_LIMITS, + MTL_P_POWER_LIMITS_1, + MTL_P_POWER_LIMITS_2, + MTL_POWER_LIMITS_COUNT +}; + +/* Types of display ports */ +enum ddi_ports { + DDI_PORT_A, + DDI_PORT_B, + DDI_PORT_C, + DDI_PORT_1, + DDI_PORT_2, + DDI_PORT_3, + DDI_PORT_4, + DDI_PORT_COUNT, +}; + +enum ddi_port_flags { + DDI_ENABLE_DDC = 1 << 0, + DDI_ENABLE_HPD = 1 << 1, +}; + +/* Bit values for use in LpmStateEnableMask. */ +enum lpm_state_mask { + LPM_S0i2_0 = BIT(0), + LPM_S0i2_1 = BIT(1), + LPM_S0i2_2 = BIT(2), + LPM_S0i3_0 = BIT(3), + LPM_S0i3_1 = BIT(4), + LPM_S0i3_2 = BIT(5), + LPM_S0i3_3 = BIT(6), + LPM_S0i3_4 = BIT(7), + LPM_S0iX_ALL = LPM_S0i2_0 | LPM_S0i2_1 | LPM_S0i2_2 + | LPM_S0i3_0 | LPM_S0i3_1 | LPM_S0i3_2 | LPM_S0i3_3 | LPM_S0i3_4, +}; + /* TODO Need to remove <dev> string when rename SoC file */ struct soc_intel_meteorlake_config {
diff --git a/src/soc/intel/meteorlake/chipset.cb b/src/soc/intel/meteorlake/chipset.cb new file mode 100644 index 0000000..95a7cf2 --- /dev/null +++ b/src/soc/intel/meteorlake/chipset.cb @@ -0,0 +1,162 @@ +chip soc/intel/meteorlake + + #FIXME: update values for MTL and enable override in systemagent.c + register "power_limits_config[MTL_P_POWER_LIMITS_2]" = "{ + .tdp_pl1_override = 15, + .tdp_pl2_override = 55, + }" + + register "power_limits_config[MTL_P_POWER_LIMITS_1]" = "{ + .tdp_pl1_override = 45, + .tdp_pl2_override = 115, + }" + + register "power_limits_config[MTL_M_POWER_LIMITS]" = "{ + .tdp_pl1_override = 9, + .tdp_pl2_override = 30, + }" + + device domain 0 on + device pci 00.0 alias system_agent on end + device pci 01.0 alias pcie_rp12 off end + device pci 02.0 alias igpu off end + device pci 04.0 alias dtt off end + device pci 05.0 alias ipu off end + device pci 06.0 alias pcie_rp9 off end + device pci 06.1 alias pcie_rp10 off end + device pci 06.2 alias pcie_rp11 off end + device pci 07.0 alias tbt_pcie_rp0 off + chip soc/intel/common/block/usb4 + use tcss_dma0 as usb4_port + device generic 0 on end + end + end + device pci 07.1 alias tbt_pcie_rp1 off + chip soc/intel/common/block/usb4 + use tcss_dma0 as usb4_port + device generic 1 on end + end + end + device pci 07.2 alias tbt_pcie_rp2 off + chip soc/intel/common/block/usb4 + use tcss_dma1 as usb4_port + device generic 0 on end + end + end + device pci 07.3 alias tbt_pcie_rp3 off + chip soc/intel/common/block/usb4 + use tcss_dma1 as usb4_port + device generic 1 on end + end + end + device pci 08.0 alias gna off end + device pci 0a.0 alias crashlog on end + device pci 0d.0 alias tcss_xhci off + chip drivers/usb/acpi + register "type" = "UPC_TYPE_HUB" + device usb 0.0 alias tcss_root_hub off + chip drivers/usb/acpi + device usb 3.0 alias tcss_usb3_port1 off end + end + chip drivers/usb/acpi + device usb 3.1 alias tcss_usb3_port2 off end + end + end + end + end + device pci 0d.1 alias tcss_xdci off end + device pci 0d.2 alias tcss_dma0 off end + device pci 0d.3 alias tcss_dma1 off end + device pci 0e.0 alias vmd off end + device pci 10.0 alias thc0 off end + device pci 10.1 alias thc1 off end + device pci 12.0 alias ish off end + device pci 12.7 alias ufs off end + device pci 13.0 alias p2sb2 off end + device pci 13.2 alias pmc2 hidden end + device pci 13.3 alias shared_sram2 off end + device pci 14.0 alias xhci off + chip drivers/usb/acpi + register "type" = "UPC_TYPE_HUB" + device usb 0.0 alias xhci_root_hub off + chip drivers/usb/acpi + device usb 2.0 alias usb2_port1 off end + end + chip drivers/usb/acpi + device usb 2.1 alias usb2_port2 off end + end + chip drivers/usb/acpi + device usb 2.2 alias usb2_port3 off end + end + chip drivers/usb/acpi + device usb 2.3 alias usb2_port4 off end + end + chip drivers/usb/acpi + device usb 2.4 alias usb2_port5 off end + end + chip drivers/usb/acpi + device usb 2.5 alias usb2_port6 off end + end + chip drivers/usb/acpi + device usb 2.6 alias usb2_port7 off end + end + chip drivers/usb/acpi + device usb 2.7 alias usb2_port8 off end + end + chip drivers/usb/acpi + device usb 2.8 alias usb2_port9 off end + end + chip drivers/usb/acpi + device usb 2.9 alias usb2_port10 off end + end + chip drivers/usb/acpi + device usb 3.0 alias usb3_port1 off end + end + chip drivers/usb/acpi + device usb 3.1 alias usb3_port2 off end + end + end + end + end + device pci 14.1 alias usb_otg off end + device pci 14.2 alias shared_sram off end + device pci 14.3 alias cnvi_wifi off end + device pci 15.0 alias i2c0 off end + device pci 15.1 alias i2c1 off end + device pci 15.2 alias i2c2 off end + device pci 15.3 alias i2c3 off end + device pci 16.0 alias heci1 off end + device pci 16.1 alias heci2 off end + device pci 16.4 alias heci3 off end + device pci 16.5 alias heci4 off end + device pci 17.0 alias sata off end + device pci 18.0 alias eheci1 off end + device pci 18.1 alias eheci2 off end + device pci 18.2 alias eheci3 off end + device pci 19.0 alias i2c4 off end + device pci 19.1 alias i2c5 off end + device pci 19.2 alias uart2 off end + device pci 1c.0 alias pcie_rp1 off end + device pci 1c.1 alias pcie_rp2 off end + device pci 1c.2 alias pcie_rp3 off end + device pci 1c.3 alias pcie_rp4 off end + device pci 1c.4 alias pcie_rp5 off end + device pci 1c.5 alias pcie_rp6 off end + device pci 1c.6 alias pcie_rp7 off end + device pci 1c.7 alias pcie_rp8 off end + device pci 1e.0 alias uart0 off end + device pci 1e.1 alias uart1 off end + device pci 1e.2 alias gspi0 off end + device pci 1e.3 alias gspi1 off end + device pci 1e.4 alias tsn_gbe1 off end + device pci 1e.5 alias tsn_gbe2 off end + device pci 1f.0 alias soc_espi on end + device pci 1f.1 alias p2sb off end + device pci 1f.2 alias pmc hidden end + device pci 1f.3 alias hda off end + device pci 1f.4 alias smbus off end + device pci 1f.5 alias fast_spi on end + device pci 1f.6 alias gbe off end + device pci 1f.7 alias npk off end + end +end diff --git a/src/soc/intel/meteorlake/cpu.c b/src/soc/intel/meteorlake/cpu.c new file mode 100644 index 0000000..64ba311 --- /dev/null +++ b/src/soc/intel/meteorlake/cpu.c @@ -0,0 +1,183 @@ +/* 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 <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> + +static void enable_x2apic(void) +{ + bool x2apic_support; + msr_t msr; + + if (!CONFIG(X2APIC_ONLY)) { + return; + } + + msr = rdmsr(LAPIC_BASE_MSR); + if (!(msr.lo & LAPIC_BASE_MSR_ENABLE)) { + msr.hi &= 0xffffff00; + msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK; + msr.lo |= LAPIC_DEFAULT_BASE; + msr.lo |= LAPIC_BASE_MSR_ENABLE; + wrmsr(LAPIC_BASE_MSR, msr); + msr = rdmsr(LAPIC_BASE_MSR); + } + + ASSERT(msr.lo & LAPIC_BASE_MSR_ENABLE); + + x2apic_support = !!(cpu_get_feature_flags_ecx() & BIT21); + + if (x2apic_support) { + msr.lo |= LAPIC_BASE_MSR_X2APIC_MODE; + wrmsr(LAPIC_BASE_MSR, msr); + msr = rdmsr(LAPIC_BASE_MSR); + ASSERT(!!(msr.lo & LAPIC_BASE_MSR_X2APIC_MODE)); + printk(BIOS_INFO, "LAPIC 0x%x switched to X2APIC mode.\n", lapicid()); + } + +} + +uint8_t get_supported_lpm_mask(void) +{ + uint8_t type = get_soctype(); + switch (type) { + case MTLM: /* fallthrough */ + case MTLP: + return LPM_S0i2_0 | LPM_S0i3_0; + default: + printk(BIOS_ERR, "Unknown MTL CPU type: %d\n", type); + return 0; + } +} + +static void soc_fsp_load(void) +{ + fsps_load(); +} + +static void configure_misc(void) +{ + msr_t msr; + + config_t *conf = 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); +} + +/* 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 the local CPU apics */ + enable_lapic_tpr(); + setup_lapic(); + + /* 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) +{ + /* + * enable_x2apic () is temporary WA for fixing S3 resume hang issue + * Once formal patch merge, this WA can be removed: + * formal patch: https://review.coreboot.org/c/coreboot/+/55262 + */ + enable_x2apic(); + + 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/crashlog.c b/src/soc/intel/meteorlake/crashlog.c new file mode 100644 index 0000000..83329e5 --- /dev/null +++ b/src/soc/intel/meteorlake/crashlog.c @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* UPDATEME: Need to update for MTL */ +#include <console/console.h> +#include <cbmem.h> +#include <delay.h> +#include <intelblocks/crashlog.h> +#include <string.h> +#include <soc/crashlog.h> +#include <arch/bert_storage.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> + +/* global crashLog info */ +static bool m_pmc_crashLog_support; +static bool m_pmc_crashLog_present; +static bool m_cpu_crashLog_support; +static bool m_cpu_crashLog_present; +static u32 m_pmc_crashLog_size; +static u32 m_cpu_crashLog_size; +static u32 cpu_crash_version; +static pmc_ipc_discovery_buf_t discovery_buf; +static pmc_crashlog_desc_table_t descriptor_table; +static tel_crashlog_devsc_cap_t cpu_cl_devsc_cap; +static cpu_crashlog_discovery_table_t cpu_cl_disc_tab; + +u32 __weak cl_get_cpu_mb_int_addr(void) +{ + return CRASHLOG_MAILBOX_INTF_ADDRESS; +} + +bool pmc_cl_discovery(void) +{ + u32 tmp_bar_addr = 0, desc_table_addr = 0; + + const struct pmc_ipc_buffer *req = { 0 }; + struct pmc_ipc_buffer *res = NULL; + uint32_t cmd_reg; + int r; + + cmd_reg = pmc_make_ipc_cmd(PMC_IPC_CMD_CRASHLOG, + PMC_IPC_CMD_ID_CRASHLOG_DISCOVERY, + PMC_IPC_CMD_SIZE_SHIFT); + printk(BIOS_DEBUG, "cmd_reg from pmc_make_ipc_cmd %d\n", cmd_reg); + + r = pmc_send_ipc_cmd(cmd_reg, req, res); + + if (r < 0) { + printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__); + return false; + } + discovery_buf.val_64_bits = ((u64)res->buf[1] << 32) | res->buf[0]; + + + if (discovery_buf.bits.supported != 1) { + printk(BIOS_INFO, "PCH crashlog feature not supported.\n"); + m_pmc_crashLog_support = false; + return false; + } + m_pmc_crashLog_support = true; + + /* Program BAR 0 and enable command register memory space decoding */ + tmp_bar_addr = SPI_BASE_ADDRESS; + pci_write_config32(PCH_DEV_SRAM, PCI_BASE_ADDRESS_0, tmp_bar_addr); + pci_or_config16(PCH_DEV_SRAM, PCI_COMMAND, PCI_COMMAND_MEMORY); + + if (discovery_buf.bits.discov_mechanism == 1) { + /* discovery mode */ + if (discovery_buf.bits.base_offset & BIT(31)) { + printk(BIOS_DEBUG, "PCH discovery to be used is disabled.\n"); + m_pmc_crashLog_present = false; + m_pmc_crashLog_size = 0; + return false; + } + desc_table_addr = tmp_bar_addr + discovery_buf.bits.desc_tabl_offset; + m_pmc_crashLog_size = pmc_cl_gen_descriptor_table(desc_table_addr, + &descriptor_table); + printk(BIOS_DEBUG, "PMC CrashLog size in discovery mode: 0x%X\n", + m_pmc_crashLog_size); + } else { + /* legacy mode */ + if (discovery_buf.bits.dis) { + printk(BIOS_DEBUG, "PCH crashlog is disabled in legacy mode.\n"); + m_pmc_crashLog_present = false; + return false; + } + m_pmc_crashLog_size = (discovery_buf.bits.size != 0) ? + (discovery_buf.bits.size * sizeof(u32)) : 0xC00; + printk(BIOS_DEBUG, "PMC crashlog size in legacy mode = 0x%x\n", + m_pmc_crashLog_size); + } + m_pmc_crashLog_present = true; + + return true; +} + +u32 cl_get_cpu_bar_addr(void) +{ + u32 base_addr = 0; + if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR0) { + base_addr = pci_read_config32(SA_DEV_TMT, PCI_BASE_ADDRESS_0) & + ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + } else if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR1) { + base_addr = pci_read_config32(SA_DEV_TMT, PCI_BASE_ADDRESS_1) & + ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + } else { + printk(BIOS_ERR, "Invalid TEL_CFG_BAR value %d, discovery failure expected.\n", + cpu_cl_devsc_cap.discovery_data.fields.t_bir_q); + } + + return base_addr; +} + + +u32 cl_get_cpu_tmp_bar(void) +{ + return SPI_BASE_ADDRESS; +} + +bool cl_pmc_sram_has_mmio_access(void) +{ + if (pci_read_config16(PCH_DEV_SRAM, PCI_VENDOR_ID) == 0xFFFF) { + printk(BIOS_ERR, "PMC SSRAM PCI device disabled. Can be enabled in device tree.\n"); + return false; + } + + return true; +} + +static bool cpu_cl_get_capability(tel_crashlog_devsc_cap_t *cl_devsc_cap) +{ + cl_devsc_cap->cap_data.data = pci_read_config32(SA_DEV_TMT, + TEL_DVSEC_OFFSET + TEL_DVSEC_PCIE_CAP_ID); + if (cl_devsc_cap->cap_data.fields.pcie_cap_id != TELEMETRY_EXTENDED_CAP_ID) { + printk(BIOS_DEBUG, "Read ID for Telemetry: 0x%x differs from expected: 0x%x\n", + cl_devsc_cap->cap_data.fields.pcie_cap_id, TELEMETRY_EXTENDED_CAP_ID); + return false; + } + + /* walk through the entries until crashLog entry */ + cl_devsc_cap->devsc_data.data_32[1] = pci_read_config32(SA_DEV_TMT, TEL_DVSEV_ID); + int new_offset = 0; + while (cl_devsc_cap->devsc_data.fields.devsc_id != CRASHLOG_DVSEC_ID) { + if (cl_devsc_cap->cap_data.fields.next_cap_offset == 0 + || cl_devsc_cap->cap_data.fields.next_cap_offset == 0xFFFF) { + printk(BIOS_DEBUG, "Read invalid pcie_cap_id value: 0x%x\n", + cl_devsc_cap->cap_data.fields.pcie_cap_id); + return false; + } + new_offset = cl_devsc_cap->cap_data.fields.next_cap_offset; + cl_devsc_cap->cap_data.data = pci_read_config32(SA_DEV_TMT, + new_offset + TEL_DVSEC_PCIE_CAP_ID); + cl_devsc_cap->devsc_data.data_32[1] = pci_read_config32(SA_DEV_TMT, + new_offset + TEL_DVSEV_ID); + } + cpu_crash_version = cl_devsc_cap->devsc_data.fields.devsc_ver; + + cl_devsc_cap->discovery_data.data = pci_read_config32(SA_DEV_TMT, new_offset + + TEL_DVSEV_DISCOVERY_TABLE_OFFSET); + + return true; +} + + +static bool cpu_cl_gen_discovery_table(void) +{ + u32 bar_addr = 0, disc_tab_addr = 0; + bar_addr = cl_get_cpu_bar_addr(); + disc_tab_addr = bar_addr + + cpu_cl_devsc_cap.discovery_data.fields.discovery_table_offset; + memset(&cpu_cl_disc_tab, 0, sizeof(cpu_crashlog_discovery_table_t)); + + printk(BIOS_DEBUG, "cpu discovery table offset: 0x%x\n", + cpu_cl_devsc_cap.discovery_data.fields.discovery_table_offset); + + cpu_cl_disc_tab.header.data = ((u64)read32((u32 *)disc_tab_addr) + + ((u64)read32((u32 *)(disc_tab_addr + 4)) << 32)); + + cpu_cl_disc_tab.cmd_mailbox.data = read32((u32 *)(disc_tab_addr + 8)); + cpu_cl_disc_tab.mailbox_data = read32((u32 *)(disc_tab_addr + 12)); + + printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer count: 0x%x\n", + cpu_cl_disc_tab.header.fields.count); + + int cur_offset = 0; + for (int i = 0; i < cpu_cl_disc_tab.header.fields.count; i++) { + cur_offset = 16 + 8*i; + cpu_cl_disc_tab.buffers[i].data = ((u64)read32((u32 *)(disc_tab_addr + + cur_offset)) + ((u64)read32((u32 *) + (disc_tab_addr + cur_offset + 4)) << 32)); + printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer: 0x%x size: " + "0x%x offset: 0x%x\n", i, cpu_cl_disc_tab.buffers[i].fields.size, + cpu_cl_disc_tab.buffers[i].fields.offset); + m_cpu_crashLog_size += cpu_cl_disc_tab.buffers[i].fields.size * sizeof(u32); + } + + m_cpu_crashLog_present = m_cpu_crashLog_size > 0; + + return true; +} + +bool cpu_cl_discovery(void) +{ + memset(&cpu_cl_devsc_cap, 0, sizeof(tel_crashlog_devsc_cap_t)); + + if (!cpu_cl_get_capability(&cpu_cl_devsc_cap)) { + printk(BIOS_ERR, "CPU crashlog capability not found.\n"); + m_cpu_crashLog_support = false; + return false; + } + + m_cpu_crashLog_support = true; + + /* Program BAR address and enable command register memory space decoding */ + u32 tmp_bar_addr = PCH_PWRM_BASE_ADDRESS; + printk(BIOS_DEBUG, "tmp_bar_addr: 0x%X\n", tmp_bar_addr); + + if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR0) { + pci_write_config32(SA_DEV_TMT, PCI_BASE_ADDRESS_0, tmp_bar_addr); + } else if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR1) { + pci_write_config32(SA_DEV_TMT, PCI_BASE_ADDRESS_1, tmp_bar_addr); + } else { + printk(BIOS_DEBUG, "invalid discovery data t_bir_q: 0x%x\n", + cpu_cl_devsc_cap.discovery_data.fields.t_bir_q); + return false; + } + pci_or_config16(SA_DEV_TMT, PCI_COMMAND, PCI_COMMAND_MEMORY); + + if (!cpu_cl_gen_discovery_table()) { + printk(BIOS_ERR, "CPU crashlog discovery table not valid.\n"); + m_cpu_crashLog_present = false; + return false; + } + m_cpu_crashLog_present = true; + + return true; +} + +void reset_discovery_buffers(void) +{ + memset(&discovery_buf, 0, sizeof(pmc_ipc_discovery_buf_t)); + memset(&descriptor_table, 0, sizeof(pmc_crashlog_desc_table_t)); + memset(&cpu_cl_devsc_cap, 0, sizeof(tel_crashlog_devsc_cap_t)); +} + +int cl_get_total_data_size(void) +{ + return m_pmc_crashLog_size + m_cpu_crashLog_size; +} + +pmc_ipc_discovery_buf_t cl_get_pmc_discovery_buf(void) +{ + return discovery_buf; +} + +pmc_crashlog_desc_table_t cl_get_pmc_descriptor_table(void) +{ + return descriptor_table; +} + +int cl_get_pmc_record_size(void) +{ + return m_pmc_crashLog_size; +} + +int cl_get_cpu_record_size(void) +{ + return m_cpu_crashLog_size; +} + +bool cl_cpu_data_present(void) +{ + return m_cpu_crashLog_present; +} + +bool cl_pmc_data_present(void) +{ + return m_pmc_crashLog_present; +} + +bool cpu_crashlog_support(void) +{ + return m_cpu_crashLog_support; +} + +bool pmc_crashlog_support(void) +{ + return m_pmc_crashLog_support; +} + +void update_new_pmc_crashlog_size(u32 *pmc_crash_size) +{ + m_pmc_crashLog_size = *pmc_crash_size; +} + +cpu_crashlog_discovery_table_t cl_get_cpu_discovery_table(void) +{ + return cpu_cl_disc_tab; +} + +void update_new_cpu_crashlog_size(u32 *cpu_crash_size) +{ + m_cpu_crashLog_size = *cpu_crash_size; +} diff --git a/src/soc/intel/meteorlake/dptf.c b/src/soc/intel/meteorlake/dptf.c new file mode 100644 index 0000000..98ccad7 --- /dev/null +++ b/src/soc/intel/meteorlake/dptf.c @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <drivers/intel/dptf/dptf.h> + +/* UPDATEME: HID need to checked for MTL */ +static const struct dptf_platform_info dptf_platform_info = { + .use_eisa_hids = false, + /* _HID for the toplevel DPTF device, typically _SB.DPTF */ + .dptf_device_hid = "INTC1041", + /* _HID for Intel DPTF Generic Device (these require PTYP as well) */ + .generic_hid = "INTC1046", + /* _HID for Intel DPTF Fan Device */ + .fan_hid = "INTC1048", +}; + +const struct dptf_platform_info *get_dptf_platform_info(void) +{ + return &dptf_platform_info; +} diff --git a/src/soc/intel/meteorlake/elog.c b/src/soc/intel/meteorlake/elog.c new file mode 100644 index 0000000..35100f9 --- /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 0000000..9cae319 --- /dev/null +++ b/src/soc/intel/meteorlake/finalize.c @@ -0,0 +1,78 @@ +/* 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 <device/pci.h> +#include <intelblocks/lpc_lib.h> +#include <intelblocks/pcr.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/tco.h> +#include <intelblocks/thermal.h> +#include <spi-generic.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> + +static void pch_handle_sideband(config_t *config) +{ + +} + +static void pch_finalize(void) +{ + config_t *config; + + /* TCO Lock down */ + tco_lockdown(); + + /* TODO: Add Thermal Configuration */ + + /* + * Disable ACPI PM timer based on dt policy + * + * Disabling ACPI PM timer is necessary for XTAL OSC shutdown. + * Disabling ACPI PM timer also switches off TCO + */ + config = config_of_soc(); + if (config->PmTimerDisabled) + pmc_disable_acpi_timer(); + + 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 soc_finalize(void *unused) +{ + printk(BIOS_DEBUG, "Finalizing chipset.\n"); + + pch_finalize(); + apm_control(APM_CNT_FINALIZE); + tbt_finalize(); + + /* Indicate finalize step with post code */ + post_code(POST_OS_BOOT); +} + +BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, soc_finalize, NULL); +BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_EXIT, 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 0000000..8ab5fbf --- /dev/null +++ b/src/soc/intel/meteorlake/fsp_params.c @@ -0,0 +1,504 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <cbfs.h> +#include <console/console.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->SerialIoI2cMode[i] : 0; + } + + max_port = get_max_gspi_port(); + for (i = 0; i < max_port; i++) { + s_cfg->SerialIoSpiCsMode[i] = config->SerialIoGSpiCsMode[i]; + s_cfg->SerialIoSpiCsState[i] = config->SerialIoGSpiCsState[i]; + s_cfg->SerialIoSpiMode[i] = is_devfn_enabled(gspi_dev[i]) ? + config->SerialIoGSpiMode[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->SerialIoUartMode[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", µcode_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) +{ + s_cfg->TcssAuxOri = config->TcssAuxOri; + + /* Explicitly clear this field to avoid using defaults */ + memset(s_cfg->IomTypeCPortPadCfg, 0, sizeof(s_cfg->IomTypeCPortPadCfg)); + + /* + * Set FSPS UPD ITbtConnectTopologyTimeoutInMs with value 0. FSP will + * evaluate this UPD value and skip sending command. There will be no + * delay for command completion. + */ + s_cfg->ITbtConnectTopologyTimeoutInMs = 0; + + /* D3Hot and D3Cold for TCSS */ + s_cfg->D3HotEnable = !config->TcssD3HotDisable; + s_cfg->D3ColdEnable = !config->TcssD3ColdDisable; +} + +static void fill_fsps_chipset_lockdown_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_meteorlake_config *config) +{ + /* Chipset Lockdown */ + if (get_lockdown_config() == CHIPSET_LOCKDOWN_COREBOOT) { + s_cfg->PchLockDownGlobalSmi = 0; + s_cfg->PchLockDownBiosInterface = 0; + s_cfg->PchUnlockGpioPads = 1; + s_cfg->RtcMemoryLock = 0; + } else { + s_cfg->PchLockDownGlobalSmi = 1; + s_cfg->PchLockDownBiosInterface = 1; + s_cfg->PchUnlockGpioPads = 0; + s_cfg->RtcMemoryLock = 1; + } + + /* 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++) { + 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_uart_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_meteorlake_config *config) +{ + /* PCH UART selection for FSP Debug */ + s_cfg->SerialIoDebugUartNumber = CONFIG_UART_FOR_CONSOLE; + ASSERT(ARRAY_SIZE(s_cfg->SerialIoUartAutoFlow) > CONFIG_UART_FOR_CONSOLE); + s_cfg->SerialIoUartAutoFlow[CONFIG_UART_FOR_CONSOLE] = 0; +} + +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->SataMode; + s_cfg->SataSalpSupport = config->SataSalpSupport; + memcpy(s_cfg->SataPortsEnable, config->SataPortsEnable, + sizeof(s_cfg->SataPortsEnable)); + memcpy(s_cfg->SataPortsDevSlp, config->SataPortsDevSlp, + 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->SataPwrOptimizeDisable); + /* + * 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->SataPortsEnableDitoConfig); i++) { + if (config->SataPortsEnableDitoConfig[i]) { + s_cfg->SataPortsDmVal[i] = config->SataPortsDmVal[i]; + s_cfg->SataPortsDitoVal[i] = config->SataPortsDitoVal[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->CnviBtCore; + s_cfg->CnviBtAudioOffload = config->CnviBtAudioOffload; + /* 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_thc_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_meteorlake_config *config) +{ + /* THC */ + s_cfg->ThcAssignment[0] = is_devfn_enabled(PCI_DEVFN_THC0) ? THC_0 : THC_NONE; + s_cfg->ThcAssignment[1] = is_devfn_enabled(PCI_DEVFN_THC1) ? THC_1 : THC_NONE; +} + +static void fill_fsps_tbt_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_meteorlake_config *config) +{ + /* USB4/TBT */ + for (int i = 0; i < ARRAY_SIZE(s_cfg->ITbtPcieRootPortEn); i++) + s_cfg->ITbtPcieRootPortEn[i] = is_devfn_enabled(PCI_DEVFN_TBT(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->HybridStorageMode; + } +} + +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_uart_params, + fill_fsps_sata_params, + fill_fsps_thermal_params, + fill_fsps_lan_params, + fill_fsps_cnvi_params, + fill_fsps_vmd_params, + fill_fsps_thc_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 0000000..2a34ab6 --- /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 0000000..50ab4a7 --- /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 0000000..9107725 --- /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 diff --git a/src/soc/intel/meteorlake/include/soc/crashlog.h b/src/soc/intel/meteorlake/include/soc/crashlog.h new file mode 100644 index 0000000..1abbc75 --- /dev/null +++ b/src/soc/intel/meteorlake/include/soc/crashlog.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_COMMON_BLOCK_CRASHLOG_LIB_H_ +#define _SOC_COMMON_BLOCK_CRASHLIB_LIB_H_ + +#include <types.h> + + +/* DVSEC capability Registers */ +#define TEL_DVSEC_OFFSET 0x100 +#define TEL_DVSEC_PCIE_CAP_ID 0x0 +#define TEL_DVSEC_NEXT_CAP 0x2 +#define TEL_DVSEV_ID 0x8 +#define TEL_DVSEV_DISCOVERY_TABLE_OFFSET 0xC +#define TELEMETRY_EXTENDED_CAP_ID 0x23 +#define CRASHLOG_DVSEC_ID 0x04 +#define TEL_DVSEC_TBIR_BAR0 0 +#define TEL_DVSEC_TBIR_BAR1 1 + +/* CPU CrashLog MMIO Registers */ +#define CRASHLOG_MAILBOX_INTF_ADDRESS 0x6038 +#define CRASHLOG_POINTER_SIZE_FIELD_OFFSET 0x04 + +#endif /* _SOC_COMMON_BLOCK_CRASHLOG_LIB_H_ */ 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 0000000..edc09a1 --- /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 0000000..74ee5ab --- /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 0000000..993ca35 --- /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 spi_protection_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/meminit.h b/src/soc/intel/meteorlake/include/soc/meminit.h new file mode 100644 index 0000000..ea4316a --- /dev/null +++ b/src/soc/intel/meteorlake/include/soc/meminit.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_METEORLAKE_MEMINIT_H_ +#define _SOC_METEORLAKE_MEMINIT_H_ + +#include <stddef.h> +#include <stdint.h> +#include <types.h> +#include <fsp/soc_binding.h> +#include <intelblocks/meminit.h> + +enum mem_type { + MEM_TYPE_DDR4, + MEM_TYPE_DDR5, + MEM_TYPE_LP4X, + MEM_TYPE_LP5X, +}; + +struct mem_ddr_config { + /* Dqs Pins Interleaved Setting. Enable/Disable Control */ + bool dq_pins_interleaved; +}; + +struct lpx_dq { + uint8_t dq0[BITS_PER_BYTE]; + uint8_t dq1[BITS_PER_BYTE]; +}; + +struct lpx_dqs { + uint8_t dqs0; + uint8_t dqs1; +}; + +struct lpx_dq_map { + struct lpx_dq ddr0; + struct lpx_dq ddr1; + struct lpx_dq ddr2; + struct lpx_dq ddr3; + struct lpx_dq ddr4; + struct lpx_dq ddr5; + struct lpx_dq ddr6; + struct lpx_dq ddr7; +}; + +struct lpx_dqs_map { + struct lpx_dqs ddr0; + struct lpx_dqs ddr1; + struct lpx_dqs ddr2; + struct lpx_dqs ddr3; + struct lpx_dqs ddr4; + struct lpx_dqs ddr5; + struct lpx_dqs ddr6; + struct lpx_dqs ddr7; +}; + +struct mem_lp5x_config { + uint8_t ccc_config; +}; + +struct rcomp { + /* + * Rcomp resistor value. This values represents the resistance in + * ohms of the rcomp resistor attached to the DDR_COMP pin on the SoC. + * + * Note: If mainboard users don't want to override rcomp related settings + * then associated rcomp UPDs will have its default value. + */ + uint16_t resistor; + /* Rcomp target values. */ + uint16_t targets[5]; +}; + +struct mb_cfg { + enum mem_type type; + struct rcomp rcomp; + union { + /* + * DQ CPU<>DRAM map: + * Index of the array represents DQ# on the CPU and the value represents DQ# on + * the DRAM part. + */ + uint8_t dq_map[CONFIG_DATA_BUS_WIDTH]; + struct lpx_dq_map lpx_dq_map; + }; + + union { + /* + * DQS CPU<>DRAM map: + * Index of the array represents DQS# on the CPU and the value represents DQS# + * on the DRAM part. + */ + uint8_t dqs_map[CONFIG_DATA_BUS_WIDTH/BITS_PER_BYTE]; + struct lpx_dqs_map lpx_dqs_map; + }; + + union { + struct mem_lp5x_config lp5x_config; + struct mem_ddr_config ddr_config; + }; + + /* Early Command Training Enable/Disable Control */ + bool ect; + + /* Board type */ + uint8_t UserBd; + + /* Command Mirror */ + uint8_t CmdMirror; + + /* Enable/Disable TxDqDqs Retraining for Lp4/Lp5/DDR */ + uint8_t LpDdrDqDqsReTraining; +}; + +void memcfg_init(FSP_M_CONFIG *mem_cfg, const struct mb_cfg *mb_cfg, + const struct mem_spd *spd_info, bool half_populated); + +#endif /* _SOC_METEORLAKE_MEMINIT_H_ */ 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 0000000..5129458 --- /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 2726851..c515475 100644 --- a/src/soc/intel/meteorlake/include/soc/p2sb.h +++ b/src/soc/intel/meteorlake/include/soc/p2sb.h @@ -1,13 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */
-/* - * This file is created based on Intel Alder Lake Processor PCH Datasheet - * Document number: 621483 - * Chapter number: 3 - */ - -#ifndef _SOC_ALDERLAKE_P2SB_H_ -#define _SOC_ALDERLAKE_P2SB_H_ +#ifndef _SOC_METEORLAKE_P2SB_H_ +#define _SOC_METEORLAKE_P2SB_H_
#define HPTC_OFFSET 0x60 #define HPTC_ADDR_ENABLE_BIT (1 << 7) 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 0000000..b29a348 --- /dev/null +++ b/src/soc/intel/meteorlake/include/soc/pcie.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_ALDERLAKE_PCIE_H__ +#define __SOC_ALDERLAKE_PCIE_H__ + +#include <intelblocks/pcie_rp.h> + +const struct pcie_rp_group *get_pcie_rp_table(void); + +#endif /* __SOC_ALDERLAKE_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 0000000..8f40f46 --- /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 0000000..d34164c --- /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 0000000..ac5c54a --- /dev/null +++ b/src/soc/intel/meteorlake/include/soc/soc_info.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#define MTLP_MAX_USB2_PORT 10 +#define MTLM_MAX_USB2_PORT 6 +#define MTLP_MAX_TCSS_PORT 4 +#define MTLM_MAX_TCSS_PORT 2 +#define MTLP_MAX_PCIE_PORT 12 +#define MTLM_MAX_PCIE_PORT 9 +#define MTLP_MAX_PCIE_CLOCK 9 +#define MTLM_MAX_PCIE_CLOCK 6 + +enum { + NOT_DETECTED = 0, + MTLM, + MTLP, +}; + +uint8_t get_soctype(void); +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_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 0000000..014e307 --- /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 0000000..e339c72 --- /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 0000000..678e63a --- /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 0000000..da1a299 --- /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.spi_protection_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.spi_protection_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/pcie_rp.c b/src/soc/intel/meteorlake/pcie_rp.c new file mode 100644 index 0000000..2f7b81c --- /dev/null +++ b/src/soc/intel/meteorlake/pcie_rp.c @@ -0,0 +1,33 @@ +/* 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 mtlm_rp_groups[] = { + { .slot = PCI_DEV_SLOT_PCIE_1, .count = 8 }, + { .slot = PCI_DEV_SLOT_PCIE_2, .count = 1 }, + { 0 } +}; + +static const struct pcie_rp_group mtlp_rp_groups[] = { + { .slot = PCI_DEV_SLOT_PCIE_1, .count = 8 }, + { .slot = PCI_DEV_SLOT_PCIE_2, .count = 3 }, + { .slot = PCI_DEV_SLOT_PCIE_3, .count = 1 }, + { 0 } +}; + +const struct pcie_rp_group *get_pcie_rp_table(void) +{ + uint8_t soc = get_soctype(); + + if (soc == MTLP) { + printk(BIOS_INFO, "soc_info: MTLP RP table is selected\n"); + return mtlp_rp_groups; + } else { + printk(BIOS_INFO, "soc_info: MTLM RP table is selected\n"); + return mtlm_rp_groups; + } +} diff --git a/src/soc/intel/meteorlake/pmc.c b/src/soc/intel/meteorlake/pmc.c new file mode 100644 index 0000000..256d4f5 --- /dev/null +++ b/src/soc/intel/meteorlake/pmc.c @@ -0,0 +1,169 @@ +/* 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/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_chip.h> +#include <stdint.h> +#include <bootstate.h> +#include <soc/cpu.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 pmc_init(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(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) Alder 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_acpi_mode_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(); +} + +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); + +struct device_operations pmc_ops = { + .read_resources = soc_pmc_read_resources, + .set_resources = noop_set_resources, + .init = soc_acpi_mode_init, + .enable = pmc_init, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_fill_ssdt = soc_pmc_fill_ssdt, +#endif + .scan_bus = scan_static_bus, +}; diff --git a/src/soc/intel/meteorlake/pmutil.c b/src/soc/intel/meteorlake/pmutil.c new file mode 100644 index 0000000..39e72ce --- /dev/null +++ b/src/soc/intel/meteorlake/pmutil.c @@ -0,0 +1,282 @@ +/* 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); +} + +void pmc_clear_pmcon_sts(void) +{ + uint32_t reg_val; + uint8_t *addr; + addr = pmc_mmio_regs(); + + reg_val = read32(addr + GEN_PMCON_A); + /* Clear SUS_PWR_FLR, GBL_RST_STS, HOST_RST_STS, PWR_FLR bits + * while retaining MS4V write-1-to-clear bit */ + reg_val &= ~(MS4V); + + write32((addr + GEN_PMCON_A), reg_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/smihandler.c b/src/soc/intel/meteorlake/smihandler.c new file mode 100644 index 0000000..3302be8 --- /dev/null +++ b/src/soc/intel/meteorlake/smihandler.c @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/pci_def.h> +#include <intelblocks/cse.h> +#include <intelblocks/smihandler.h> +#include <soc/soc_chip.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> + +/* + * Specific SOC SMI handler during ramstage finalize phase + * + * BIOS can't make CSME function disable as is due to POSTBOOT_SAI + * restriction in place from ADP chipset. Hence create SMI Handler to + * perform CSME function disabling logic during SMM mode. + */ +void smihandler_soc_at_finalize(void) +{ + const struct soc_intel_meteorlake_config *config; + + config = config_of_soc(); + + if (!config->HeciEnabled && CONFIG(HECI_DISABLE_USING_SMM)) + heci_disable(); +} + +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 0000000..9239978 --- /dev/null +++ b/src/soc/intel/meteorlake/soc_info.c @@ -0,0 +1,95 @@ +/* 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_soctype(void) +{ + uint16_t did; + +#ifdef __SIMPLE_DEVICE__ + did = pci_read_config16(PCI_DEVFN_ROOT, PCI_DEVICE_ID); +#else + struct device *dev; + dev = pcidev_path_on_root(PCI_DEVFN_ROOT); + did = pci_read_config16(dev, PCI_DEVICE_ID); +#endif + printk(BIOS_DEBUG, "soc_info: DID:0x%04x\n", did); + + if (did == PCI_DEVICE_ID_INTEL_MTL_M_ID) + return MTLM; + else + return MTLP; +} + +uint8_t get_max_usb20_port(void) +{ + uint8_t usb20_port = MTLM_MAX_USB2_PORT; + uint8_t soc = get_soctype(); + if (soc == MTLP) + usb20_port = MTLP_MAX_USB2_PORT; + 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 = MTLM_MAX_TCSS_PORT; + uint8_t soc = get_soctype(); + if (soc == MTLP) + tcss_port = MTLP_MAX_TCSS_PORT; + printk(BIOS_DEBUG, "soc_info: tcss_port:%d\n", tcss_port); + return tcss_port; +} + +uint8_t get_max_pcie_port(void) +{ + uint8_t pcie_port = MTLM_MAX_PCIE_PORT; + uint8_t soc = get_soctype(); + if (soc == MTLP) + pcie_port = MTLP_MAX_PCIE_PORT; + 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 = MTLM_MAX_PCIE_CLOCK; + uint8_t soc = get_soctype(); + if (soc == MTLP) + pcie_clock = MTLP_MAX_PCIE_CLOCK; + 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 0000000..c3ff05d --- /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 0000000..439f082 --- /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_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 0000000..b761d35 --- /dev/null +++ b/src/soc/intel/meteorlake/systemagent.c @@ -0,0 +1,103 @@ +/* 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_MMCONF_BASE_ADDRESS, CONFIG_MMCONF_LENGTH, + "PCIEXBAR" }, + { MCHBAR, MCH_BASE_ADDRESS, MCH_BASE_SIZE, "MCHBAR" }, + { 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_DEVICE_ID_INTEL_MTL_M_ID: + soc_config = &config->power_limits_config[MTL_M_POWER_LIMITS]; + break; + case PCI_DEVICE_ID_INTEL_MTL_P_ID_1: + soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_1]; + break; + case PCI_DEVICE_ID_INTEL_MTL_P_ID_2: + soc_config = &config->power_limits_config[MTL_P_POWER_LIMITS_2]; + 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/uart.c b/src/soc/intel/meteorlake/uart.c new file mode 100644 index 0000000..9f549c5 --- /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 0000000..9b4ac1b --- /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; +}