Saurabh Mishra has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/83798?usp=email )
Change subject: soc/intel/ptl: Do initial Panther Lake SoC commit till ramstage ......................................................................
soc/intel/ptl: Do initial Panther Lake SoC commit till ramstage
List of changes: 1. Add required SoC programming till ramstage. 2. Include only required headers into include/soc. 3. Skeleton code used to call FSP-S API.
BUG=b:348678529 TEST=Verified on Intel® Simics® Pre Silicon Simulation platform for PTL using google/fatcat mainboard.
Change-Id: Idc6fb11e9e84c28c7567ae2b7abc1ab832a88362 Signed-off-by: Saurabh Mishra mishra.saurabh@intel.com --- M src/soc/intel/pantherlake/Kconfig M src/soc/intel/pantherlake/Makefile.mk A src/soc/intel/pantherlake/acpi.c A src/soc/intel/pantherlake/chip.c A src/soc/intel/pantherlake/cpu.c A src/soc/intel/pantherlake/crashlog.c A src/soc/intel/pantherlake/elog.c A src/soc/intel/pantherlake/finalize.c A src/soc/intel/pantherlake/fsp_params.c A src/soc/intel/pantherlake/gspi.c A src/soc/intel/pantherlake/i2c.c A src/soc/intel/pantherlake/include/soc/cpu.h A src/soc/intel/pantherlake/include/soc/crashlog.h A src/soc/intel/pantherlake/include/soc/espi.h A src/soc/intel/pantherlake/include/soc/irq.h A src/soc/intel/pantherlake/include/soc/itss.h A src/soc/intel/pantherlake/include/soc/me.h A src/soc/intel/pantherlake/include/soc/nvs.h A src/soc/intel/pantherlake/include/soc/pcie.h A src/soc/intel/pantherlake/include/soc/ramstage.h A src/soc/intel/pantherlake/include/soc/serialio.h A src/soc/intel/pantherlake/include/soc/tcss.h A src/soc/intel/pantherlake/include/soc/usb.h A src/soc/intel/pantherlake/lockdown.c A src/soc/intel/pantherlake/me.c A src/soc/intel/pantherlake/pcie_rp.c A src/soc/intel/pantherlake/pmc.c A src/soc/intel/pantherlake/pmutil.c A src/soc/intel/pantherlake/retimer.c A src/soc/intel/pantherlake/smihandler.c A src/soc/intel/pantherlake/soundwire.c A src/soc/intel/pantherlake/spi.c A src/soc/intel/pantherlake/systemagent.c A src/soc/intel/pantherlake/tcss.c A src/soc/intel/pantherlake/uart.c A src/soc/intel/pantherlake/xhci.c 36 files changed, 3,857 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/98/83798/1
diff --git a/src/soc/intel/pantherlake/Kconfig b/src/soc/intel/pantherlake/Kconfig index 608c9b2..d2a0c2e 100644 --- a/src/soc/intel/pantherlake/Kconfig +++ b/src/soc/intel/pantherlake/Kconfig @@ -8,20 +8,43 @@ select CACHE_MRC_SETTINGS select CAR_ENHANCED_NEM select CPU_INTEL_COMMON + select CPU_INTEL_COMMON_VOLTAGE select CPU_INTEL_FIRMWARE_INTERFACE_TABLE + select CPU_SUPPORTS_PM_TIMER_EMULATION + select DEFAULT_SOFTWARE_CONNECTION_MANAGER if MAINBOARD_HAS_CHROMEOS + select DISPLAY_FSP_VERSION_INFO_2 select DRIVERS_USB_ACPI + select EDK2_CPU_TIMER_LIB if PAYLOAD_EDK2 + 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 FSP_USES_CB_DEBUG_EVENT_HANDLER select FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW + select GENERIC_GPIO_LIB + select HAVE_DEBUG_RAM_SETUP + select HAVE_FSP_GOP + select INTEL_DESCRIPTOR_MODE_CAPABLE + select HAVE_SMI_HANDLER select HAVE_X86_64_SUPPORT select IDT_IN_EVERY_STAGE + select INTEL_GMA_ACPI select INTEL_GMA_ADD_VBT if RUN_FSP_GOP select INTEL_DESCRIPTOR_MODE_CAPABLE select IOAPIC select MICROCODE_BLOB_UNDISCLOSED + select MP_SERVICES_PPI_V2 select MRC_SETTINGS_PROTECT + select PARALLEL_MP_AP_WORK + select MICROCODE_BLOB_UNDISCLOSED select PLATFORM_USES_FSP2_4 + select INTEL_GMA_OPREGION_2_1 + select INTEL_GMA_VERSION_2 + select REG_SCRIPT + select PMC_GLOBAL_RESET_ENABLE_LOCK + select PMC_EPOC select SOC_INTEL_COMMON + select SOC_INTEL_COMMON_ACPI_WAKE_SOURCE select SOC_INTEL_COMMON_BLOCK select SOC_INTEL_COMMON_BLOCK_ACPI select SOC_INTEL_COMMON_BLOCK_ACPI_CPPC @@ -31,20 +54,59 @@ select SOC_INTEL_COMMON_BLOCK_ACPI_PEP_LPM_REQ select SOC_INTEL_COMMON_BLOCK_CAR select SOC_INTEL_COMMON_BLOCK_CHIP_CONFIG + select SOC_INTEL_COMMON_BLOCK_CNVI 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_GPIO_IOSTANDBY + select SOC_INTEL_COMMON_BLOCK_GPIO_LOCK_USING_PCR + select SOC_INTEL_COMMON_BLOCK_GPIO_PMODE_4BITS select SOC_INTEL_COMMON_BLOCK_GSPI_VERSION_2 + select SOC_INTEL_COMMON_BLOCK_HDA + select SOC_INTEL_COMMON_BLOCK_HECI1_DISABLE_USING_PMC_IPC + select SOC_INTEL_COMMON_BLOCK_IAA select SOC_INTEL_COMMON_BLOCK_IOE_P2SB + select SOC_INTEL_COMMON_BLOCK_IPU + select SOC_INTEL_COMMON_BLOCK_TRACEHUB + select SOC_INTEL_COMMON_BLOCK_IRQ + select SOC_INTEL_COMMON_BLOCK_ME_SPEC_18 select SOC_INTEL_COMMON_BLOCK_MEMINIT + select SOC_INTEL_COMMON_BLOCK_OSSE + 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_TCSS + select SOC_INTEL_COMMON_BLOCK_TCSS_REG_ACCESS_SBI + select SOC_INTEL_COMMON_BLOCK_THERMAL_BEHIND_PMC + select SOC_INTEL_COMMON_BLOCK_USB4 + select SOC_INTEL_COMMON_BLOCK_USB4_PCIE + select SOC_INTEL_COMMON_BLOCK_USB4_XHCI + select SOC_INTEL_COMMON_BLOCK_XHCI + select SOC_INTEL_COMMON_BLOCK_XHCI_ELOG + select SOC_INTEL_COMMON_BASECODE + select SOC_INTEL_COMMON_BASECODE_RAMTOP + select SOC_INTEL_COMMON_FSP_RESET select SOC_INTEL_COMMON_PCH_CLIENT select SOC_INTEL_COMMON_RESET + select SOC_INTEL_COMMON_BLOCK_IOC + select SOC_INTEL_COMMON_BLOCK_PMC_EPOC + select SOC_INTEL_CSE_SEND_EOP_LATE if !MAINBOARD_HAS_CHROMEOS + select SOC_INTEL_CSE_SET_EOP + select SOC_INTEL_ENABLE_USB4_PCIE_RESOURCES + select SOC_INTEL_GFX_NON_PREFETCHABLE_MMIO select SOC_INTEL_IOE_DIE_SUPPORT + select SOC_INTEL_MEM_MAPPED_PM_CONFIGURATION select SSE2 select SUPPORT_CPU_UCODE_IN_CBFS select TSC_MONOTONIC_TIMER select UDELAY_TSC select UDK_202302_BINDING select USE_X86_64_SUPPORT + select X86_CLFLUSH_CAR help Intel Pantherlake support. Mainboards should specify the SoC type using the `SOC_INTEL_PANTHERLAKE_*` options instead @@ -98,6 +160,16 @@ Refer to Platform FSP integration guide document to know the exact FSP requirement for Heap setup.
+config CHIPSET_DEVICETREE + string + default "soc/intel/pantherlake/chipset.cb" + +config EXT_BIOS_WIN_BASE + default 0xf8000000 + +config EXT_BIOS_WIN_SIZE + default 0x2000000 + config IFD_CHIPSET string default "ptl" @@ -106,6 +178,26 @@ hex default 0x400000
+# Intel recommends reserving the PCIe TBT root port resources as below: +# - 42 buses +# - 194 MiB Non-prefetchable memory +# - 448 MiB Prefetchable memory +if SOC_INTEL_ENABLE_USB4_PCIE_RESOURCES + +config PCIEXP_HOTPLUG_BUSES + int + default 42 + +config PCIEXP_HOTPLUG_MEM + hex + default 0x6000000 + +config PCIEXP_HOTPLUG_PREFETCH_MEM + hex + default 0x800000000 + +endif # SOC_INTEL_ENABLE_USB4_PCIE_RESOURCES + config MAX_TBT_ROOT_PORTS int default 4 @@ -118,6 +210,14 @@ int default 9
+config SMM_TSEG_SIZE + hex + default 0x2000000 + +config SMM_RESERVED_SIZE + hex + default 0x200000 + config PCR_BASE_ADDRESS hex default 0x4000000000 @@ -185,6 +285,10 @@ default 0xfe02c000 depends on INTEL_LPSS_UART_FOR_CONSOLE
+config VBT_DATA_SIZE_KB + int + default 9 + # Clock divider parameters for 115200 baud rate # Baudrate = (UART source clcok * M) /(N *16) # PTL UART source clock: 100MHz @@ -260,6 +364,17 @@ int default 16
+config SOC_INTEL_CRASHLOG + def_bool n + select SOC_INTEL_COMMON_BLOCK_CRASHLOG + select ACPI_BERT + help + Enables CrashLog. + +config SOC_INTEL_GFX_FRAMEBUFFER_OFFSET + hex + default 0x800000 + config BUILDING_WITH_DEBUG_FSP bool "Debug FSP is used for the build" default n @@ -274,13 +389,11 @@ This is to control creation of ME_BIOS_PAYLOAD_HOB (MBP HOB) by FSP. Disabling it for the platforms, which do not use MBP HOB, can improve the boot time.
-endif - config SOC_INTEL_ACPI_GPIO_PINCTRL_COMPACT bool default n help - Since Lunarlake, OS pinctrl no long provides SOC GPIO pincntrl info. + Since Pantherlake, OS pinctrl no long provides SOC GPIO pincntrl info. Rather, firmware is responsible for providing such info via APCI. Firmware can provide entire PADs or excluding those non GPP_[group]_[number] at the end of each community. diff --git a/src/soc/intel/pantherlake/Makefile.mk b/src/soc/intel/pantherlake/Makefile.mk index 9d2e487..5cea250 100644 --- a/src/soc/intel/pantherlake/Makefile.mk +++ b/src/soc/intel/pantherlake/Makefile.mk @@ -5,20 +5,59 @@ subdirs-y += ../../../cpu/intel/microcode subdirs-y += ../../../cpu/intel/turbo
+# all (bootblock, verstage, romstage, postcar, ramstage) +all-y += gspi.c +all-y += i2c.c +all-y += pmutil.c +all-y += spi.c +all-y += uart.c +all-y += gpio.c + bootblock-y += bootblock/bootblock.c bootblock-y += bootblock/pcd.c bootblock-y += bootblock/report_platform.c bootblock-y += soc_info.c bootblock-y += espi.c bootblock-y += p2sb.c -bootblock-y += gpio.c
romstage-y += espi.c romstage-y += meminit.c +romstage-y += pcie_rp.c romstage-y += reset.c -romstage-y += gpio.c +romstage-y += soc_info.c + +ramstage-y += acpi.c +ramstage-y += chip.c +ramstage-y += cpu.c +ramstage-y += elog.c +ramstage-y += espi.c +ramstage-y += finalize.c +ramstage-y += fsp_params.c +ramstage-y += lockdown.c +ramstage-y += me.c +ramstage-y += p2sb.c +ramstage-y += pcie_rp.c +ramstage-y += pmc.c +ramstage-y += reset.c +ramstage-y += retimer.c +ramstage-y += soundwire.c +ramstage-y += systemagent.c +ramstage-y += tcss.c +ramstage-y += xhci.c +ramstage-$(CONFIG_SOC_INTEL_CRASHLOG) += crashlog.c +ramstage-y += soc_info.c + +smm-y += elog.c +smm-y += gpio.c +smm-y += p2sb.c +smm-y += pmutil.c +smm-y += smihandler.c +smm-y += uart.c +smm-y += xhci.c +smm-y += soc_info.c
CPPFLAGS_common += -I$(src)/soc/intel/pantherlake CPPFLAGS_common += -I$(src)/soc/intel/pantherlake/include
+CFLAGS_common += -fshort-wchar endif diff --git a/src/soc/intel/pantherlake/acpi.c b/src/soc/intel/pantherlake/acpi.c new file mode 100644 index 0000000..4508c9d --- /dev/null +++ b/src/soc/intel/pantherlake/acpi.c @@ -0,0 +1,311 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <acpi/acpi_gnvs.h> +#include <acpi/acpigen.h> +#include <arch/ioapic.h> +#include <arch/smp/mpspec.h> +#include <console/console.h> +#include <device/device.h> +#include <device/mmio.h> +#include <device/pci_ops.h> +#include <fw_config.h> +#include <intelblocks/cpulib.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/acpi.h> +#include <soc/cpu.h> +#include <soc/iomap.h> +#include <soc/nvs.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_chip.h> +#include <soc/systemagent.h> +#include <string.h> +#include <types.h> + +/* + * List of supported C-states in this processor. + */ +enum { + C_STATE_C0, /* 0 */ + C_STATE_C1, /* 1 */ + C_STATE_C1E, /* 2 */ + C_STATE_C6_SHORT_LAT, /* 3 */ + C_STATE_C6_LONG_LAT, /* 4 */ + C_STATE_C7_SHORT_LAT, /* 5 */ + C_STATE_C7_LONG_LAT, /* 6 */ + C_STATE_C7S_SHORT_LAT, /* 7 */ + C_STATE_C7S_LONG_LAT, /* 8 */ + C_STATE_C8, /* 9 */ + C_STATE_C9, /* 10 */ + C_STATE_C10, /* 11 */ + NUM_C_STATES +}; + +static const acpi_cstate_t cstate_map[NUM_C_STATES] = { + [C_STATE_C0] = {}, + [C_STATE_C1] = { + .latency = C1_LATENCY, + .power = C1_POWER, + .resource = MWAIT_RES(0, 0), + }, + [C_STATE_C1E] = { + .latency = C1_LATENCY, + .power = C1_POWER, + .resource = MWAIT_RES(0, 1), + }, + [C_STATE_C6_SHORT_LAT] = { + .latency = C6_LATENCY, + .power = C6_POWER, + .resource = MWAIT_RES(2, 0), + }, + [C_STATE_C6_LONG_LAT] = { + .latency = C6_LATENCY, + .power = C6_POWER, + .resource = MWAIT_RES(2, 1), + }, + [C_STATE_C7_SHORT_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 0), + }, + [C_STATE_C7_LONG_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 1), + }, + [C_STATE_C7S_SHORT_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 2), + }, + [C_STATE_C7S_LONG_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 3), + }, + [C_STATE_C8] = { + .latency = C8_LATENCY, + .power = C8_POWER, + .resource = MWAIT_RES(4, 0), + }, + [C_STATE_C9] = { + .latency = C9_LATENCY, + .power = C9_POWER, + .resource = MWAIT_RES(5, 0), + }, + [C_STATE_C10] = { + .latency = C10_LATENCY, + .power = C10_POWER, + .resource = MWAIT_RES(6, 0), + }, +}; + +static int cstate_set_non_s0ix[] = { + C_STATE_C1, + C_STATE_C6_LONG_LAT, + C_STATE_C7S_LONG_LAT +}; + +static int cstate_set_s0ix[] = { + C_STATE_C1, + C_STATE_C7S_LONG_LAT, + C_STATE_C10 +}; + +const acpi_cstate_t *soc_get_cstate_map(size_t *entries) +{ + static acpi_cstate_t map[MAX(ARRAY_SIZE(cstate_set_s0ix), + ARRAY_SIZE(cstate_set_non_s0ix))]; + int *set; + int i; + + config_t *config = config_of_soc(); + + int is_s0ix_enable = config->s0ix_enable; + + if (is_s0ix_enable) { + *entries = ARRAY_SIZE(cstate_set_s0ix); + set = cstate_set_s0ix; + } else { + *entries = ARRAY_SIZE(cstate_set_non_s0ix); + set = cstate_set_non_s0ix; + } + + for (i = 0; i < *entries; i++) { + map[i] = cstate_map[set[i]]; + map[i].ctype = i + 1; + } + return map; +} + +void soc_power_states_generation(int core_id, int cores_per_package) +{ + config_t *config = config_of_soc(); + + if (config->eist_enable) + /* Generate P-state tables */ + generate_p_state_entries(core_id, cores_per_package); +} + +void soc_fill_fadt(acpi_fadt_t *fadt) +{ + const uint16_t pmbase = ACPI_BASE_ADDRESS; + + config_t *config = config_of_soc(); + + fadt->pm_tmr_blk = pmbase + PM1_TMR; + fadt->pm_tmr_len = 4; + + fill_fadt_extended_pm_io(fadt); + + if (config->s0ix_enable) + fadt->flags |= ACPI_FADT_LOW_PWR_IDLE_S0; +} + +static struct min_sleep_state min_pci_sleep_states[] = { + { SA_DEVFN_ROOT, ACPI_DEVICE_SLEEP_D3 }, + { SA_DEVFN_IGD, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_IPU, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TBT0, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TBT1, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TBT2, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TBT3, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TCSSI_XHCI, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TCSSI_XDCI, ACPI_DEVICE_SLEEP_D3 }, + { SA_DEVFN_TCSS_DMA0, ACPI_DEVICE_SLEEP_D3 }, + { SA_DEVFN_TCSS_DMA1, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_THC0, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_THC1, ACPI_DEVICE_SLEEP_D3 }, + { PCH_DEVFN_XHCI, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_USBOTG, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_SRAM, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_CNVI_WIFI, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_I2C0, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_I2C1, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_I2C2, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_I2C3, ACPI_DEVICE_SLEEP_D3 }, + { PCH_DEVFN_CSE, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_I2C4, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_I2C5, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_UART2, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_PCIE1, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE2, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE3, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE4, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE5, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE6, ACPI_DEVICE_SLEEP_D0 }, + { PCH_DEVFN_PCIE7, ACPI_DEVICE_SLEEP_D0 }, + { PCH_DEVFN_PCIE8, ACPI_DEVICE_SLEEP_D0 }, + { PCH_DEVFN_PCIE9, ACPI_DEVICE_SLEEP_D0 }, + { PCH_DEVFN_PCIE10, ACPI_DEVICE_SLEEP_D0 }, + { PCH_DEVFN_PCIE11, ACPI_DEVICE_SLEEP_D0 }, + { PCH_DEVFN_PCIE12, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_UART0, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_UART1, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_GSPI0, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_GSPI1, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_ESPI, ACPI_DEVICE_SLEEP_D0 }, + { PCH_DEVFN_PMC, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_HDA, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_SPI, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_GBE, ACPI_DEVICE_SLEEP_D3 }, +}; + +struct min_sleep_state *soc_get_min_sleep_state_array(size_t *size) +{ + *size = ARRAY_SIZE(min_pci_sleep_states); + return min_pci_sleep_states; +} + +uint32_t soc_read_sci_irq_select(void) +{ + return read32p(soc_read_pmc_base() + IRQ_REG); +} + +static unsigned long soc_fill_dmar(unsigned long current) +{ + unsigned long tmp; + 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_devfn_enabled(PCI_DEVFN_IGD) && 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_from_hw(current, + IO_APIC_ADDR, 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_devfn_enabled(PCI_DEVFN_IGD) && 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); + if (is_devfn_enabled(PCI_DEVFN_NPU)) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_NPU, 0); + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IAA, 0); + acpi_dmar_satc_fixup(tmp, current); + + return current; +} + +unsigned long sa_write_acpi_tables(const struct device *dev, unsigned long current, + struct acpi_rsdp *rsdp) +{ + acpi_dmar_t *const dmar = (acpi_dmar_t *)current; + + /* + * Create DMAR table only if we have VT-d capability and FSP does not override its + * feature. + */ + if ((pci_read_config32(dev, CAPID0_A) & VTD_DISABLE) || + !(MCHBAR32(GFXVTBAR) & VTBAR_ENABLED)) + return current; + + printk(BIOS_DEBUG, "ACPI: * DMAR\n"); + acpi_create_dmar(dmar, DMAR_INTR_REMAP | DMA_CTRL_PLATFORM_OPT_IN_FLAG, soc_fill_dmar); + current += dmar->header.length; + current = acpi_align_current(current); + acpi_add_table(rsdp, dmar); + + return current; +} + +void soc_fill_gnvs(struct global_nvs *gnvs) +{ + config_t *config = config_of_soc(); + + /* Enable DPTF based on mainboard configuration */ + gnvs->dpte = config->dptf_enable; + + /* Set USB2/USB3 wake enable bitmaps. */ + gnvs->u2we = config->usb2_wake_enable_bitmap; + gnvs->u3we = config->usb3_wake_enable_bitmap; +} + +int soc_madt_sci_irq_polarity(int sci) +{ + return MP_IRQ_POLARITY_HIGH; +} diff --git a/src/soc/intel/pantherlake/chip.c b/src/soc/intel/pantherlake/chip.c new file mode 100644 index 0000000..4f74133 --- /dev/null +++ b/src/soc/intel/pantherlake/chip.c @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/device.h> +#include <device/pci.h> +#include <fsp/api.h> +#include <fsp/util.h> +#include <gpio.h> +#include <intelblocks/acpi.h> +#include <intelblocks/cfg.h> +#include <intelblocks/irq.h> +#include <intelblocks/gpio.h> +#include <intelblocks/itss.h> +#include <intelblocks/p2sb.h> +#include <intelblocks/pcie_rp.h> +#include <intelblocks/systemagent.h> +#include <intelblocks/tcss.h> +#include <intelblocks/xdci.h> +#include <soc/intel/common/vbt.h> +#include <soc/iomap.h> +#include <soc/itss.h> +#include <soc/p2sb.h> +#include <soc/pci_devs.h> +#include <soc/pcie.h> +#include <soc/ramstage.h> +#include <soc/soc_chip.h> +#include <soc/tcss.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"; + } + break; + case 3: + /* USB3 ports */ + switch (dev->path.usb.port_id) { + case 0: return "SS01"; + case 1: return "SS02"; + } + break; + } + printk(BIOS_DEBUG, "dev->path.type=%x\n", dev->path.usb.port_type); + return NULL; + } + if (dev->path.type != DEVICE_PATH_PCI) { + printk(BIOS_DEBUG, "dev->path.type=%x\n", dev->path.type); + return NULL; + } + + switch (dev->path.pci.devfn) { + case PCI_DEVFN_ROOT: return "MCHC"; + case PCI_DEVFN_TCSS_XHCI: return "TXHC"; + case PCI_DEVFN_TCSS_XDCI: return "TXDC"; + case PCI_DEVFN_TCSS_DMA0: return "TDM0"; + case PCI_DEVFN_TCSS_DMA1: return "TDM1"; + case PCI_DEVFN_TBT0: return "TRP0"; + case PCI_DEVFN_TBT1: return "TRP1"; + case PCI_DEVFN_TBT2: return "TRP2"; + case PCI_DEVFN_TBT3: return "TRP3"; + case PCI_DEVFN_IPU: return "IPU0"; + case PCI_DEVFN_I3C1: return "I3C1"; + case PCI_DEVFN_I3C2: return "I3C2"; + 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_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"; + case PCI_DEVFN_IGD: return "GFX0"; + } + printk(BIOS_DEBUG, "Missing ACPI Name for PCI: 00:%02x.%01x\n", + PCI_SLOT(dev->path.pci.devfn), PCI_FUNC(dev->path.pci.devfn)); + return NULL; +} +#endif + +/* SoC routine to fill GPIO PM mask and value for GPIO_MISCCFG register */ +static void soc_fill_gpio_pm_configuration(void) +{ + uint8_t value[TOTAL_GPIO_COMM]; + const config_t *config = config_of_soc(); + + if (config->gpio_override_pm) + memcpy(value, config->gpio_pm, sizeof(value)); + else + memset(value, MISCCFG_GPIO_PM_CONFIG_BITS, sizeof(value)); + + gpio_pm_configure(value, TOTAL_GPIO_COMM); +} + +void soc_init_pre_device(void *chip_info) +{ + /* Perform silicon specific init. */ + fsp_silicon_init(); + + /* Display FIRMWARE_VERSION_INFO_HOB */ + fsp_display_fvi_version_hob(); + + soc_fill_gpio_pm_configuration(); + + /* Swap enabled PCI ports in device tree if needed. */ + pcie_rp_update_devicetree(get_pcie_rp_table()); +} + +static void cpu_fill_ssdt(const struct device *dev) +{ + if (!generate_pin_irq_map()) + printk(BIOS_ERR, "Failed to generate ACPI _PRT table!\n"); + + generate_cpu_entries(dev); +} + +static void cpu_set_north_irqs(struct device *dev) +{ + irq_program_non_pch(); +} + +static struct device_operations pci_domain_ops = { + .read_resources = &pci_domain_read_resources, + .set_resources = &pci_domain_set_resources, + .scan_bus = &pci_host_bridge_scan_bus, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_name = &soc_acpi_name, + .acpi_fill_ssdt = ssdt_set_above_4g_pci, +#endif +}; + +static struct device_operations cpu_bus_ops = { + .read_resources = noop_read_resources, + .set_resources = noop_set_resources, + .enable_resources = cpu_set_north_irqs, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_fill_ssdt = cpu_fill_ssdt, +#endif +}; + +static void soc_enable(struct device *dev) +{ + /* + * Set the operations if it is a special bus type or a hidden PCI + * device. + */ + if (dev->path.type == DEVICE_PATH_DOMAIN) + dev->ops = &pci_domain_ops; + else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) + dev->ops = &cpu_bus_ops; + else if (dev->path.type == DEVICE_PATH_PCI && + dev->path.pci.devfn == PCI_DEVFN_PMC) + dev->ops = &pmc_ops; + else if (dev->path.type == DEVICE_PATH_PCI && + dev->path.pci.devfn == PCI_DEVFN_P2SB) + dev->ops = &soc_p2sb_ops; + else if (dev->path.type == DEVICE_PATH_GPIO) + block_gpio_enable(dev); +} + +struct chip_operations soc_intel_pantherlake_ops = { + .name = "Intel Pantherlake", + .enable_dev = &soc_enable, + .init = &soc_init_pre_device, +}; diff --git a/src/soc/intel/pantherlake/cpu.c b/src/soc/intel/pantherlake/cpu.c new file mode 100644 index 0000000..a778381 --- /dev/null +++ b/src/soc/intel/pantherlake/cpu.c @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/intel/common/common.h> +#include <cpu/intel/smm_reloc.h> +#include <cpu/intel/turbo.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/mp.h> +#include <cpu/x86/msr.h> +#include <device/pci.h> +#include <fsp/api.h> +#include <intelblocks/acpi.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> + +bool cpu_soc_is_in_untrusted_mode(void) +{ + msr_t msr; + + msr = rdmsr(MSR_BIOS_DONE); + return !!(msr.lo & ENABLE_IA_UNTRUSTED); +} + +void cpu_soc_bios_done(void) +{ + msr_t msr; + + msr = rdmsr(MSR_BIOS_DONE); + msr.lo |= ENABLE_IA_UNTRUSTED; + wrmsr(MSR_BIOS_DONE, msr); +} + +uint8_t get_supported_lpm_mask(void) +{ + return LPM_S0i2_0 | LPM_S0i2_1 | LPM_S0i2_2; +} + +static void soc_fsp_load(void) +{ + fsps_load(); +} + +static void configure_misc(void) +{ + msr_t msr; + + config_t *conf = (config_t *)config_of_soc(); + + msr = rdmsr(IA32_MISC_ENABLE); + msr.lo |= (1 << 0); /* Fast String enable */ + msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ + wrmsr(IA32_MISC_ENABLE, msr); + + /* Set EIST status */ + cpu_set_eist(conf->eist_enable); + + /* Disable Thermal interrupts */ + msr.lo = 0; + msr.hi = 0; + wrmsr(IA32_THERM_INTERRUPT, msr); + + /* Enable package critical interrupt only */ + msr.lo = 1 << 4; + msr.hi = 0; + wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr); + + /* Enable PROCHOT */ + msr = rdmsr(MSR_POWER_CTL); + msr.lo |= (1 << 0); /* Enable Bi-directional PROCHOT as an input*/ + msr.lo |= (1 << 23); /* Lock it */ + wrmsr(MSR_POWER_CTL, msr); +} + +enum core_type get_soc_cpu_type(void) +{ + if (cpu_is_hybrid_supported()) + return cpu_get_cpu_type(); + else + return CPUID_CORE_TYPE_INTEL_CORE; +} + +bool soc_is_nominal_freq_supported(void) +{ + return true; +} + +static void enable_x2apic(void) +{ + if (!CONFIG(X2APIC_LATE_WORKAROUND)) + return; + + enable_lapic_mode(true); +} + +/* All CPUs including BSP will run the following function. */ +void soc_core_init(struct device *cpu) +{ + /* Clear out pending MCEs */ + /* TODO(adurbin): This should only be done on a cold boot. Also, some + * of these banks are core vs package scope. For now every CPU clears + * every bank. */ + mca_configure(); + + enable_x2apic(); + + enable_lapic_tpr(); + + /* Configure Enhanced SpeedStep and Thermal Sensors */ + configure_misc(); + + enable_pm_timer_emulation(); + + /* Enable Direct Cache Access */ + configure_dca_cap(); + + /* Set energy policy */ + set_energy_perf_bias(ENERGY_POLICY_NORMAL); + + /* Enable Turbo */ + enable_turbo(); + + if (CONFIG(INTEL_TME) && is_tme_supported()) + set_tme_core_activate(); +} + +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 mp_init_cpus(struct bus *cpu_bus) +{ + if (mp_init_with_smm(cpu_bus, &mp_ops)) + printk(BIOS_ERR, "MP initialization failure.\n"); + + /* Thermal throttle activation offset */ + configure_tcc_thermal_target(); +} diff --git a/src/soc/intel/pantherlake/crashlog.c b/src/soc/intel/pantherlake/crashlog.c new file mode 100644 index 0000000..1f6f4b5 --- /dev/null +++ b/src/soc/intel/pantherlake/crashlog.c @@ -0,0 +1,415 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/bert_storage.h> +#include <console/console.h> +#include <cbmem.h> +#include <delay.h> +#include <device/pci_ops.h> +#include <intelblocks/crashlog.h> +#include <intelblocks/pmc_ipc.h> +#include <soc/crashlog.h> +#include <arch/bert_storage.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <string.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; +} + +/* Get the SRAM BAR. */ +static uintptr_t get_sram_bar(pci_devfn_t sram_devfn) +{ + uintptr_t sram_bar; + const struct device *dev; + struct resource *res; + + dev = pcidev_path_on_root(sram_devfn); + if (!dev) { + printk(BIOS_ERR, "device: 0x%x not found!\n", sram_devfn); + return 0; + } + + res = probe_resource(dev, PCI_BASE_ADDRESS_0); + if (!res) { + printk(BIOS_ERR, "SOC SRAM device not found!\n"); + return 0; + } + + /* Get the base address of the resource */ + sram_bar = res->base; + + return sram_bar; +} + +static void configure_sram(const struct device *sram_dev, u32 base_addr) +{ + pci_update_config16(sram_dev, PCI_COMMAND, ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY), 0); + + /* Program BAR 0 and enable command register memory space decoding */ + pci_write_config32(sram_dev, PCI_BASE_ADDRESS_0, base_addr); + pci_or_config16(sram_dev, PCI_COMMAND, PCI_COMMAND_MEMORY); +} + +void cl_get_pmc_sram_data(void) +{ + u32 *soc_pmc_dest = NULL; + u32 pmc_sram_base = cl_get_cpu_tmp_bar(); + u32 pmc_crashLog_size = cl_get_pmc_record_size(); + + if (!pmc_sram_base) { + printk(BIOS_ERR, "PMC SRAM base not valid\n"); + return; + } + + if (!pmc_crashLog_size) { + printk(BIOS_ERR, "No PMC crashlog records\n"); + return; + } + + if (!cl_pmc_sram_has_mmio_access()) + return; + + printk(BIOS_DEBUG, "PMC crashLog size : 0x%x\n", pmc_crashLog_size); + + /* allocate memory for the PMC crash records to be copied */ + unsigned long pmc_cl_cbmem_addr; + + pmc_cl_cbmem_addr = (unsigned long) cbmem_add(CBMEM_ID_PMC_CRASHLOG, + pmc_crashLog_size); + if (!pmc_cl_cbmem_addr) { + printk(BIOS_ERR, "Unable to allocate CBMEM PMC crashLog entry.\n"); + return; + } + + memset((void *)pmc_cl_cbmem_addr, 0, pmc_crashLog_size); + soc_pmc_dest = (u32 *)(uintptr_t) pmc_cl_cbmem_addr; + + bool pmc_sram = true; + + /* process crashlog records for SOC PMC SRAM */ + for (int i = 0; i < descriptor_table.numb_regions + 1; i++) { + printk(BIOS_DEBUG, "Region[0x%x].Tag=0x%x offset=0x%x, size=0x%x\n", + i, + descriptor_table.regions[i].bits.assign_tag, + descriptor_table.regions[i].bits.offset, + descriptor_table.regions[i].bits.size); + + if (!descriptor_table.regions[i].bits.size) + continue; + + if (descriptor_table.regions[i].bits.assign_tag == + CRASHLOG_DESCRIPTOR_TABLE_TAG_SOC) { + + if (cl_copy_data_from_sram(pmc_sram_base, + descriptor_table.regions[i].bits.offset, + descriptor_table.regions[i].bits.size, + soc_pmc_dest, + i, + pmc_sram)) { + soc_pmc_dest = (u32 *)((u32)soc_pmc_dest + + (descriptor_table.regions[i].bits.size + * sizeof(u32))); + } else { + pmc_crashLog_size -= descriptor_table.regions[i].bits.size * + sizeof(u32); + printk(BIOS_DEBUG, "PMC crashlog size adjusted to: 0x%x\n", + pmc_crashLog_size); + } + } + } + update_new_pmc_crashlog_size(&pmc_crashLog_size); + + /* when bit 7 of discov cmd resp is set -> bit 2 of size field */ + cl_pmc_re_arm_after_reset(); + + /* Clear the SSRAM region after copying the error log */ + cl_pmc_clear(); +} + +bool pmc_cl_discovery(void) +{ + u32 bar_addr = 0, desc_table_addr = 0; + + const struct pmc_ipc_buffer req = { 0 }; + struct pmc_ipc_buffer res; + 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 in %s\n", cmd_reg, __func__); + + 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.conv_val_64_bits = ((u64)res.buf[1] << 32) | res.buf[0]; + + if ((discovery_buf.conv_bits64.supported != 1) || + (discovery_buf.conv_bits64.discov_mechanism == 0) || + (discovery_buf.conv_bits64.crash_dis_sts == 1)) { + printk(BIOS_INFO, "PCH crashlog feature not supported.\n"); + m_pmc_crashLog_support = false; + m_pmc_crashLog_size = 0; + printk(BIOS_DEBUG, "discovery_buf supported: %d, mechanism: %d, CrashDisSts: %d\n", + discovery_buf.conv_bits64.supported, + discovery_buf.conv_bits64.discov_mechanism, + discovery_buf.conv_bits64.crash_dis_sts); + return false; + } + + printk(BIOS_INFO, "PMC crashlog feature is supported.\n"); + m_pmc_crashLog_support = true; + + /* Program BAR 0 and enable command register memory space decoding */ + bar_addr = get_sram_bar(PCI_DEVFN_SRAM); + if (bar_addr == 0) { + printk(BIOS_ERR, "PCH SRAM not available, crashlog feature can't be enabled.\n"); + return false; + } + + configure_sram(PCI_DEV_SRAM, bar_addr); + + desc_table_addr = bar_addr + discovery_buf.conv_bits64.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); + m_pmc_crashLog_present = m_pmc_crashLog_size > 0; + + 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(PCI_DEV_TELEMETRY, 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(PCI_DEV_TELEMETRY, 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 get_sram_bar(PCI_DEVFN_SRAM); +} + +bool cl_pmc_sram_has_mmio_access(void) +{ + if (pci_read_config16(PCI_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(PCI_DEV_TELEMETRY, + 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(PCI_DEV_TELEMETRY, 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(PCI_DEV_TELEMETRY, + new_offset + TEL_DVSEC_PCIE_CAP_ID); + cl_devsc_cap->devsc_data.data_32[1] = pci_read_config32(PCI_DEV_TELEMETRY, + 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(PCI_DEV_TELEMETRY, 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(); + + if (!bar_addr) + return false; + + 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 = 8 + 24*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); + } + + if (m_cpu_crashLog_size > 0) + m_cpu_crashLog_present = true; + else + m_cpu_crashLog_present = false; + + 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) +{ + printk(BIOS_DEBUG, "crashlog size:pmc-0x%x, cpu-0x%x\n", + m_pmc_crashLog_size, m_cpu_crashLog_size); + 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/pantherlake/elog.c b/src/soc/intel/pantherlake/elog.c new file mode 100644 index 0000000..dc03c21 --- /dev/null +++ b/src/soc/intel/pantherlake/elog.c @@ -0,0 +1,217 @@ +/* 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_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_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 & TCO2_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/pantherlake/finalize.c b/src/soc/intel/pantherlake/finalize.c new file mode 100644 index 0000000..6f5127b --- /dev/null +++ b/src/soc/intel/pantherlake/finalize.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/io.h> +#include <bootstate.h> +#include <console/console.h> +#include <cpu/x86/smm.h> +#include <delay.h> +#include <device/mmio.h> +#include <device/pci.h> +#include <intelblocks/cse.h> +#include <intelblocks/lpc_lib.h> +#include <intelblocks/pcr.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/systemagent.h> +#include <intelblocks/tco.h> +#include <intelblocks/thermal.h> +#include <intelpch/lockdown.h> +#include <soc/p2sb.h> +#include <soc/pci_devs.h> +#include <soc/pcr_ids.h> +#include <soc/pm.h> +#include <soc/smbus.h> +#include <soc/soc_chip.h> +#include <soc/systemagent.h> +#include <spi-generic.h> +#include <timer.h> + +static void pch_handle_sideband(config_t *config) +{ + +} + +static void pch_finalize(void) +{ + config_t *config = config_of_soc(); + + /* TCO Lock down */ + tco_lockdown(); + + /* TODO: Add Thermal Configuration */ + + pch_handle_sideband(config); + + pmc_clear_pmcon_sts(); +} + +static void tbt_finalize(void) +{ + int i; + const struct device *dev; + + /* Disable Thunderbolt PCIe root ports bus master */ + for (i = 0; i < NUM_TBT_FUNCTIONS; i++) { + dev = pcidev_path_on_root(PCI_DEVFN_TBT(i)); + if (dev) + pci_dev_disable_bus_master(dev); + } +} + +static void sa_finalize(void) +{ + if (get_lockdown_config() == CHIPSET_LOCKDOWN_COREBOOT) + sa_lock_pam(); +} + +static void heci_finalize(void) +{ + heci_set_to_d0i3(); + if (CONFIG(DISABLE_HECI1_AT_PRE_BOOT)) + heci1_disable(); +} + +static void soc_finalize(void *unused) +{ + printk(BIOS_DEBUG, "Finalizing chipset.\n"); + + pch_finalize(); + apm_control(APM_CNT_FINALIZE); + tbt_finalize(); + sa_finalize(); + if (CONFIG(USE_FSP_NOTIFY_PHASE_READY_TO_BOOT) && + CONFIG(USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE)) + heci_finalize(); + + /* Indicate finalize step with post code */ + post_code(POSTCODE_OS_BOOT); +} + +BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, soc_finalize, NULL); +/* + * The purpose of this change is to accommodate more time to push out sending + * CSE EOP messages at post. + */ +BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, soc_finalize, NULL); diff --git a/src/soc/intel/pantherlake/fsp_params.c b/src/soc/intel/pantherlake/fsp_params.c new file mode 100644 index 0000000..2a5be98 --- /dev/null +++ b/src/soc/intel/pantherlake/fsp_params.c @@ -0,0 +1,555 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <cbfs.h> +#include <console/console.h> +#include <cpu/intel/cpu_ids.h> +#include <cpu/intel/microcode.h> +#include <device/device.h> +#include <device/pci.h> +#include <fsp/api.h> +#include <fsp/fsp_debug_event.h> +#include <fsp/ppi/mp_service_ppi.h> +#include <fsp/util.h> +#include <option.h> +#include <intelblocks/cse.h> +#include <intelblocks/irq.h> +#include <intelblocks/lpss.h> +#include <intelblocks/mp_init.h> +#include <intelblocks/systemagent.h> +#include <intelblocks/xdci.h> +#include <intelblocks/tcss.h> +#include <intelpch/lockdown.h> +#include <security/vboot/vboot_common.h> +#include <soc/cpu.h> +#include <soc/gpio_soc_defs_lnl.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 <stdlib.h> +#include <string.h> +#include <types.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 + +#define MAX_ONBOARD_PCIE_DEVICES 256 + +/* + * 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 i3c_dev[] = { + PCI_DEVFN_I3C1, + PCI_DEVFN_I3C2, +}; + +static const pci_devfn_t gspi_dev[] = { + PCI_DEVFN_GSPI0, + PCI_DEVFN_GSPI1, + PCI_DEVFN_GSPI2, +}; + +static const pci_devfn_t uart_dev[] = { + PCI_DEVFN_UART0, + PCI_DEVFN_UART1, + PCI_DEVFN_UART2 +}; + +static const struct slot_irq_constraints irq_constraints[] = { + { + .slot = PCI_DEV_SLOT_IGD, + .fns = { + /* INTERRUPT_PIN is RO/0x01 */ + FIXED_INT_ANY_PIRQ(PCI_DEV_SLOT_IGD, PCI_INT_A), + }, + }, + { + .slot = PCI_DEV_SLOT_DPTF, + .fns = { + ANY_PIRQ(PCI_DEVFN_DPTF), + }, + }, + { + .slot = PCI_DEV_SLOT_IPU, + .fns = { + /* INTERRUPT_PIN is RO/0x01, and INTERRUPT_LINE is RW, + but S0ix fails when not set to 16 (b/193434192) */ + FIXED_INT_PIRQ(PCI_DEVFN_IPU, PCI_INT_A, PIRQ_A), + }, + }, + { + .slot = PCI_DEV_SLOT_TBT, + .fns = { + ANY_PIRQ(PCI_DEVFN_TBT0), + ANY_PIRQ(PCI_DEVFN_TBT1), + ANY_PIRQ(PCI_DEVFN_TBT2), + ANY_PIRQ(PCI_DEVFN_TBT3), + }, + }, + { + .slot = PCI_DEV_SLOT_NPU, + .fns = { + /* INTERRUPT_PIN is RO/0x01 */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_NPU, PCI_INT_A), + }, + }, + { + .slot = PCI_DEV_SLOT_TCSS, + .fns = { + ANY_PIRQ(PCI_DEVFN_TCSS_XHCI), + }, + }, + { + .slot = PCI_DEV_SLOT_THC, + .fns = { + ANY_PIRQ(PCI_DEVFN_THC0), + ANY_PIRQ(PCI_DEVFN_THC1), + }, + }, + { + .slot = PCI_DEV_SLOT_ISH, + .fns = { + DIRECT_IRQ(PCI_DEVFN_ISH), + }, + }, + { + .slot = PCI_DEV_SLOT_XHCI, + .fns = { + ANY_PIRQ(PCI_DEVFN_XHCI), + DIRECT_IRQ(PCI_DEVFN_USBOTG), + ANY_PIRQ(PCI_DEVFN_CNVI_WIFI), + }, + }, + { + .slot = PCI_DEV_SLOT_SIO0, + .fns = { + DIRECT_IRQ(PCI_DEVFN_I2C0), + DIRECT_IRQ(PCI_DEVFN_I2C1), + DIRECT_IRQ(PCI_DEVFN_I2C2), + DIRECT_IRQ(PCI_DEVFN_I2C3), + }, + }, + { + .slot = PCI_DEV_SLOT_CSE, + .fns = { + ANY_PIRQ(PCI_DEVFN_CSE), + ANY_PIRQ(PCI_DEVFN_CSE_2), + ANY_PIRQ(PCI_DEVFN_CSE_IDER), + ANY_PIRQ(PCI_DEVFN_CSE_KT), + ANY_PIRQ(PCI_DEVFN_CSE_3), + ANY_PIRQ(PCI_DEVFN_CSE_4), + }, + }, + { + .slot = PCI_DEV_SLOT_SIO1, + .fns = { + DIRECT_IRQ(PCI_DEVFN_I2C4), + DIRECT_IRQ(PCI_DEVFN_I2C5), + DIRECT_IRQ(PCI_DEVFN_UART2), + }, + }, + { + .slot = PCI_DEV_SLOT_PCIE_1, + .fns = { + FIXED_INT_PIRQ(PCI_DEVFN_PCIE1, PCI_INT_A, PIRQ_A), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE2, PCI_INT_B, PIRQ_B), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE3, PCI_INT_C, PIRQ_C), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE4, PCI_INT_D, PIRQ_D), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE5, PCI_INT_A, PIRQ_A), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE6, PCI_INT_B, PIRQ_B), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE7, PCI_INT_C, PIRQ_C), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE8, PCI_INT_D, PIRQ_D), + }, + }, + { + .slot = PCI_DEV_SLOT_PCIE_2, + .fns = { + FIXED_INT_PIRQ(PCI_DEVFN_PCIE9, PCI_INT_A, PIRQ_A), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE10, PCI_INT_B, PIRQ_B), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE11, PCI_INT_C, PIRQ_C), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE12, PCI_INT_D, PIRQ_D), + }, + }, + { + .slot = PCI_DEV_SLOT_SIO2, + .fns = { + /* UART0 shares an interrupt line with TSN0, so must use + a PIRQ */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_UART0, PCI_INT_A), + /* UART1 shares an interrupt line with TSN1, so must use + a PIRQ */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_UART1, PCI_INT_B), + DIRECT_IRQ(PCI_DEVFN_GSPI0), + DIRECT_IRQ(PCI_DEVFN_GSPI1), + }, + }, + { + .slot = PCI_DEV_SLOT_ESPI, + .fns = { + ANY_PIRQ(PCI_DEVFN_HDA), + ANY_PIRQ(PCI_DEVFN_SMBUS), + ANY_PIRQ(PCI_DEVFN_GBE), + /* INTERRUPT_PIN is RO/0x01 */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_NPK, PCI_INT_A), + }, + }, +}; + +static const SI_PCH_DEVICE_INTERRUPT_CONFIG *pci_irq_to_fsp(size_t *out_count) +{ + const struct pci_irq_entry *entry = get_cached_pci_irqs(); + SI_PCH_DEVICE_INTERRUPT_CONFIG *config; + size_t pch_total = 0; + size_t cfg_count = 0; + + if (!entry) + return NULL; + + /* Count PCH devices */ + while (entry) { + if (is_pch_slot(entry->devfn)) + ++pch_total; + entry = entry->next; + } + + /* Convert PCH device entries to FSP format */ + config = calloc(pch_total, sizeof(*config)); + entry = get_cached_pci_irqs(); + while (entry) { + if (!is_pch_slot(entry->devfn)) { + entry = entry->next; + continue; + } + + config[cfg_count].Device = PCI_SLOT(entry->devfn); + config[cfg_count].Function = PCI_FUNC(entry->devfn); + config[cfg_count].IntX = (SI_PCH_INT_PIN)entry->pin; + config[cfg_count].Irq = entry->irq; + ++cfg_count; + + entry = entry->next; + } + + *out_count = cfg_count; + + return config; +} + +/* + * 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 (CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE)) + ctl = L1_SS_DISABLED; + else if ((ctl > L1_SS_L1_2) || (ctl == L1_SS_FSP_DEFAULT)) + ctl = L1_SS_L1_2; + return ctl - 1; +} + +/* + * get_aspm_control() ensures that the right UPD value is set in fsp_params. + * 0: Disable ASPM + * 1: L0s only + * 2: L1 only + * 3: L0s and L1 + * 4: Auto configuration + */ +static unsigned int get_aspm_control(enum ASPM_control ctl) +{ + if (ctl > ASPM_AUTO) + ctl = ASPM_AUTO; + return ctl; +} + +__weak void mainboard_update_soc_chip_config(struct soc_intel_pantherlake_config *config) +{ + /* Override settings per board. */ +} + +static void fill_fsps_lpss_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_microcode_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_cpu_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + + +static void fill_fsps_igd_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_tcss_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_chipset_lockdown_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_xhci_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_xdci_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_uart_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_thermal_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ + +} + +static void fill_fsps_irq_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void evaluate_ssid(const struct device *dev, uint16_t *svid, uint16_t *ssid) +{ + /* Settings per board. */ +} + +/* + * Programming SSID before FSP-S is important because SSID registers of a few PCIE + * devices (e.g. IPU, Crashlog, XHCI, TCSS_XHCI etc.) are locked after FSP-S hence + * provide a custom SSID (same as DID by default) value via UPD. + */ +static void fill_fsps_pci_ssid_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_lan_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_cnvi_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ + +} + +static void fill_fsps_pmcpd_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_thc_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_tbt_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_8254_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_pm_timer_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_pcie_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_misc_power_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + + +static void fill_fsps_ufs_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void fill_fsps_ai_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + /* Settings per board. */ +} + +static void arch_silicon_init_params(FSPS_ARCH2_UPD *s_arch_cfg) +{ + /* Assign FspEventHandler arch Upd to use coreboot debug event handler */ + if (CONFIG(FSP_USES_CB_DEBUG_EVENT_HANDLER) && CONFIG(CONSOLE_SERIAL) && + CONFIG(FSP_ENABLE_SERIAL_DEBUG)) + s_arch_cfg->FspEventHandler = (uintptr_t)((FSP_EVENT_HANDLER *) + fsp_debug_event_handler); + +} + +static void soc_silicon_init_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_config *config) +{ + const void (*fill_fsps_params[])(FSP_S_CONFIG *s_cfg, + const struct soc_intel_pantherlake_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_thermal_params, + fill_fsps_lan_params, + fill_fsps_cnvi_params, + fill_fsps_pmcpd_params, + fill_fsps_thc_params, + fill_fsps_tbt_params, + fill_fsps_8254_params, + fill_fsps_pm_timer_params, + fill_fsps_pcie_params, + fill_fsps_misc_power_params, + fill_fsps_ufs_params, + fill_fsps_ai_params, + fill_fsps_irq_params, + fill_fsps_pci_ssid_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_pantherlake_config *config; + FSP_S_CONFIG *s_cfg = &supd->FspsConfig; + FSPS_ARCH2_UPD *s_arch_cfg = &supd->FspsArchUpd; + + config = config_of_soc(); + arch_silicon_init_params(s_arch_cfg); + /* Override settings per board if required. */ + mainboard_update_soc_chip_config(config); + 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 + * 2 | Before BIOS Reset CPL is set by FSP-S | for CPU specific init + */ +void platform_fsp_silicon_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; + case 2: + /* CPU specific initialization here */ + printk(BIOS_DEBUG, "FSP MultiPhaseSiInit %s/%s called\n", + __FILE__, __func__); + before_post_cpus_init(); + /* Enable BIOS Reset CPL */ + enable_bios_reset_cpl(); + 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/pantherlake/gspi.c b/src/soc/intel/pantherlake/gspi.c new file mode 100644 index 0000000..2a34ab6 --- /dev/null +++ b/src/soc/intel/pantherlake/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/pantherlake/i2c.c b/src/soc/intel/pantherlake/i2c.c new file mode 100644 index 0000000..50ab4a7 --- /dev/null +++ b/src/soc/intel/pantherlake/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/pantherlake/include/soc/cpu.h b/src/soc/intel/pantherlake/include/soc/cpu.h new file mode 100644 index 0000000..3ef6df5 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/cpu.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_CPU_H_ +#define _SOC_PANTHERLAKE_CPU_H_ + +/* Latency times in us */ +#define C1_LATENCY 1 +#define C6_LATENCY 127 +#define C7_LATENCY 253 +#define C8_LATENCY 260 +#define C9_LATENCY 487 +#define C10_LATENCY 1048 + +/* Power in units of mW */ +#define C1_POWER 0x3e8 +#define C6_POWER 0x15e +#define C7_POWER 0xc8 +#define C8_POWER 0xc8 +#define C9_POWER 0xc8 +#define C10_POWER 0xc8 + +/* Get a bitmask of supported LPM states */ +uint8_t get_supported_lpm_mask(void); + +#endif /* _SOC_PANTHERLAKE_CPU_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/crashlog.h b/src/soc/intel/pantherlake/include/soc/crashlog.h new file mode 100644 index 0000000..e13fd64 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/crashlog.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_CRASHLOG_LIB_H_ +#define _SOC_PANTHERLAKE_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_PANTHERLAKE_CRASHLOG_LIB_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/espi.h b/src/soc/intel/pantherlake/include/soc/espi.h new file mode 100644 index 0000000..ca1b8f6 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/espi.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_ESPI_H_ +#define _SOC_PANTHERLAKE_ESPI_H_ + +/* PCI Configuration Space (D31:F0): ESPI */ +#define SCI_IRQ_SEL (7 << 0) +#define SCIS_IRQ9 0 +#define SCIS_IRQ10 1 +#define SCIS_IRQ11 2 +#define SCIS_IRQ20 4 +#define SCIS_IRQ21 5 +#define SCIS_IRQ22 6 +#define SCIS_IRQ23 7 +#define SERIRQ_CNTL 0x64 +#define ESPI_IO_DEC 0x80 /* IO Decode Ranges Register */ +#define COMA_RANGE 0x0 /* 0x3F8 - 0x3FF COM1*/ +#define COMB_RANGE 0x1 /* 0x2F8 - 0x2FF COM2*/ +#define ESPI_GEN1_DEC 0x84 /* ESPI IF Generic Decode Range 1 */ +#define ESPI_GEN2_DEC 0x88 /* ESPI IF Generic Decode Range 2 */ +#define ESPI_GEN3_DEC 0x8c /* ESPI IF Generic Decode Range 3 */ +#define ESPI_GEN4_DEC 0x90 /* ESPI IF Generic Decode Range 4 */ +#define LGMR 0x98 /* ESPI Generic Memory Range */ +#define PCCTL 0xE0 /* PCI Clock Control */ +#define CLKRUN_EN (1 << 0) + +#endif /* _SOC_PANTHERLAKE_ESPI_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/irq.h b/src/soc/intel/pantherlake/include/soc/irq.h new file mode 100644 index 0000000..95ad8cb --- /dev/null +++ b/src/soc/intel/pantherlake/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 //_SOC_IRQ_H_ diff --git a/src/soc/intel/pantherlake/include/soc/itss.h b/src/soc/intel/pantherlake/include/soc/itss.h new file mode 100644 index 0000000..0fe88ce --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/itss.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SOC_PANTHERLAKE_ITSS_H +#define SOC_PANTHERLAKE_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_PANTHERLAKE_ITSS_H */ diff --git a/src/soc/intel/pantherlake/include/soc/me.h b/src/soc/intel/pantherlake/include/soc/me.h new file mode 100644 index 0000000..1bd5850 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/me.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_ME_H_ +#define _SOC_PANTHERLAKE_ME_H_ + +#include <stdint.h> + +/* ME Host Firmware Status register 1 */ +union me_hfsts1 { + u32 data; + struct { + u32 working_state: 4; + u32 mfg_mode: 1; + u32 fpt_bad: 1; + u32 operation_state: 3; + u32 fw_init_complete: 1; + u32 ft_bup_ld_flr: 1; + u32 update_in_progress: 1; + u32 error_code: 4; + u32 operation_mode: 4; + u32 reset_count: 4; + u32 boot_options_present: 1; + u32 invoke_enhance_dbg_mode: 1; + u32 bist_test_state: 1; + u32 bist_reset_request: 1; + u32 current_power_source: 2; + u32 reserved: 1; + u32 d0i3_support_valid: 1; + } __packed fields; +}; + +/* ME Host Firmware Status Register 3 */ +union me_hfsts3 { + u32 data; + struct { + u32 reserved_0: 4; + u32 fw_sku: 3; + u32 reserved_7: 2; + u32 reserved_9: 2; + u32 resered_11: 3; + u32 resered_14: 16; + u32 reserved_30: 2; + } __packed fields; +}; +#endif /* _SOC_PANTHERLAKE_ME_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/nvs.h b/src/soc/intel/pantherlake/include/soc/nvs.h new file mode 100644 index 0000000..8e47721 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/nvs.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_NVS_H_ +#define _SOC_PANTHERLAKE_NVS_H_ + +#include <intelblocks/nvs.h> + +#endif /* _SOC_PANTHERLAKE_NVS_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/pcie.h b/src/soc/intel/pantherlake/include/soc/pcie.h new file mode 100644 index 0000000..25d56f9 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/pcie.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_PANTHERLAKE_PCIE_H__ +#define __SOC_PANTHERLAKE_PCIE_H__ + +#include <intelblocks/pcie_rp.h> + +const struct pcie_rp_group *get_pcie_rp_table(void); + +#endif /* __SOC_PANTHERLAKE_PCIE_H__ */ diff --git a/src/soc/intel/pantherlake/include/soc/ramstage.h b/src/soc/intel/pantherlake/include/soc/ramstage.h new file mode 100644 index 0000000..b0bb56d --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/ramstage.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_RAMSTAGE_H_ +#define _SOC_PANTHERLAKE_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_pantherlake_config *config); +void soc_init_pre_device(void *chip_info); + +#endif /* _SOC_PANTHERLAKE_RAMSTAGE_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/serialio.h b/src/soc/intel/pantherlake/include/soc/serialio.h new file mode 100644 index 0000000..8e37147 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/serialio.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_SERIALIO_H_ +#define _SOC_PANTHERLAKE_SERIALIO_H_ + +enum { + PchSerialIoDisabled, + PchSerialIoPci, + PchSerialIoHidden, + PchSerialIoLegacyUart, + PchSerialIoSkipInit +}; + +enum { + PchSerialIoIndexI2C0, + PchSerialIoIndexI2C1, + PchSerialIoIndexI2C2, + PchSerialIoIndexI2C3, + PchSerialIoIndexI2C4, + PchSerialIoIndexI2C5 +}; + +enum { + PchSerialIoIndexI3C0, + PchSerialIoIndexI3C1 +}; + +enum { + PchSerialIoIndexGSPI0, + PchSerialIoIndexGSPI1, + PchSerialIoIndexGSPI2, +}; + +enum { + PchSerialIoIndexUART0, + PchSerialIoIndexUART1, + PchSerialIoIndexUART2 +}; + +#endif /* _SOC_PANTHERLAKE_SERIALIO_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/tcss.h b/src/soc/intel/pantherlake/include/soc/tcss.h new file mode 100644 index 0000000..d423901 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/tcss.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _SOC_PANTHERLAKE_TCSS_H_ +#define _SOC_PANTHERLAKE_TCSS_H_ + +/* Thunderbolt firmware IMR status */ +#define IOM_CSME_IMR_TBT_STATUS 0x14 +#define TBT_VALID_AUTHENTICATION BIT(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) + +/* + * The PCI-SIG engineering change requirement provides the ACPI additions for firmware latency + * optimization. Both of FW_RESET_TIME and FW_D3HOT_TO_D0_TIME are applicable to the upstream + * port of the USB4/TBT topology. + */ +/* Number of microseconds to wait after a conventional reset */ +#define FW_RESET_TIME 50000 + +/* Number of microseconds to wait after data link layer active report */ +#define FW_DL_UP_TIME 1 + +/* Number of microseconds to wait after a function level reset */ +#define FW_FLR_RESET_TIME 1 + +/* Number of microseconds to wait from D3 hot to D0 transition */ +#define FW_D3HOT_TO_D0_TIME 50000 + +/* Number of microseconds to wait after setting the VF enable bit */ +#define FW_VF_ENABLE_TIME 1 + +#endif /* _SOC_PANTHERLAKE_TCSS_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/usb.h b/src/soc/intel/pantherlake/include/soc/usb.h new file mode 100644 index 0000000..62bedf8 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/usb.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_USB_H_ +#define _SOC_PANTHERLAKE_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 /* _SOC_PANTHERLAKE_USB_H_ */ diff --git a/src/soc/intel/pantherlake/lockdown.c b/src/soc/intel/pantherlake/lockdown.c new file mode 100644 index 0000000..2994952 --- /dev/null +++ b/src/soc/intel/pantherlake/lockdown.c @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/mmio.h> +#include <intelblocks/cfg.h> +#include <intelblocks/pcr.h> +#include <intelblocks/pmclib.h> +#include <intelpch/lockdown.h> +#include <soc/pcr_ids.h> +#include <soc/pm.h> +#include <stdint.h> + +/* PCR PSTH Control Register */ +#define PCR_PSTH_CTRLREG 0x1d00 +#define PSTH_CTRLREG_IOSFPTCGE BIT(2) + +static void pmc_lockdown_cfg(int chipset_lockdown) +{ + uint8_t *pmcbase = pmc_mmio_regs(); + + /* PMSYNC */ + setbits32(pmcbase + PMSYNC_TPR_CFG, PCH2CPU_TPR_CFG_LOCK); + /* Lock down ABASE and sleep stretching policy */ + setbits32(pmcbase + GEN_PMCON_B, SLP_STR_POL_LOCK | ACPI_BASE_LOCK); + + if (chipset_lockdown == CHIPSET_LOCKDOWN_COREBOOT) + setbits32(pmcbase + GEN_PMCON_B, SMI_LOCK); + + if (!CONFIG(USE_FSP_NOTIFY_PHASE_POST_PCI_ENUM)) { + setbits32(pmcbase + GEN_PMCON_B, ST_FDIS_LOCK); + setbits32(pmcbase + SSML, SSML_SSL_EN); + setbits32(pmcbase + PM_CFG, PM_CFG_DBG_MODE_LOCK | + PM_CFG_XRAM_READ_DISABLE); + } + + /* Send PMC IPC to inform about both BIOS Reset and PCI enumeration done */ + pmc_send_bios_reset_pci_enum_done(); +} + +static void soc_die_lockdown_cfg(void) +{ + if (CONFIG(USE_FSP_NOTIFY_PHASE_POST_PCI_ENUM)) + return; + + /* Enable IOSF Primary Trunk Clock Gating */ + pcr_rmw32(PID_PSTH, PCR_PSTH_CTRLREG, ~0, PSTH_CTRLREG_IOSFPTCGE); +} + +void soc_lockdown_config(int chipset_lockdown) +{ + /* PMC lock down configuration */ + pmc_lockdown_cfg(chipset_lockdown); + /* SOC Die lock down configuration */ + soc_die_lockdown_cfg(); +} diff --git a/src/soc/intel/pantherlake/me.c b/src/soc/intel/pantherlake/me.c new file mode 100644 index 0000000..7ef2f71 --- /dev/null +++ b/src/soc/intel/pantherlake/me.c @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <console/console.h> +#include <intelblocks/cse.h> +#include <soc/me.h> +#include <stdint.h> + +/* Host Firmware Status Register 2 */ +union me_hfsts2 { + uint32_t data; + struct { + uint32_t nftp_load_failure : 1; + uint32_t icc_prog_status : 2; + uint32_t invoke_mebx : 1; + uint32_t cpu_replaced : 1; + uint32_t rsvd0 : 1; + uint32_t mfs_failure : 1; + uint32_t warm_reset_rqst : 1; + uint32_t cpu_replaced_valid : 1; + uint32_t low_power_state : 1; + uint32_t me_power_gate : 1; + uint32_t ipu_needed : 1; + uint32_t forced_safe_boot : 1; + uint32_t rsvd1 : 2; + uint32_t listener_change : 1; + uint32_t status_data : 8; + uint32_t current_pmevent : 4; + uint32_t phase : 4; + } __packed fields; +}; + +/* Host Firmware Status Register 4 */ +union me_hfsts4 { + uint32_t data; + struct { + uint32_t rsvd0 : 9; + uint32_t enforcement_flow : 1; + uint32_t sx_resume_type : 1; + uint32_t rsvd1 : 1; + uint32_t tpms_disconnected : 1; + uint32_t rvsd2 : 1; + uint32_t fwsts_valid : 1; + uint32_t boot_guard_self_test : 1; + uint32_t rsvd3 : 16; + } __packed fields; +}; + +/* Host Firmware Status Register 5 */ +union me_hfsts5 { + uint32_t data; + struct { + uint32_t acm_active : 1; + uint32_t valid : 1; + uint32_t result_code_source : 1; + uint32_t error_status_code : 5; + uint32_t acm_done_sts : 1; + uint32_t timeout_count : 7; + uint32_t scrtm_indicator : 1; + uint32_t inc_boot_guard_acm : 4; + uint32_t inc_key_manifest : 4; + uint32_t inc_boot_policy : 4; + uint32_t rsvd0 : 2; + uint32_t start_enforcement : 1; + } __packed fields; +}; + +/* Host Firmware Status Register 6 */ +union me_hfsts6 { + uint32_t data; + struct { + uint32_t force_boot_guard_acm : 1; + uint32_t cpu_debug_disable : 1; + uint32_t bsp_init_disable : 1; + uint32_t protect_bios_env : 1; + uint32_t rsvd0 : 2; + uint32_t error_enforce_policy : 2; + uint32_t measured_boot : 1; + uint32_t verified_boot : 1; + uint32_t boot_guard_acmsvn : 4; + uint32_t kmsvn : 4; + uint32_t bpmsvn : 4; + uint32_t key_manifest_id : 4; + uint32_t boot_policy_status : 1; + uint32_t error : 1; + uint32_t boot_guard_disable : 1; + uint32_t fpf_disable : 1; + uint32_t fpf_soc_lock : 1; + uint32_t txt_support : 1; + } __packed fields; +}; + +static void dump_me_status(void *unused) +{ + union me_hfsts1 hfsts1; + union me_hfsts2 hfsts2; + union me_hfsts3 hfsts3; + union me_hfsts4 hfsts4; + union me_hfsts5 hfsts5; + union me_hfsts6 hfsts6; + + if (!is_cse_enabled()) + return; + + hfsts1.data = me_read_config32(PCI_ME_HFSTS1); + hfsts2.data = me_read_config32(PCI_ME_HFSTS2); + hfsts3.data = me_read_config32(PCI_ME_HFSTS3); + hfsts4.data = me_read_config32(PCI_ME_HFSTS4); + hfsts5.data = me_read_config32(PCI_ME_HFSTS5); + hfsts6.data = me_read_config32(PCI_ME_HFSTS6); + + printk(BIOS_DEBUG, "ME: HFSTS1 : 0x%08X\n", hfsts1.data); + printk(BIOS_DEBUG, "ME: HFSTS2 : 0x%08X\n", hfsts2.data); + printk(BIOS_DEBUG, "ME: HFSTS3 : 0x%08X\n", hfsts3.data); + printk(BIOS_DEBUG, "ME: HFSTS4 : 0x%08X\n", hfsts4.data); + printk(BIOS_DEBUG, "ME: HFSTS5 : 0x%08X\n", hfsts5.data); + printk(BIOS_DEBUG, "ME: HFSTS6 : 0x%08X\n", hfsts6.data); + + /* + * Lock Descriptor, and Fuses must be programmed on a + * production system to indicate ME Manufacturing mode is disabled. + */ + printk(BIOS_DEBUG, "ME: Manufacturing Mode : %s\n", + ((hfsts1.fields.mfg_mode == 0) && + (hfsts6.fields.fpf_soc_lock == 1)) ? "NO" : "YES"); + /* + * The SPI Protection Mode bit reflects SPI descriptor + * locked(0) or unlocked(1). + */ + printk(BIOS_DEBUG, "ME: SPI Protection Mode Enabled : %s\n", + hfsts1.fields.mfg_mode ? "NO" : "YES"); + printk(BIOS_DEBUG, "ME: FW Partition Table : %s\n", + hfsts1.fields.fpt_bad ? "BAD" : "OK"); + printk(BIOS_DEBUG, "ME: Bringup Loader Failure : %s\n", + hfsts1.fields.ft_bup_ld_flr ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Firmware Init Complete : %s\n", + hfsts1.fields.fw_init_complete ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Boot Options Present : %s\n", + hfsts1.fields.boot_options_present ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Update In Progress : %s\n", + hfsts1.fields.update_in_progress ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: D0i3 Support : %s\n", + hfsts1.fields.d0i3_support_valid ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Low Power State Enabled : %s\n", + hfsts2.fields.low_power_state ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Replaced : %s\n", + hfsts2.fields.cpu_replaced ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Replacement Valid : %s\n", + hfsts2.fields.cpu_replaced_valid ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Current Working State : %u\n", + hfsts1.fields.working_state); + printk(BIOS_DEBUG, "ME: Current Operation State : %u\n", + hfsts1.fields.operation_state); + printk(BIOS_DEBUG, "ME: Current Operation Mode : %u\n", + hfsts1.fields.operation_mode); + printk(BIOS_DEBUG, "ME: Error Code : %u\n", + hfsts1.fields.error_code); + printk(BIOS_DEBUG, "ME: Enhanced Debug Mode : %s\n", + hfsts1.fields.invoke_enhance_dbg_mode ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Debug Disabled : %s\n", + hfsts6.fields.cpu_debug_disable ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: TXT Support : %s\n", + hfsts6.fields.txt_support ? "YES" : "NO"); +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_EXIT, print_me_fw_version, NULL); +BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_EXIT, dump_me_status, NULL); diff --git a/src/soc/intel/pantherlake/pcie_rp.c b/src/soc/intel/pantherlake/pcie_rp.c new file mode 100644 index 0000000..ff19d41 --- /dev/null +++ b/src/soc/intel/pantherlake/pcie_rp.c @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <intelblocks/pcie_rp.h> +#include <soc/pci_devs.h> +#include <soc/pcie.h> +#include <soc/soc_info.h> + +static const struct pcie_rp_group ptlp_rp_groups[] = { + { .slot = PCI_DEV_SLOT_PCIE_1, .count = 8, .lcap_port_base = 1 }, + { .slot = PCI_DEV_SLOT_PCIE_2, .count = 4, .lcap_port_base = 1 }, + { 0 } +}; + +const struct pcie_rp_group *get_pcie_rp_table(void) +{ + const struct pcie_rp_group *rp_groups = NULL; + + printk(BIOS_INFO, "soc_info: PTLP RP table is selected\n"); + rp_groups = ptlp_rp_groups; + return rp_groups; +} + +enum pcie_rp_type soc_get_pcie_rp_type(const struct device *dev) +{ + return PCIE_RP_PCH; +} + +int soc_get_cpu_rp_vw_idx(const struct device *dev) +{ + return -1; +} diff --git a/src/soc/intel/pantherlake/pmc.c b/src/soc/intel/pantherlake/pmc.c new file mode 100644 index 0000000..c902f99 --- /dev/null +++ b/src/soc/intel/pantherlake/pmc.c @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpigen.h> +#include <bootstate.h> +#include <console/console.h> +#include <device/device.h> +#include <device/mmio.h> +#include <drivers/intel/pmc_mux/chip.h> +#include <intelblocks/acpi.h> +#include <intelblocks/pmc.h> +#include <intelblocks/pmc_ipc.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/rtc.h> +#include <soc/cpu.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_chip.h> +#include <stdint.h> + +#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); + + pmc_read_qdf(); +} + +static void soc_pmc_read_resources(struct device *dev) +{ + struct resource *res; + + /* Add the fixed MMIO resource */ + mmio_range(dev, PWRMBASE, PCH_PWRM_BASE_ADDRESS, PCH_PWRM_BASE_SIZE); + + /* 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) Panther 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 lnl_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(&lnl_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 + * LNL has its PMC device available for device_operations, it can be + * done from the "ops->init" callback. + */ + pmc_set_acpi_mode(); + + /* + * Disable ACPI PM timer based on Kconfig + * + * Disabling ACPI PM timer is necessary for XTAL OSC shutdown. + * Disabling ACPI PM timer also switches off TCO + */ + if (!CONFIG(USE_PM_ACPI_TIMER)) + setbits8(pmc_mmio_regs() + PCH_PWRM_ACPI_TMR_CTL, ACPI_TIM_DIS); +} + +static void pm1_enable_pwrbtn_smi(void *unused) +{ + /* Enable power button SMI after BS_DEV_INIT_CHIPS (FSP-S) is done. */ + pmc_update_pm1_enable(PWRBTN_EN); +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, pm1_enable_pwrbtn_smi, NULL); + +/* + * `pmc_final` function is native implementation of equivalent events performed by + * each FSP NotifyPhase() API invocations. + * + * + * Clear PMCON status bits (Global Reset/Power Failure/Host Reset Status bits) + * + * Perform the PMCON status bit clear operation from `.final` + * to cover any such chances where later boot stage requested a global + * reset and PMCON status bit remains set. + */ +static void pmc_final(struct device *dev) +{ + pmc_clear_pmcon_sts(); +} +struct device_operations pmc_ops = { + .read_resources = soc_pmc_read_resources, + .set_resources = noop_set_resources, + .init = soc_acpi_mode_init, + .enable = pmc_init, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_fill_ssdt = soc_pmc_fill_ssdt, +#endif + .scan_bus = scan_static_bus, + .final = pmc_final, +}; diff --git a/src/soc/intel/pantherlake/pmutil.c b/src/soc/intel/pantherlake/pmutil.c new file mode 100644 index 0000000..370804d --- /dev/null +++ b/src/soc/intel/pantherlake/pmutil.c @@ -0,0 +1,268 @@ +/* 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 <console/console.h> +#include <device/mmio.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_def.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/rtc.h> +#include <intelblocks/tco.h> +#include <security/vboot/vbnv.h> +#include <soc/gpe.h> +#include <soc/gpio.h> +#include <soc/espi.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/smbus.h> +#include <soc/soc_chip.h> +#include <types.h> + +/* + * SMI + */ + +const char *const *soc_smi_sts_array(size_t *a) +{ + static const char *const smi_sts_bits[] = { + [BIOS_STS_BIT] = "BIOS", + [LEGACY_USB_STS_BIT] = "LEGACY_USB", + [SMI_ON_SLP_EN_STS_BIT] = "SLP_SMI", + [APM_STS_BIT] = "APM", + [SWSMI_TMR_STS_BIT] = "SWSMI_TMR", + [PM1_STS_BIT] = "PM1", + [GPE0_STS_BIT] = "GPE0", + [GPIO_STS_BIT] = "GPI", + [MCSMI_STS_BIT] = "MCSMI", + [DEVMON_STS_BIT] = "DEVMON", + [TCO_STS_BIT] = "TCO", + [PERIODIC_STS_BIT] = "PERIODIC", + [SERIRQ_SMI_STS_BIT] = "SERIRQ_SMI", + [SMBUS_SMI_STS_BIT] = "SMBUS_SMI", + [PCI_EXP_SMI_STS_BIT] = "PCI_EXP_SMI", + [MONITOR_STS_BIT] = "MONITOR", + [SPI_SMI_STS_BIT] = "SPI", + [GPIO_UNLOCK_SMI_STS_BIT] = "GPIO_UNLOCK", + [ESPI_SMI_STS_BIT] = "ESPI_SMI", + }; + + *a = ARRAY_SIZE(smi_sts_bits); + return smi_sts_bits; +} + +/* + * TCO + */ + +const char *const *soc_tco_sts_array(size_t *a) +{ + static const char *const tco_sts_bits[] = { + [0] = "NMI2SMI", + [1] = "SW_TCO", + [2] = "TCO_INT", + [3] = "TIMEOUT", + [7] = "NEWCENTURY", + [8] = "BIOSWR", + [9] = "DMISCI", + [10] = "DMISMI", + [12] = "DMISERR", + [13] = "SLVSEL", + [16] = "INTRD_DET", + [17] = "SECOND_TO", + [18] = "BOOT", + [20] = "SMLINK_SLV" + }; + + *a = ARRAY_SIZE(tco_sts_bits); + return tco_sts_bits; +} + +/* + * GPE0 + */ + +const char *const *soc_std_gpe_sts_array(size_t *a) +{ + static const char *const gpe_sts_bits[] = { + [1] = "HOTPLUG", + [2] = "SWGPE", + [6] = "TCO_SCI", + [7] = "SMB_WAK", + [9] = "PCI_EXP", + [10] = "BATLOW", + [11] = "PME", + [12] = "ME", + [13] = "PME_B0", + [14] = "eSPI", + [15] = "GPIO Tier-2", + [16] = "LAN_WAKE", + [18] = "WADT" + }; + + *a = ARRAY_SIZE(gpe_sts_bits); + return gpe_sts_bits; +} + +void pmc_set_disb(void) +{ + /* Set the DISB after DRAM init */ + uint8_t disb_val; + /* Only care about bits [23:16] of register GEN_PMCON_A */ + uint8_t *addr = (uint8_t *)(pmc_mmio_regs() + GEN_PMCON_A + 2); + + disb_val = read8(addr); + disb_val |= (DISB >> 16); + + /* Don't clear bits that are write-1-to-clear */ + disb_val &= ~((MS4V | SUS_PWR_FLR) >> 16); + write8(addr, disb_val); +} + +/* + * PMC controller gets hidden from PCI bus + * during FSP-Silicon init call. Hence PWRMBASE + * can't be accessible using PCI configuration space + * read/write. + */ +uint8_t *pmc_mmio_regs(void) +{ + return (void *)(uintptr_t)PCH_PWRM_BASE_ADDRESS; +} + +uintptr_t soc_read_pmc_base(void) +{ + return (uintptr_t)pmc_mmio_regs(); +} + +uint32_t *soc_pmc_etr_addr(void) +{ + return (uint32_t *)(soc_read_pmc_base() + ETR); +} + +void soc_get_gpi_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2) +{ + DEVTREE_CONST struct soc_intel_pantherlake_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_fetch_pm_state(&ps, PS_CLAIMER_RTC) < 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->pm1_sts & WAK_STS) && (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/pantherlake/retimer.c b/src/soc/intel/pantherlake/retimer.c new file mode 100644 index 0000000..cc82e9f --- /dev/null +++ b/src/soc/intel/pantherlake/retimer.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/console.h> +#include <device/device.h> +#include <drivers/intel/usb4/retimer/retimer.h> +#include <intelblocks/tcss.h> +#include <soc/soc_info.h> + +int retimer_get_index_for_typec(uint8_t typec_port) +{ + int ec_port = 0; + + const struct device *tcss_port_arr[] = { + DEV_PTR(tcss_usb3_port0), + DEV_PTR(tcss_usb3_port1), + DEV_PTR(tcss_usb3_port2), + DEV_PTR(tcss_usb3_port3), + }; + + uint8_t _MAX_TYPE_C_PORTS = get_max_tcss_port(); + for (uint8_t i = 0; i < _MAX_TYPE_C_PORTS ; i++) { + if (i == typec_port) { + printk(BIOS_INFO, "USB Type-C %d mapped to EC port %d\n", typec_port, + ec_port); + return ec_port; + } + + if (is_dev_enabled(tcss_port_arr[i])) + ec_port++; + } + + /* Code should not come here if typec_port input is correct */ + return -1; +} diff --git a/src/soc/intel/pantherlake/smihandler.c b/src/soc/intel/pantherlake/smihandler.c new file mode 100644 index 0000000..6a21f0a --- /dev/null +++ b/src/soc/intel/pantherlake/smihandler.c @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/pci_def.h> +#include <intelblocks/smihandler.h> +#include <soc/soc_chip.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> + +int smihandler_soc_disable_busmaster(pci_devfn_t dev) +{ + /* Skip disabling PMC bus master to keep IO decode enabled */ + if (dev == PCI_DEV_PMC) + return 0; + return 1; +} + +const smi_handler_t southbridge_smi[SMI_STS_BITS] = { + [SMI_ON_SLP_EN_STS_BIT] = smihandler_southbridge_sleep, + [APM_STS_BIT] = smihandler_southbridge_apmc, + [PM1_STS_BIT] = smihandler_southbridge_pm1, + [GPE0_STS_BIT] = smihandler_southbridge_gpe0, + [GPIO_STS_BIT] = smihandler_southbridge_gpi, + [ESPI_SMI_STS_BIT] = smihandler_southbridge_espi, + [MCSMI_STS_BIT] = smihandler_southbridge_mc, +#if CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE) + [TCO_STS_BIT] = smihandler_southbridge_tco, +#endif + [PERIODIC_STS_BIT] = smihandler_southbridge_periodic, + [MONITOR_STS_BIT] = smihandler_southbridge_monitor, +}; diff --git a/src/soc/intel/pantherlake/soundwire.c b/src/soc/intel/pantherlake/soundwire.c new file mode 100644 index 0000000..c3ff05d --- /dev/null +++ b/src/soc/intel/pantherlake/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/pantherlake/spi.c b/src/soc/intel/pantherlake/spi.c new file mode 100644 index 0000000..f2e3400 --- /dev/null +++ b/src/soc/intel/pantherlake/spi.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <intelblocks/fast_spi.h> +#include <intelblocks/spi.h> +#include <soc/pci_devs.h> + +#define PSF_SPI_DESTINATION_ID 0x5140 + +int spi_soc_devfn_to_bus(unsigned int devfn) +{ + switch (devfn) { + case PCI_DEVFN_SPI: + return 0; + case PCI_DEVFN_GSPI0: + return 1; + case PCI_DEVFN_GSPI1: + return 2; + } + return -1; +} + +uint32_t soc_get_spi_psf_destination_id(void) +{ + return PSF_SPI_DESTINATION_ID; +} diff --git a/src/soc/intel/pantherlake/systemagent.c b/src/soc/intel/pantherlake/systemagent.c new file mode 100644 index 0000000..8e97ea7 --- /dev/null +++ b/src/soc/intel/pantherlake/systemagent.c @@ -0,0 +1,318 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/ioapic.h> +#include <console/console.h> +#include <cpu/x86/msr.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <delay.h> +#include <intelblocks/cpulib.h> +#include <intelblocks/msr.h> +#include <intelblocks/power_limit.h> +#include <intelblocks/systemagent.h> +#include <soc/iomap.h> +#include <soc/soc_chip.h> +#include <soc/systemagent.h> + +/* + * SoC implementation + * + * Add all known fixed memory ranges for Host Controller/Memory + * controller. + */ +void soc_add_fixed_mmio_resources(struct device *dev, int *index) +{ + static const struct sa_mmio_descriptor soc_fixed_resources[] = { + { PCIEXBAR, CONFIG_ECAM_MMCONF_BASE_ADDRESS, CONFIG_ECAM_MMCONF_LENGTH, + "PCIEXBAR" }, + { MCHBAR, MCH_BASE_ADDRESS, MCH_BASE_SIZE, "MCHBAR" }, + { SAFBAR, SAF_BASE_ADDRESS, SAF_BASE_SIZE, "SAFBAR" }, + { EPBAR, EP_BASE_ADDRESS, EP_BASE_SIZE, "EPBAR" }, + { REGBAR, REG_BASE_ADDRESS, REG_BASE_SIZE, "REGBAR" }, + { EDRAMBAR, EDRAM_BASE_ADDRESS, EDRAM_BASE_SIZE, "EDRAMBAR" }, + /* first field (sa_mmio_descriptor.index) is not used, setting to 0: */ + { 0, CRAB_ABORT_BASE_ADDR, CRAB_ABORT_SIZE, "CRAB_ABORT" }, + { 0, LT_SECURITY_BASE_ADDR, LT_SECURITY_SIZE, "LT_SECURITY" }, + { 0, IO_APIC_ADDR, APIC_SIZE, "APIC" }, + // PCH_PRESERVERD covers: + // TraceHub SW BAR, PMC MBAR, SPI BAR0, SerialIo BAR in ACPI mode + // eSPI LGMR BAR, eSPI2 SEGMR BAR, TraceHub MTB BAR, TraceHub FW BAR + // IOE PMC BAR, Tracehub RTIT BAR (SOC), HECI{1,2,3} BAR0 + // see fsp/ClientOneSiliconPkg/Fru/MtlSoc/Include/PchReservedResources.h + { 0, PCH_PRESERVED_BASE_ADDRESS, PCH_PRESERVED_BASE_SIZE, "PCH_RESERVED" }, + }; + + 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)); +} + +/* + * set MMIO resource's fields + */ +static void set_mmio_resource( + struct sa_mmio_descriptor *resource, + uint64_t base, + uint64_t size, + const char *description) +{ + if (resource == NULL) { + printk(BIOS_ERR, "%s: argument resource is NULL for %s\n", + __func__, description); + return; + } + resource->base = base; + resource->size = size; + resource->description = description; +} + +int soc_get_uncore_prmmr_base_and_mask(uint64_t *prmrr_base, + uint64_t *prmrr_mask) +{ + msr_t msr; + msr = rdmsr(MSR_PRMRR_BASE_0); + *prmrr_base = (uint64_t)msr.hi << 32 | msr.lo; + msr = rdmsr(MSR_PRMRR_PHYS_MASK); + *prmrr_mask = (uint64_t)msr.hi << 32 | msr.lo; + return 0; +} + +/* + * SoC implementation + * + * Add all known configurable memory ranges for Host Controller/Memory + * controller. + */ +void soc_add_configurable_mmio_resources(struct device *dev, int *resource_cnt) +{ + uint64_t size, base, tseg_base; + int count = 0; + struct sa_mmio_descriptor cfg_rsrc[6]; /* Increase size when adding more resources */ + + /* MMCONF */ + size = get_mmcfg_size(dev); + if (size > 0) + set_mmio_resource(&(cfg_rsrc[count++]), CONFIG_ECAM_MMCONF_BASE_ADDRESS, + size, "MMCONF"); + + /* DSM */ + size = get_dsm_size(dev); + if (size > 0) { + base = pci_read_config32(dev, DSM_BASE_ADDR_REG) & 0xFFF00000; + set_mmio_resource(&(cfg_rsrc[count++]), base, size, "DSM"); + } + + /* TSEG */ + size = sa_get_tseg_size(); + tseg_base = sa_get_tseg_base(); + if (size > 0) + set_mmio_resource(&(cfg_rsrc[count++]), tseg_base, size, "TSEG"); + + /* PMRR */ + size = get_valid_prmrr_size(); + if (size > 0) { + uint64_t mask; + if (soc_get_uncore_prmmr_base_and_mask(&base, &mask) == 0) { + base &= mask; + set_mmio_resource(&(cfg_rsrc[count++]), base, size, "PMRR"); + } else { + printk(BIOS_ERR, "SA: Failed to get PRMRR base and mask\n"); + } + } + + /* GSM */ + size = get_gsm_size(dev); + if (size > 0) { + base = sa_get_gsm_base(); + set_mmio_resource(&(cfg_rsrc[count++]), base, size, "GSM"); + } + + /* DPR */ + size = get_dpr_size(dev); + if (size > 0) { + /* DPR just below TSEG: */ + base = tseg_base - size; + set_mmio_resource(&(cfg_rsrc[count++]), base, size, "DPR"); + } + + /* Add all the above */ + sa_add_fixed_mmio_resources(dev, resource_cnt, cfg_rsrc, count); +} + +/* + * SoC implementation + * + * Perform System Agent Initialization during Ramstage phase. + */ +void soc_systemagent_init(struct device *dev) +{ + struct soc_power_limits_config *soc_config; + struct device *sa; + uint16_t sa_pci_id; + config_t *config; + + /* Enable Power Aware Interrupt Routing */ + enable_power_aware_intr(); + + /* Enable BIOS Reset CPL */ + enable_bios_reset_cpl(); + + /* Configure turbo power limits 1ms after reset complete bit */ + mdelay(1); + config = config_of_soc(); + + /* Get System Agent PCI ID */ + sa = pcidev_path_on_root(PCI_DEVFN_ROOT); + sa_pci_id = sa ? pci_read_config16(sa, PCI_DEVICE_ID) : 0xFFFF; + + /* Choose a power limits configuration based on the SoC SKU type, + * differentiated here based on SA PCI ID. */ + switch (sa_pci_id) { + case PCI_DID_INTEL_PTL_U_ID_1: + case PCI_DID_INTEL_PTL_H_ID_1: + case PCI_DID_INTEL_PTL_H_ID_2: + soc_config = &config->power_limits_config[PTL_H_POWER_LIMITS]; + 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; + } +} + +uint64_t get_mmcfg_size(const struct device *dev) +{ + uint32_t pciexbar_reg; + uint64_t mmcfg_length; + + if (!dev) { + printk(BIOS_DEBUG, "%s : device is null\n", __func__); + return 0; + } + + pciexbar_reg = pci_read_config32(dev, PCIEXBAR); + + if (!(pciexbar_reg & (1 << 0))) { + printk(BIOS_DEBUG, "%s : PCIEXBAR disabled\n", __func__); + return 0; + } + + switch ((pciexbar_reg & MASK_PCIEXBAR_LENGTH) >> PCIEXBAR_LENGTH_LSB) { + case PCIEXBAR_LENGTH_4096MB: + mmcfg_length = 4 * ((uint64_t)GiB); + break; + case PCIEXBAR_LENGTH_2048MB: + mmcfg_length = 2 * ((uint64_t)GiB); + break; + case PCIEXBAR_LENGTH_1024MB: + mmcfg_length = 1 * GiB; + break; + case PCIEXBAR_LENGTH_512MB: + mmcfg_length = 512 * MiB; + break; + case PCIEXBAR_LENGTH_256MB: + mmcfg_length = 256 * MiB; + break; + case PCIEXBAR_LENGTH_128MB: + mmcfg_length = 128 * MiB; + break; + case PCIEXBAR_LENGTH_64MB: + mmcfg_length = 64 * MiB; + break; + default: + printk(BIOS_DEBUG, "%s : PCIEXBAR - invalid length (0x%x)\n", __func__, + pciexbar_reg & MASK_PCIEXBAR_LENGTH); + mmcfg_length = 0x0; + break; + } + + return mmcfg_length; +} + +uint64_t get_dsm_size(const struct device *dev) +{ + // - size : B0/D0/F0:R 50h [15:8] + uint32_t reg32 = pci_read_config32(dev, GGC); + uint64_t size; + uint32_t size_field = (reg32 & MASK_DSM_LENGTH) >> MASK_DSM_LENGTH_LSB; + if (size_field <= 0x10) { // 0x0 - 0x10 + size = size_field * 32 * MiB; + } else if ((size_field >= 0xF0) && (size_field >= 0xFE)) { + size = ((uint64_t)size_field - 0xEF) * 4 * MiB; + } else { + switch (size_field) { + case 0x20: + size = 1 * GiB; + break; + case 0x30: + size = 1536 * MiB; + break; + case 0x40: + size = 2 * (uint64_t)GiB; + break; + default: + printk(BIOS_DEBUG, "%s : DSM - invalid length (0x%x)\n", + __func__, size_field); + size = 0x0; + break; + } + } + return size; +} + +uint64_t get_gsm_size(const struct device *dev) +{ + const u32 gsm_size = pci_read_config32(dev, GGC); + uint64_t size; + uint32_t size_field = (gsm_size & MASK_GSM_LENGTH) >> MASK_GSM_LENGTH_LSB; + switch (size_field) { + case 0x0: + size = 0; + break; + case 0x1: + size = 2 * MiB; + break; + case 0x2: + size = 4 * MiB; + break; + case 0x3: + size = 8 * MiB; + break; + default: + size = 0; + break; + } + return size; +} +uint64_t get_dpr_size(const struct device *dev) +{ + uint64_t size; + uint32_t dpr_reg = pci_read_config32(dev, DPR_REG); + uint32_t size_field = (dpr_reg & MASK_DPR_LENGTH) >> MASK_DPR_LENGTH_LSB; + size = (uint64_t)size_field * MiB; + return size; +} diff --git a/src/soc/intel/pantherlake/tcss.c b/src/soc/intel/pantherlake/tcss.c new file mode 100644 index 0000000..6ee865f --- /dev/null +++ b/src/soc/intel/pantherlake/tcss.c @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <intelblocks/tcss.h> +#include <soc/soc_chip.h> + +const struct soc_tcss_ops tcss_ops = { +}; + +bool ioe_tcss_valid_tbt_auth(void) +{ + const config_t *config = config_of_soc(); + return config->tbt_authentication; +} diff --git a/src/soc/intel/pantherlake/uart.c b/src/soc/intel/pantherlake/uart.c new file mode 100644 index 0000000..9f549c5 --- /dev/null +++ b/src/soc/intel/pantherlake/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/pantherlake/xhci.c b/src/soc/intel/pantherlake/xhci.c new file mode 100644 index 0000000..9b4ac1b --- /dev/null +++ b/src/soc/intel/pantherlake/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; +}