Subrata Banik has submitted this change. ( https://review.coreboot.org/c/coreboot/+/84332?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: I61930726ad0c765bfa1d72c5df893262be884834 Signed-off-by: Saurabh Mishra mishra.saurabh@intel.com Reviewed-on: https://review.coreboot.org/c/coreboot/+/84332 Reviewed-by: Jérémy Compostella jeremy.compostella@intel.com Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Subrata Banik subratabanik@google.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 M src/soc/intel/pantherlake/chip.h M src/soc/intel/pantherlake/chipset.cb A src/soc/intel/pantherlake/cpu.c A src/soc/intel/pantherlake/crashlog.c A src/soc/intel/pantherlake/cse_telemetry.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/dptf.h M src/soc/intel/pantherlake/include/soc/iomap.h A src/soc/intel/pantherlake/include/soc/irq.h A src/soc/intel/pantherlake/include/soc/nvs.h M src/soc/intel/pantherlake/include/soc/p2sb.h A src/soc/intel/pantherlake/include/soc/pcie.h M src/soc/intel/pantherlake/include/soc/pmc.h A src/soc/intel/pantherlake/include/soc/ramstage.h A src/soc/intel/pantherlake/include/soc/serialio.h M src/soc/intel/pantherlake/include/soc/systemagent.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/p2sb.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 41 files changed, 3,692 insertions(+), 110 deletions(-)
Approvals: Jérémy Compostella: Looks good to me, approved build bot (Jenkins): Verified Subrata Banik: Looks good to me, approved
diff --git a/src/soc/intel/pantherlake/Kconfig b/src/soc/intel/pantherlake/Kconfig index 98248fe..0dc65e4 100644 --- a/src/soc/intel/pantherlake/Kconfig +++ b/src/soc/intel/pantherlake/Kconfig @@ -7,37 +7,100 @@ select BOOT_DEVICE_SUPPORTS_WRITES select CACHE_MRC_SETTINGS select CPU_INTEL_COMMON + select CPU_INTEL_COMMON_VOLTAGE select CPU_INTEL_FIRMWARE_INTERFACE_TABLE - select FSP_M_XIP - select FSP_USES_CB_DEBUG_EVENT_HANDLER + select CPU_SUPPORTS_INTEL_TME + select CPU_SUPPORTS_PM_TIMER_EMULATION + select DEFAULT_SOFTWARE_CONNECTION_MANAGER if MAINBOARD_HAS_CHROMEOS + select DEFAULT_X2APIC_LATE_WORKAROUND + select DISPLAY_FSP_VERSION_INFO_2 select FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW + select FSP_COMPRESS_FSP_S_LZ4 + select FSP_M_XIP + select FSP_STATUS_GLOBAL_RESET_REQUIRED_3 + select FSP_UGOP_EARLY_SIGN_OF_LIFE + select FSP_USES_CB_DEBUG_EVENT_HANDLER + select FSPS_HAS_ARCH_UPD + select GENERIC_GPIO_LIB + select HAVE_DEBUG_RAM_SETUP + select HAVE_FSP_GOP + select HAVE_FSP_LOGO_SUPPORT if RUN_FSP_GOP + select HAVE_HYPERTHREADING + select HAVE_INTEL_COMPLIANCE_TEST_MODE + select HAVE_SMI_HANDLER select HAVE_X86_64_SUPPORT select IDT_IN_EVERY_STAGE - select INTEL_GMA_ADD_VBT if RUN_FSP_GOP select INTEL_DESCRIPTOR_MODE_CAPABLE + select INTEL_GMA_ACPI + select INTEL_GMA_ADD_VBT if RUN_FSP_GOP + select INTEL_GMA_OPREGION_2_1 + select INTEL_GMA_VERSION_2 + select INTEL_KEYLOCKER select IOAPIC select MICROCODE_BLOB_UNDISCLOSED + select MP_SERVICES_PPI_V2 + select MRC_CACHE_USING_MRC_VERSION select MRC_SETTINGS_PROTECT + select PARALLEL_MP_AP_WORK + select PCIE_CLOCK_CONTROL_THROUGH_P2SB select PLATFORM_USES_FSP2_4 + select PMC_GLOBAL_RESET_ENABLE_LOCK select SOC_INTEL_COMMON + select SOC_INTEL_COMMON_ACPI_WAKE_SOURCE + select SOC_INTEL_COMMON_BASECODE + select SOC_INTEL_COMMON_BASECODE_RAMTOP select SOC_INTEL_COMMON_BLOCK 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_IOC select SOC_INTEL_COMMON_BLOCK_IOE_P2SB + select SOC_INTEL_COMMON_BLOCK_IPU + select SOC_INTEL_COMMON_BLOCK_IRQ + select SOC_INTEL_COMMON_BLOCK_ME_SPEC_18 # TODO: Update with ME21 Spec select SOC_INTEL_COMMON_BLOCK_MEMINIT + select SOC_INTEL_COMMON_BLOCK_PCIE_RTD3 + select SOC_INTEL_COMMON_BLOCK_PMC_EPOC + select SOC_INTEL_COMMON_BLOCK_POWER_LIMIT select SOC_INTEL_COMMON_BLOCK_SA + select SOC_INTEL_COMMON_BLOCK_SMM + select SOC_INTEL_COMMON_BLOCK_SMM_IO_TRAP + select SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE + select SOC_INTEL_COMMON_BLOCK_THERMAL_BEHIND_PMC + select SOC_INTEL_COMMON_BLOCK_TRACEHUB + select SOC_INTEL_COMMON_BLOCK_XHCI + select SOC_INTEL_COMMON_BLOCK_XHCI_ELOG + select SOC_INTEL_COMMON_FSP_RESET select SOC_INTEL_COMMON_PCH_CLIENT select SOC_INTEL_COMMON_RESET + select SOC_INTEL_CRASHLOG + select SOC_INTEL_CSE_LITE_PSR if MAINBOARD_HAS_CHROMEOS && SOC_INTEL_CSE_LITE_SKU + select SOC_INTEL_CSE_SEND_EOP_LATE if !MAINBOARD_HAS_CHROMEOS + select SOC_INTEL_CSE_SET_EOP + select SOC_INTEL_GFX_NON_PREFETCHABLE_MMIO select SOC_INTEL_IOE_DIE_SUPPORT + select SOC_INTEL_MEM_MAPPED_PM_CONFIGURATION select SOC_QDF_DYNAMIC_READ_PMC select SSE2 select SUPPORT_CPU_UCODE_IN_CBFS + select TME_KEY_REGENERATION_ON_WARM_BOOT select TSC_MONOTONIC_TIMER select UDELAY_TSC select UDK_202302_BINDING select USE_X86_64_SUPPORT + select X86_CLFLUSH_CAR + select X86_INIT_NEED_1_SIPI help Intel Pantherlake support. Mainboards should specify the SoC type using the `SOC_INTEL_PANTHERLAKE_*` options instead @@ -49,8 +112,6 @@ help Choose this option if the mainboard is built using either a PTL-U (15W) or PTL-H 12Xe (25W) system-on-a-chip SoC. - Note, PTL U/H processor line is offered in a single package platform that includes the - Compute tile, the PCD tile, and the GFX tile on the same package.
config SOC_INTEL_PANTHERLAKE_H bool @@ -58,11 +119,17 @@ select SOC_INTEL_PANTHERLAKE_BASE help Choose this option if the mainboard is built using PTL-H 4Xe system-on-a-chip (SoC). - Note, PTL-H processor line is offered in a single package platform that includes the - Compute tile, the PCD tile, and the GFX tile on the same package.
if SOC_INTEL_PANTHERLAKE_BASE
+config SOC_INTEL_PANTHERLAKE_TCSS_USB4_SUPPORT + bool + default y + select SOC_INTEL_COMMON_BLOCK_TCSS + select SOC_INTEL_COMMON_BLOCK_USB4 + select SOC_INTEL_COMMON_BLOCK_USB4_PCIE + select SOC_INTEL_COMMON_BLOCK_USB4_XHCI + config CAR_ENHANCED_NEM bool default y if !INTEL_CAR_NEM @@ -101,6 +168,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" @@ -109,6 +186,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 0xc200000 + +config PCIEXP_HOTPLUG_PREFETCH_MEM + hex + default 0x1c000000 + +endif # SOC_INTEL_ENABLE_USB4_PCIE_RESOURCES + config MAX_TBT_ROOT_PORTS int default 4 @@ -122,6 +219,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 @@ -137,6 +242,14 @@ config ECAM_MMCONF_BASE_ADDRESS default 0xe0000000
+config SOC_INTEL_PERFORMANCE_CORE_SCALE_FACTOR + int + default 125 # TODO: Update with PTL data + +config SOC_INTEL_EFFICIENT_CORE_SCALE_FACTOR + int + default 100 # TODO: Update with PTL data + config CPU_BCLK_MHZ int default 100 @@ -178,7 +291,7 @@ depends on INTEL_LPSS_UART_FOR_CONSOLE
# Clock divider parameters for 115200 baud rate -# Baudrate = (UART source clcok * M) /(N *16) +# Baudrate = (UART source clock * M) /(N *16) # PTL UART source clock: 100MHz config SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL hex @@ -189,12 +302,13 @@ default 0x7fff
config VBOOT - select VBOOT_SEPARATE_VERSTAGE select VBOOT_MUST_REQUEST_DISPLAY + select VBOOT_SEPARATE_VERSTAGE select VBOOT_STARTS_IN_BOOTBLOCK select VBOOT_VBNV_CMOS select VBOOT_VBNV_CMOS_BACKUP_TO_FLASH select VBOOT_X86_SHA256_ACCELERATION + select VBOOT_X86_RSA_ACCELERATION
# Default hash block size is 1KiB. Increasing it to 4KiB to improve # hashing time as well as read time. @@ -242,4 +356,62 @@ int default 16
+config SOC_INTEL_GFX_FRAMEBUFFER_OFFSET + hex + default 0x800000 + +config DROP_CPU_FEATURE_PROGRAM_IN_FSP + bool + default n + help + This is to avoid FSP running basic CPU feature programming on BSP + and on APs using the "CpuFeaturesPei.efi" module. The feature programming + includes enabling x2APIC, MCA, MCE and Turbo etc. + + Most of these feature programming are getting performed today in scope + of coreboot doing MP Init. Running these redundant programming in scope + of FSP (when `USE_FSP_FEATURE_PROGRAM_ON_APS` config is enabled) would + results in CPU exception. + + SoC users to select this config after dropping "CpuFeaturesPei.ffs" module + from FSP-S Firmware Volume (FV). Upon selection, coreboot runs those additional + feature programming on BSP and APs. + + This feature is default enabled, in case of "coreboot running MP init" + aka MP_SERVICES_PPI_V2_NOOP config is selected. + +config PCIE_LTR_MAX_SNOOP_LATENCY + hex + default 0x100f + help + Latency tolerance reporting, max snoop latency value defaults to 15.73 ms. + +config PCIE_LTR_MAX_NO_SNOOP_LATENCY + hex + default 0x100f + help + Latency tolerance reporting, max non-snoop latency value defaults to 15.73 ms. + +config HAVE_BMP_LOGO_COMPRESS_LZMA + default n + +# The default offset to store CSE RW FW version information is at 68. +# However, in Intel Panther Lake based systems that use PSR, the additional +# size required to keep CSE RW FW version information and PSR back-up status +# in adjacent CMOS memory at offset 68 is not available. Therefore, we +# override the default offset to 161, which has enough space to keep both +# the CSE related information together. +config SOC_INTEL_CSE_FW_PARTITION_CMOS_OFFSET + int + default 161 + +config SOC_INTEL_COMMON_BLOCK_ACPI_SLP_S0_FREQ_HZ + default 0x2005 + help + slp_s0_residency granularity in 122us ticks (i.e. ~8.2KHz) in Panther Lake. + +config SOC_PHYSICAL_ADDRESS_WIDTH + int + default 42 + endif diff --git a/src/soc/intel/pantherlake/Makefile.mk b/src/soc/intel/pantherlake/Makefile.mk index 2704305..10ef8e9 100644 --- a/src/soc/intel/pantherlake/Makefile.mk +++ b/src/soc/intel/pantherlake/Makefile.mk @@ -6,20 +6,55 @@ 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 += espi.c -bootblock-y += gpio.c bootblock-y += soc_info.c
+romstage-$(CONFIG_SOC_INTEL_CSE_PRE_CPU_RESET_TELEMETRY) += cse_telemetry.c romstage-y += espi.c -romstage-y += gpio.c romstage-y += meminit.c romstage-y += pcie_rp.c romstage-y += reset.c romstage-y += soc_info.c
+ramstage-y += acpi.c +ramstage-y += chip.c +ramstage-y += cpu.c +ramstage-$(CONFIG_SOC_INTEL_CRASHLOG) += crashlog.c +ramstage-y += elog.c +ramstage-y += espi.c +ramstage-y += finalize.c +ramstage-y += fsp_params.c +ramstage-y += lockdown.c +ramstage-y += p2sb.c +ramstage-y += pcie_rp.c +ramstage-y += pmc.c +ramstage-y += reset.c +ramstage-y += retimer.c +ramstage-y += soc_info.c +ramstage-y += soundwire.c +ramstage-y += systemagent.c +ramstage-y += tcss.c +ramstage-y += xhci.c + +smm-y += elog.c +smm-y += gpio.c +smm-y += p2sb.c +smm-y += pmutil.c +smm-y += smihandler.c +smm-y += soc_info.c +smm-y += uart.c +smm-y += xhci.c CPPFLAGS_common += -I$(src)/soc/intel/pantherlake CPPFLAGS_common += -I$(src)/soc/intel/pantherlake/include
diff --git a/src/soc/intel/pantherlake/acpi.c b/src/soc/intel/pantherlake/acpi.c new file mode 100644 index 0000000..79e47e8 --- /dev/null +++ b/src/soc/intel/pantherlake/acpi.c @@ -0,0 +1,358 @@ +/* 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 <types.h> + +/* + * TODO: Update as per PTL spec. + * 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 +}; + +/* TODO: Update as per PTL spec. */ +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), + }, +}; + +/* TODO: Update as per PTL spec */ +static int cstate_set_non_s0ix[] = { + C_STATE_C1, + C_STATE_C6_LONG_LAT, + C_STATE_C7S_LONG_LAT +}; + +/* TODO: Update as per PTL spec */ +static int cstate_set_s0ix[] = { + C_STATE_C1, + C_STATE_C6_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))]; + static bool c_state_initialized = false; + size_t i; + + if (c_state_initialized) + return map; + + config_t *config = config_of_soc(); + if (config == NULL) { + printk(BIOS_ERR, "Error: Configuration could not be retrieved.\n"); + return NULL; + } + + int *set; + if (config->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; + } + c_state_initialized = true; + + return map; +} + +void soc_power_states_generation(int core_id, int cores_per_package) +{ + config_t *config = config_of_soc(); + if (config == NULL) { + printk(BIOS_ERR, "Error: Configuration could not be retrieved.\n"); + return; + } + 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(); + if (config == NULL) { + printk(BIOS_ERR, "Error: Configuration could not be retrieved.\n"); + return; + } + fadt->pm_tmr_blk = pmbase + PM1_TMR; + fadt->pm_tmr_len = sizeof(uint32_t); + + 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_TCSS_XHCI, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TCSS_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 }, + { PCI_DEVFN_PCIE7, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE8, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE9, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE10, ACPI_DEVICE_SLEEP_D0 }, + { PCI_DEVFN_PCIE11, ACPI_DEVICE_SLEEP_D0 }, + { PCI_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) +{ + uint32_t vtd_engine_enabled = MCHBAR32(GFXVTBAR); + const uint64_t gfxvtbar = MCHBAR64(GFXVTBAR) & VTBAR_MASK; + bool is_ipu_enabled = is_devfn_enabled(PCI_DEVFN_IPU); + bool is_dptf_enabled = is_devfn_enabled(PCI_DEVFN_DPTF); + bool is_npu_enabled = is_devfn_enabled(PCI_DEVFN_NPU); + bool is_iaa_enabled = is_devfn_enabled(PCI_DEVFN_IAA); + + printk(BIOS_DEBUG, "%s - gfxvtbar:0x%llx 0x%x\n", __func__, gfxvtbar, MCHBAR32(GFXVTBAR)); + if (vtd_engine_enabled & GFXVT_ENABLED) { + const unsigned long tmp = current; + current += acpi_create_dmar_drhd(current, 0, 0, gfxvtbar, GFXVT_BASE_SIZE); + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0); + + acpi_dmar_drhd_fixup(tmp, current); + } + + if ((is_ipu_enabled || is_dptf_enabled || is_npu_enabled || is_iaa_enabled) && + (vtd_engine_enabled & NONGFXVT_ENABLED)) { + const unsigned long tmp = current; + current += acpi_create_dmar_drhd(current, + 0, 0, (uint64_t)VTVC0_BASE_ADDRESS, VTVC0_BASE_SIZE); + if (is_ipu_enabled) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IPU, 0); + if (is_dptf_enabled) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_DPTF, 0); + if (is_npu_enabled) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_NPU, 0); + if (is_iaa_enabled) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IAA, 0); + + acpi_dmar_drhd_fixup(tmp, current); + } + + if (vtd_engine_enabled & IOCVT_ENABLED) { + const unsigned long tmp = current; + current += acpi_create_dmar_drhd(current, + DRHD_INCLUDE_PCI_ALL, 0, (uint64_t)IOCVTD_BASE_ADDRESS, IOCVTD_BASE_SIZE); + 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 (vtd_engine_enabled & GFXVT_ENABLED) { + const unsigned long 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); + } + + if (is_ipu_enabled || is_dptf_enabled || is_npu_enabled || is_iaa_enabled) { + const unsigned long tmp = current; + current += acpi_create_dmar_satc(current, ATC_REQUIRED, 0); + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0); + if (is_dptf_enabled) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_DPTF, 0); + if (is_ipu_enabled) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IPU, 0); + if (is_npu_enabled) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_NPU, 0); + if (is_iaa_enabled) + 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) & (GFXVT_ENABLED | NONGFXVT_ENABLED | IOCVT_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(); + if (config == NULL) { + printk(BIOS_ERR, "Configuration could not be retrieved.\n"); + return; + } + /* 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..6b596b0 --- /dev/null +++ b/src/soc/intel/pantherlake/chip.c @@ -0,0 +1,283 @@ +/* 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/cse.h> +#include <intelblocks/irq.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/reset.h> +#include <soc/intel/common/vbt.h> +#include <soc/iomap.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"; + case 2: return "SS03"; + case 3: return "SS04"; + } + break; + } + printk(BIOS_ERR, "Missing ACPI Name for USB port_type=0x%x\n", + dev->path.usb.port_type); + return NULL; + } + if (dev->path.type != DEVICE_PATH_PCI) { + printk(BIOS_ERR, "Missing ACPI Name for USB path_type=0x%x\n", + dev->path.type); + return NULL; + } + + switch (dev->path.pci.devfn) { + case PCI_DEVFN_ROOT: return "MCHC"; + case PCI_DEVFN_IGD: return "GFX0"; + 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_NPU: return "NPU"; + case PCI_DEVFN_IPU: return "IPU"; + 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_CSE: return "HECI"; + case PCI_DEVFN_PCIE1: return "RP01"; + case PCI_DEVFN_PCIE2: return "RP02"; + case PCI_DEVFN_PCIE3: return "RP03"; + case PCI_DEVFN_PCIE4: return "RP04"; + case PCI_DEVFN_PCIE5: return "RP05"; + case PCI_DEVFN_PCIE6: return "RP06"; + case PCI_DEVFN_PCIE7: return "RP07"; + case PCI_DEVFN_PCIE8: return "RP08"; + case PCI_DEVFN_PCIE9: return "RP09"; + case PCI_DEVFN_PCIE10: return "RP10"; + case PCI_DEVFN_PCIE11: return "RP11"; + case PCI_DEVFN_PCIE12: return "RP12"; + case PCI_DEVFN_PMC: return "PMC"; + case PCI_DEVFN_UART0: return "UAR0"; + case PCI_DEVFN_UART1: return "UAR1"; + case PCI_DEVFN_UART2: return "UAR2"; + case PCI_DEVFN_GSPI0: return "SPI0"; + case PCI_DEVFN_GSPI1: return "SPI1"; + /* Keeping ACPI device name coherent with ec.asl */ + case PCI_DEVFN_ESPI: return "LPCB"; + case PCI_DEVFN_HDA: return "HDAS"; + case PCI_DEVFN_SMBUS: return "SBUS"; + case PCI_DEVFN_GBE: return "GLAN"; + } + printk(BIOS_ERR, "Missing ACPI Name for PCI: 00:%02x.%01x\n", + PCI_SLOT(dev->path.pci.devfn), PCI_FUNC(dev->path.pci.devfn)); + return NULL; +} +#endif + +#if CONFIG(SOC_INTEL_STORE_ISH_FW_VERSION) +/* SoC override API to identify if ISH Firmware existed inside CSE FPT */ +bool soc_is_ish_partition_enabled(void) +{ + struct device *ish = pcidev_path_on_root(PCI_DEVFN_ISH); + uint16_t ish_pci_id = ish ? pci_read_config16(ish, PCI_DEVICE_ID) : 0xFFFF; + + if (ish_pci_id == 0xFFFF) + return false; + + return true; +} +#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); +} + +/* Enable tracehub in device tree */ +static void soc_enable_tracehub(void) +{ + struct device *dev; + + dev = pcidev_path_on_root(PCI_DEVFN_NPK); + if (dev) { + dev->enabled = 1; + printk(BIOS_DEBUG, "Tracehub is enabled.\n"); + } +} + +void soc_init_pre_device(void *chip_info) +{ + config_t *config = config_of_soc(); + if (config == NULL) { + printk(BIOS_ERR, "Error: Configuration could not be retrieved.\n"); + return; + } + /* Validate TBT image authentication */ + config->tbt_authentication = ioe_p2sb_sbi_read(PID_IOM, + IOM_CSME_IMR_TBT_STATUS) & TBT_VALID_AUTHENTICATION; + + if (CONFIG(SOC_INTEL_COMMON_BLOCK_TRACEHUB)) + soc_enable_tracehub(); + + /* 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()); + + /* Swap enabled TBT root ports in device tree if needed. */ + pcie_rp_update_devicetree(get_tbt_pcie_rp_table()); + + /* + * Earlier when coreboot used to send EOP at late as possible caused + * issue of delayed response from CSE since CSE was busy loading payload. + * To resolve the issue, EOP should be sent earlier than current sequence + * in the boot sequence at BS_DEV_INIT. + * + * Intel CSE team recommends to send EOP close to FW init (between FSP-S + * exit and current boot sequence) to reduce message response time from + * CSE hence moving sending EOP to earlier stage. + */ + if (CONFIG(SOC_INTEL_CSE_SEND_EOP_EARLY) || CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC)) { + printk(BIOS_INFO, "Sending EOP early from SoC\n"); + cse_send_end_of_post(); + } +} + +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 = &pcd_p2sb_ops; + else if (dev->path.type == DEVICE_PATH_PCI && + dev->path.pci.devfn == PCI_DEVFN_P2SB2) + dev->ops = &pcd_p2sb_2_ops; + else if (dev->path.type == DEVICE_PATH_GPIO) + block_gpio_enable(dev); +} + +static void soc_init_final_device(void *chip_info) +{ + uint32_t reset_status = fsp_get_pch_reset_status(); + + if (reset_status == FSP_SUCCESS) + return; + + /* Handle any pending reset request from previously executed FSP APIs */ + fsp_handle_reset(reset_status); + + /* Control shouldn't return here */ + die_with_post_code(POSTCODE_HW_INIT_FAILURE, + "Failed to handle the FSP reset request with error 0x%08x\n", reset_status); +} + +struct chip_operations soc_intel_pantherlake_ops = { + .name = "Intel Pantherlake", + .enable_dev = &soc_enable, + .init = &soc_init_pre_device, + .final = &soc_init_final_device, +}; diff --git a/src/soc/intel/pantherlake/chip.h b/src/soc/intel/pantherlake/chip.h index d1dbe44..27d766f 100644 --- a/src/soc/intel/pantherlake/chip.h +++ b/src/soc/intel/pantherlake/chip.h @@ -3,7 +3,9 @@ #ifndef _SOC_PANTHERLAKE_CHIP_H_ #define _SOC_PANTHERLAKE_CHIP_H_
+#include <device/pci_ids.h> #include <drivers/i2c/designware/dw_i2c.h> +#include <gpio.h> #include <intelblocks/cfg.h> #include <intelblocks/gpio.h> #include <intelblocks/gspi.h> @@ -20,11 +22,14 @@ /* Define config parameters for In-Band ECC (IBECC). */ #define MAX_IBECC_REGIONS 8
+#define MAX_SAGV_POINTS 4 +#define MAX_HD_AUDIO_SDI_LINKS 2 + /* In-Band ECC Operation Mode */ enum ibecc_mode { IBECC_MODE_PER_REGION, IBECC_MODE_NONE, - IBECC_MODE_ALL + IBECC_MODE_ALL, };
struct ibecc_config { @@ -36,14 +41,32 @@ uint16_t region_mask[MAX_IBECC_REGIONS]; };
-/* Types of different SKUs */ enum soc_intel_pantherlake_power_limits { - PTL_U_15W_POWER_LIMITS, - PTL_H_25W_POWER_LIMITS, - PTL_H_45W_POWER_LIMITS, + PTL_U_1_CORE, + PTL_H_1_CORE, + PTL_H_2_CORE, + PTL_H_3_CORE, PTL_POWER_LIMITS_COUNT, };
+/* TDP values for different SKUs */ +enum soc_intel_pantherlake_cpu_tdps { + TDP_15W = 15, + TDP_25W = 25, + TDP_45W = 45, +}; + +/* Mapping of different SKUs based on CPU ID and TDP values */ +static const struct { + unsigned int cpu_id; + enum soc_intel_pantherlake_power_limits limits; + enum soc_intel_pantherlake_cpu_tdps cpu_tdp; +} cpuid_to_ptl[] = { + { PCI_DID_INTEL_PTL_U_ID_1, PTL_U_1_CORE, TDP_15W }, + { PCI_DID_INTEL_PTL_H_ID_1, PTL_H_1_CORE, TDP_25W }, + { PCI_DID_INTEL_PTL_H_ID_2, PTL_H_3_CORE, TDP_45W }, +}; + /* Types of display ports */ enum ddi_ports { DDI_PORT_A, @@ -61,6 +84,70 @@ DDI_ENABLE_HPD = BIT(1), /* Hot Plug Detect */ };
+/* + * TODO: Update as per PTL spec + * The Max Pkg Cstate + * Values 0 - C0/C1, 1 - C2, 2 - C3, 3 - C6, 4 - C7, 5 - C7S, 6 - C8, 7 - C9, 8 - C10, + * 254 - CPU Default , 255 - Auto. + */ +enum pkgcstate_limit { + LIMIT_C0_C1 = 0, + LIMIT_C2 = 1, + LIMIT_C3 = 2, + LIMIT_C6 = 3, + LIMIT_C7 = 4, + LIMIT_C7S = 5, + LIMIT_C8 = 6, + LIMIT_C9 = 7, + LIMIT_C10 = 8, + LIMIT_CPUDEFAULT = 254, + LIMIT_AUTO = 255, +}; + +/* Bit values for use in LpmStateEnableMask. */ +enum lpm_state_mask { + LPM_S0i2_0 = BIT(0), + LPM_S0i2_1 = BIT(1), + LPM_S0i2_2 = BIT(2), + LPM_S0i3_0 = BIT(3), + LPM_S0i3_1 = BIT(4), + LPM_S0i3_2 = BIT(5), + LPM_S0i3_3 = BIT(6), + LPM_S0i3_4 = BIT(7), + LPM_S0iX_ALL = LPM_S0i2_0 | LPM_S0i2_1 | LPM_S0i2_2 + | LPM_S0i3_0 | LPM_S0i3_1 | LPM_S0i3_2 | LPM_S0i3_3 | LPM_S0i3_4, +}; + +/* + * As per definition from FSP header: + * - [0] for IA + * - [1] for GT + * - [2] for SA + * - [3] through [5] are reserved + */ +enum vr_domain { + VR_DOMAIN_IA, + VR_DOMAIN_GT, + VR_DOMAIN_SA, + NUM_VR_DOMAINS, +}; + +/* + * Slew Rate configuration for Deep Package C States for VR domain. + * They are fast time divided by 2. + * 0 - Fast/2 + * 1 - Fast/4 + * 2 - Fast/8 + * 3 - Fast/16 + */ +enum slew_rate { + SLEW_FAST_2, + SLEW_FAST_4, + SLEW_FAST_8, + SLEW_FAST_16, + SLEW_IGNORE = 0xff, +}; + struct soc_intel_pantherlake_config {
/* Common struct containing soc config data required by common code */ @@ -70,7 +157,8 @@ struct soc_power_limits_config power_limits_config[PTL_POWER_LIMITS_COUNT];
/* Gpio group routed to each dword of the GPE0 block. Values are - * of the form PMC_GPP_[A:U] or GPD. */ + * of the form PMC_GPP_[A:U] or GPD. + */ uint8_t pmc_gpe0_dw0; /* GPE0_31_0 STS/EN */ uint8_t pmc_gpe0_dw1; /* GPE0_63_32 STS/EN */ uint8_t pmc_gpe0_dw2; /* GPE0_95_64 STS/EN */ @@ -82,44 +170,54 @@ uint32_t gen4_dec;
/* Enable S0iX support */ - int s0ix_enable; + bool s0ix_enable; /* Support for TCSS xhci, xdci, TBT PCIe root ports and DMA controllers */ - uint8_t tcss_d3_hot_disable; + bool tcss_d3_hot_disable; /* Support for TBT PCIe root ports and DMA controllers with D3Hot->D3Cold */ - uint8_t TcssD3ColdDisable; + bool tcss_d3_cold_disable; /* Enable DPTF support */ - int dptf_enable; + bool dptf_enable;
/* Deep SX enable for both AC and DC */ - int deep_s3_enable_ac; - int deep_s3_enable_dc; - int deep_s5_enable_ac; - int deep_s5_enable_dc; + bool deep_s3_enable_ac; + bool deep_s3_enable_dc; + bool deep_s5_enable_ac; + bool deep_s5_enable_dc;
/* Deep Sx Configuration * DSX_EN_WAKE_PIN - Enable WAKE# pin * DSX_EN_LAN_WAKE_PIN - Enable LAN_WAKE# pin - * DSX_DIS_AC_PRESENT_PD - Disable pull-down on AC_PRESENT pin */ + * DSX_DIS_AC_PRESENT_PD - Disable pull-down on AC_PRESENT pin + */ uint32_t deep_sx_config;
/* TCC activation offset */ uint32_t tcc_offset;
+ /* In-Band ECC (IBECC) configuration */ + struct ibecc_config ibecc; + /* System Agent dynamic frequency support. Only effects ULX/ULT CPUs. * When enabled memory will be training at two different frequencies. - * 0:Disabled, 1:FixedPoint0, 2:FixedPoint1, 3:FixedPoint2, - * 4:FixedPoint3, 5:Enabled */ + * 0:Disabled, 1:Enabled + */ enum { - SaGv_Disabled, - SaGv_FixedPoint0, - SaGv_FixedPoint1, - SaGv_FixedPoint2, - SaGv_FixedPoint3, - SaGv_Enabled, + SAGV_DISABLED, + SAGV_ENABLED, } sagv;
- /* Rank Margin Tool. 1:Enable, 0:Disable */ - uint8_t rmt; + /* System Agent dynamic frequency work points that memory will be training + * at the enabled frequencies. Possible work points are: + * 0x3:Points0_1, 0x7:Points0_1_2, 0xF:AllPoints0_1_2_3 + */ + enum { + SAGV_POINTS_0_1 = 0x03, + SAGV_POINTS_0_1_2 = 0x07, + SAGV_POINTS_0_1_2_3 = 0x0f, + } sagv_wp_bitmap; + + /* Rank Margin Tool. true:Enable, false:Disable */ + bool rmt;
/* USB related */ struct usb2_port_config usb2_ports[CONFIG_SOC_INTEL_USB2_DEV_MAX]; @@ -137,7 +235,9 @@ bool tbt_authentication;
/* Audio related */ - uint8_t pch_hda_dsp_enable; + bool pch_hda_audio_link_hda_enable; + bool pch_hda_dsp_enable; + bool pch_hda_sdi_enable[MAX_HD_AUDIO_SDI_LINKS];
/* iDisp-Link T-Mode 0: 2T, 2: 4T, 3: 8T, 4: 16T */ enum { @@ -178,9 +278,84 @@ IGD_SM_52MB = 0xFC, IGD_SM_56MB = 0xFD, IGD_SM_60MB = 0xFE, - } IgdDvmt50PreAlloc; + } igd_dvmt50_pre_alloc; + bool skip_ext_gfx_scan;
+ /* Enable/Disable EIST. true:Enabled, false:Disabled */ + bool eist_enable; + + /* + * When enabled, this feature makes the SoC throttle when the power + * consumption exceeds the I_TRIP threshold. + * + * FSPs sets a by default I_TRIP threshold adapted to the current SoC + * and assuming a Voltage Regulator error accuracy of 6.5%. + */ + bool enable_fast_vmode[NUM_VR_DOMAINS]; + + /* + * Current Excursion Protection needs to be set for each VR domain + * in order to be able to enable fast Vmode. + */ + bool cep_enable[NUM_VR_DOMAINS]; + + /* + * VR Fast Vmode I_TRIP threshold. + * 0-255A in 1/4 A units. Example: 400 = 100A + * This setting overrides the default value set by FSPs when Fast VMode + * is enabled. + */ + uint16_t fast_vmode_i_trip[NUM_VR_DOMAINS]; + + /* + * Power state current threshold 1. + * Defined in 1/4 A increments. A value of 400 = 100A. Range 0-512, + * which translates to 0-128A. 0 = AUTO. [0] for IA, [1] for GT, [2] for + * SA, [3] through [5] are Reserved. + */ + uint16_t ps_cur_1_threshold[NUM_VR_DOMAINS]; + + /* + * Power state current threshold 2. + * Defined in 1/4 A increments. A value of 400 = 100A. Range 0-512, + * which translates to 0-128A. 0 = AUTO. [0] for IA, [1] for GT, [2] for + * SA, [3] through [5] are Reserved. + */ + uint16_t ps_cur_2_threshold[NUM_VR_DOMAINS]; + + /* + * Power state current threshold 3. + * Defined in 1/4 A increments. A value of 400 = 100A. Range 0-512, + * which translates to 0-128A. 0 = AUTO. [0] for IA, [1] for GT, [2] for + * SA, [3] through [5] are Reserved. + */ + uint16_t ps_cur_3_threshold[NUM_VR_DOMAINS]; + + /* + * SerialIO device mode selection: + * PchSerialIoDisabled, + * PchSerialIoPci, + * PchSerialIoHidden, + * PchSerialIoLegacyUart, + * PchSerialIoSkipInit + */ + uint8_t serial_io_i2c_mode[CONFIG_SOC_INTEL_I2C_DEV_MAX]; + uint8_t serial_io_gspi_mode[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX]; + uint8_t serial_io_uart_mode[CONFIG_SOC_INTEL_UART_DEV_MAX]; + /* + * GSPIn Default Chip Select Mode: + * 0:Hardware Mode, + * 1:Software Mode + */ + uint8_t serial_io_gspi_cs_mode[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX]; + /* + * GSPIn Default Chip Select State: + * 0: Low, + * 1: High + */ + uint8_t serial_io_gspi_cs_state[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX]; + /* CNVi WiFi Core Enable/Disable */ bool cnvi_wifi_core;
@@ -190,43 +365,6 @@ /* CNVi BT Audio Offload: Enable/Disable BT Audio Offload. */ bool cnvi_bt_audio_offload;
- /* In-Band ECC (IBECC) configuration */ - struct ibecc_config ibecc; - - /* HeciEnabled decides the state of Heci1 at end of boot - * Setting to 0 (default) disables Heci1 and hides the device from OS */ - uint8_t HeciEnabled; - - /* Enable/Disable EIST. 1b:Enabled, 0b:Disabled */ - uint8_t eist_enable; - - /* Enable C6 DRAM */ - uint8_t enable_c6dram; - uint8_t PmTimerDisabled; - /* - * SerialIO device mode selection: - * PchSerialIoDisabled, - * PchSerialIoPci, - * PchSerialIoHidden, - * PchSerialIoLegacyUart, - * PchSerialIoSkipInit - */ - uint8_t SerialIoI2cMode[CONFIG_SOC_INTEL_I2C_DEV_MAX]; - uint8_t SerialIoGSpiMode[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX]; - uint8_t SerialIoUartMode[CONFIG_SOC_INTEL_UART_DEV_MAX]; - /* - * GSPIn Default Chip Select Mode: - * 0:Hardware Mode, - * 1:Software Mode - */ - uint8_t SerialIoGSpiCsMode[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX]; - /* - * GSPIn Default Chip Select State: - * 0: Low, - * 1: High - */ - uint8_t SerialIoGSpiCsState[CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX]; - /* Debug interface selection */ enum { DEBUG_INTERFACE_RAM = BIT(0), @@ -288,11 +426,6 @@ /* Enable(1)/Disable(0) HPD/DDC */ uint8_t ddi_ports_config[DDI_PORT_COUNT];
- /* Hybrid storage mode enable (1) / disable (0) - * This mode makes FSP detect Optane and NVME and set PCIe lane mode - * accordingly */ - uint8_t HybridStorageMode; - /* * Override CPU flex ratio value: * CPU ratio value controls the maximum processor non-turbo ratio. @@ -307,25 +440,78 @@ uint8_t cpu_ratio_override;
/* - * Enable(0)/Disable(1) DMI Power Optimizer on PCH side. - * Default 0. Setting this to 1 disables the DMI Power Optimizer. + * Enable(true)/Disable(false) CPU Replacement check. + * Default false. Setting this to true to check CPU replacement. */ - uint8_t DmiPwrOptimizeDisable; - - /* - * Enable(1)/Disable(0) CPU Replacement check. - * Default 0. Setting this to 1 to check CPU replacement. - */ - uint8_t cpu_replacement_check; + bool cpu_replacement_check;
/* ISA Serial Base selection. */ enum { ISA_SERIAL_BASE_ADDR_3F8, ISA_SERIAL_BASE_ADDR_2F8, - } IsaSerialUartBase; + } isa_serial_uart_base;
- /* USB overcurrent pin mapping */ - uint8_t pch_usb_oc_enable; + /* + * Enable or Disable C1 C-state Auto Demotion & un-demotion + * The algorithm looks at the behavior of the wake up tracker, how + * often it is waking up, and based on that it demote the c-state. + * Default false. Set this to true in order to disable C1-state auto + * demotion. + * NOTE: Un-Demotion from Demoted C1 needs to be disabled when + * C1 C-state Auto Demotion is disabled. + */ + bool disable_c1_state_auto_demotion; + + /* + * Enable or Disable Package C-state Demotion. + * Default is set to false. + * Set this to true in order to disable Package C-state demotion. + * NOTE: Un-Demotion from demoted Package C-state needs to be disabled + * when auto demotion is disabled. + */ + bool disable_package_c_state_demotion; + + /* Enable PCH to CPU energy report feature. */ + bool pch_pm_energy_report_enable; + + /* Energy-Performance Preference (HWP feature) */ + bool enable_energy_perf_pref; + uint8_t energy_perf_pref_value; + + bool disable_vmx; + + /* + * SAGV Frequency per point in Mhz. 0 is Auto, otherwise holds the + * frequency value expressed as an integer. For example: 1867 + */ + uint16_t sagv_freq_mhz[MAX_SAGV_POINTS]; + + /* Gear Selection for SAGV points. 0: Auto, 1: Gear 1, 2: Gear 2, 4: Gear 4 */ + uint8_t sagv_gear[MAX_SAGV_POINTS]; + + /* + * Enable or Disable Reduced BasicMemoryTest size. + * Default is set to false. + * Set this to true in order to reduce BasicMemoryTest size + */ + bool lower_basic_mem_test_size; + + /* Platform Power Pmax in Watts. Zero means automatic. */ + uint16_t psys_pmax_watts; + + /* Platform Power Limit 2 in Watts. */ + uint16_t psys_pl2_watts; + + /* Enable or Disable Acoustic Noise Mitigation feature */ + bool enable_acoustic_noise_mitigation; + /* Disable Fast Slew Rate for Deep Package C States for VR domains */ + bool disable_fast_pkgc_ramp[NUM_VR_DOMAINS]; + /* + * Slew Rate configuration for Deep Package C States for VR domains + * as per `enum slew_rate` data type. + */ + uint8_t slow_slew_rate_config[NUM_VR_DOMAINS]; + };
typedef struct soc_intel_pantherlake_config config_t; diff --git a/src/soc/intel/pantherlake/chipset.cb b/src/soc/intel/pantherlake/chipset.cb index 91e21c0..4f6c8e04 100644 --- a/src/soc/intel/pantherlake/chipset.cb +++ b/src/soc/intel/pantherlake/chipset.cb @@ -2,12 +2,24 @@
device cpu_cluster 0 on end
- register "power_limits_config[PTL_U_15W_POWER_LIMITS]" = "{ + register "power_limits_config[PTL_U_1_CORE]" = "{ .tdp_pl1_override = 15, .tdp_pl2_override = 54, .tdp_pl4 = 142, }"
+ register "power_limits_config[PTL_H_1_CORE]" = "{ + .tdp_pl1_override = 25, + .tdp_pl2_override = 64, + .tdp_pl4 = 154, + }" + + register "power_limits_config[PTL_H_2_CORE]" = "{ + .tdp_pl1_override = 25, + .tdp_pl2_override = 80, + .tdp_pl4 = 240, + }" + # NOTE: if any variant wants to override this value, use the same format # as register "common_soc_config.pch_thermal_trip" = "value", instead of # putting it under register "common_soc_config" in overridetree.cb file. @@ -116,7 +128,7 @@ end end end - device pci 14.2 alias shared_sram off end + device pci 14.2 alias pmc_shared_sram off end device pci 14.3 alias cnvi_wifi off end device pci 14.7 alias cnvi_bluetooth off end device pci 14.5 alias ieh off end diff --git a/src/soc/intel/pantherlake/cpu.c b/src/soc/intel/pantherlake/cpu.c new file mode 100644 index 0000000..13a1d9e --- /dev/null +++ b/src/soc/intel/pantherlake/cpu.c @@ -0,0 +1,226 @@ +/* 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/microcode.h> +#include <cpu/intel/smm_reloc.h> +#include <cpu/intel/turbo.h> +#include <cpu/x86/lapic.h> +#include <cpu/x86/mp.h> +#include <cpu/x86/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 |= FAST_STRINGS_ENABLE_BIT; + msr.lo |= TM1_TM2_EMTTM_ENABLE_BIT; + 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 = CRITICAL_TEMP_INTERRUPT_ENABLE; + msr.hi = 0; + wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr); + + /* Enable PROCHOT and Power Performance Platform Override */ + msr = rdmsr(MSR_POWER_CTL); + msr.lo |= ENABLE_BIDIR_PROCHOT; + msr.lo |= VR_THERM_ALERT_DISABLE_LOCK; + msr.lo |= PWR_PERF_PLATFORM_OVR; + wrmsr(MSR_POWER_CTL, msr); +} + +enum core_type get_soc_cpu_type(void) +{ + if (cpu_is_hybrid_supported()) + return cpu_get_cpu_type(); + + 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 */ + 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); + + const config_t *conf = config_of_soc(); + /* Set energy-performance preference */ + if (conf != NULL && conf->enable_energy_perf_pref) { + if (check_energy_perf_cap()) + set_energy_perf_pref(conf->energy_perf_pref_value); + } + + /* Enable Turbo */ + enable_turbo(); + + /* Set core type in struct cpu_info */ + set_dev_core_type(); + + if (CONFIG(INTEL_TME) && is_tme_supported()) + set_tme_core_activate(); + + /* TODO: Add support for DROP_CPU_FEATURE_PROGRAM_IN_FSP */ +} + +static void per_cpu_smm_trigger(void) +{ + /* Relocate the SMM handler. */ + smm_relocate(); +} + +static void pre_mp_init(void) +{ + soc_fsp_load(); + + const config_t *conf = config_of_soc(); + if (conf == NULL) { + printk(BIOS_ERR, "Configuration could not be retrieved.\n"); + return; + } + if (conf->enable_energy_perf_pref) { + if (check_energy_perf_cap()) + enable_energy_perf_pref(); + else + printk(BIOS_WARNING, "Energy Performance Preference not supported!\n"); + } +} + +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 = pre_mp_init, + .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(); +} + +int soc_skip_ucode_update(u32 current_patch_id, u32 new_patch_id) +{ + if (!CONFIG(CHROMEOS)) + return 0; + /* + * Locked RO Descriptor Implications: + * + * - A locked descriptor signals the RO binary is fixed; the FIT will load the + * RO's microcode during system reset. + * - Attempts to load newer microcode from the RW CBFS will cause a boot-time + * delay (~60ms, core-dependent), as the microcode must be reloaded on BSP+APs. + * - The kernel can load microcode updates without impacting AP FW boot time. + * - Skipping RW CBFS microcode loading is low-risk when the RO is locked, + * prioritizing fast boot times. + */ + if (CONFIG(LOCK_MANAGEMENT_ENGINE) && current_patch_id) + return 1; + + return 0; +} diff --git a/src/soc/intel/pantherlake/crashlog.c b/src/soc/intel/pantherlake/crashlog.c new file mode 100644 index 0000000..d94f4c5 --- /dev/null +++ b/src/soc/intel/pantherlake/crashlog.c @@ -0,0 +1,516 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/bert_storage.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/intel/cpu_ids.h> +#include <delay.h> +#include <device/pci_ops.h> +#include <intelblocks/crashlog.h> +#include <intelblocks/pmc_ipc.h> +#include <soc/crashlog.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <string.h> + +#define CONTROL_INTERFACE_OFFSET 0x5 +#define CRASHLOG_NODES_COUNT 0x2 +#define CRASHLOG_PUNIT_STORAGE_OFF_MASK BIT(24) +#define CRASHLOG_RE_ARM_STATUS_MASK BIT(25) +#define CRASHLOG_CONSUMED_MASK BIT(31) + +/* Global crashLog info */ +static bool m_pmc_crash_log_support; +static bool m_pmc_crash_log_present; +static bool m_cpu_crash_log_support; +static bool m_cpu_crash_log_present; +static u32 m_pmc_crash_log_size; +static u32 m_cpu_crash_log_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; +static uintptr_t disc_tab_addr; + +static u64 get_disc_tab_header(void) +{ + return read64p(disc_tab_addr); +} + +/* Get the SRAM BAR. */ +static uintptr_t get_sram_bar(pci_devfn_t sram_devfn) +{ + 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; + } + + /* Return the base address of the resource */ + return res->base; +} + +static void configure_sram(const struct device *sram_dev, uintptr_t 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(cl_node_t *head) +{ + uintptr_t pmc_sram_base = cl_get_cpu_tmp_bar(); + u32 pmc_crashLog_size = cl_get_pmc_record_size(); + cl_node_t *cl_cur = head; + + if (!pmc_crashLog_size) { + printk(BIOS_ERR, "No PMC crashlog records\n"); + return; + } + + if (!pmc_sram_base) { + printk(BIOS_ERR, "PMC SRAM base not valid\n"); + return; + } + + if (!cl_pmc_sram_has_mmio_access()) + return; + + printk(BIOS_DEBUG, "PMC crashLog size : 0x%x\n", pmc_crashLog_size); + + /* Goto tail node */ + while (cl_cur && cl_cur->next) { + cl_cur = cl_cur->next; + } + + /* Process crashlog records */ + for (int i = 0; i < descriptor_table.numb_regions + 1; i++) { + uintptr_t sram_base = 0; + bool pmc_sram = true; + 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; + + /* + * Region with metadata TAG contains information about BDF entry for SOC PMC SRAM + * and IOE SRAM. We don't need to parse this as we already define BDFs in + * soc/pci_devs.h for these SRAMs. Also we need to skip this region as it does not + * contain any crashlog data. + */ + if (descriptor_table.regions[i].bits.assign_tag == + CRASHLOG_DESCRIPTOR_TABLE_TAG_META) { + pmc_crashLog_size -= descriptor_table.regions[i].bits.size * + sizeof(u32); + printk(BIOS_DEBUG, "Found metadata tag. PMC crashlog size adjusted to: 0x%x\n", + pmc_crashLog_size); + continue; + } else { + if (descriptor_table.regions[i].bits.assign_tag == + CRASHLOG_DESCRIPTOR_TABLE_TAG_SOC) + sram_base = pmc_sram_base; + else + continue; + + cl_node_t *cl_node = malloc_cl_node(descriptor_table.regions[i].bits.size); + + if (!cl_node) { + printk(BIOS_DEBUG, "failed to allocate cl_node [region = %d]\n", i); + goto pmc_send_re_arm_after_reset; + } + + if (cl_copy_data_from_sram(sram_base, + descriptor_table.regions[i].bits.offset, + descriptor_table.regions[i].bits.size, + cl_node->data, + i, + pmc_sram)) { + cl_cur->next = cl_node; + cl_cur = cl_cur->next; + } else { + /* Coping data from sram failed */ + 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); + /* Free cl_node */ + free_cl_node(cl_node); + } + } + } + + update_new_pmc_crashlog_size(&pmc_crashLog_size); + +pmc_send_re_arm_after_reset: + /* 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) +{ + uintptr_t 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_crash_log_support = false; + m_pmc_crash_log_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_crash_log_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_crash_log_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_crash_log_size); + m_pmc_crash_log_present = m_pmc_crash_log_size > 0; + + return true; +} + +uintptr_t cl_get_cpu_bar_addr(void) +{ + uintptr_t 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; +} + +uintptr_t 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 u32 get_disc_table_offset(void) +{ + u32 offset = cpu_cl_devsc_cap.discovery_data.fields.discovery_table_offset; + + return offset; +} + +static bool is_crashlog_data_valid(u32 dw0) +{ + return (dw0 != 0x0 && dw0 != INVALID_CRASHLOG_RECORD); +} + +static bool cpu_cl_gen_discovery_table(void) +{ + uintptr_t bar_addr = cl_get_cpu_bar_addr(); + + if (!bar_addr) + return false; + + disc_tab_addr = bar_addr + get_disc_table_offset(); + memset(&cpu_cl_disc_tab, 0, sizeof(cpu_crashlog_discovery_table_t)); + cpu_cl_disc_tab.header.data = get_disc_tab_header(); + /* Check both 32 bit header data and status register for non-zero values */ + if ((!is_crashlog_data_valid(cpu_cl_disc_tab.header.data & 0xFFFFFFFF)) && + (!is_crashlog_data_valid((cpu_cl_disc_tab.header.data) >> 32))) + return false; + + u32 cur_offset = 0; + cpu_cl_disc_tab.header.fields.count = CRASHLOG_NODES_COUNT; + printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer count: 0x%x\n", + cpu_cl_disc_tab.header.fields.count); + for (int i = 0; i < cpu_cl_disc_tab.header.fields.count; i++) { + cur_offset = 8 + 24 * i; + u32 cl_buffer_size = read32p(disc_tab_addr + cur_offset + 4); + /* Check for buffer size */ + if (!(is_crashlog_data_valid(cl_buffer_size))) + continue; + + u32 dw0 = read32p(disc_tab_addr + cur_offset); + if (dw0 & CRASHLOG_CONSUMED_MASK) { + printk(BIOS_DEBUG, "cpu crashlog records already consumed." + "id: 0x%x dw0: 0x%x\n", i, dw0); + break; + } + + cpu_cl_disc_tab.buffers[i].data = read64p(disc_tab_addr + cur_offset); + 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_crash_log_size += cpu_cl_disc_tab.buffers[i].fields.size * sizeof(u32); + } + + if (m_cpu_crash_log_size > 0) + m_cpu_crash_log_present = true; + else + m_cpu_crash_log_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_crash_log_support = false; + return false; + } + + m_cpu_crash_log_support = true; + + if (!cpu_cl_gen_discovery_table()) { + printk(BIOS_ERR, "CPU crashlog discovery table not valid.\n"); + m_cpu_crash_log_present = false; + return false; + } + + 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_crash_log_size, m_cpu_crash_log_size); + return m_pmc_crash_log_size + m_cpu_crash_log_size; +} + +static uintptr_t get_control_status_interface(void) +{ + if (disc_tab_addr) + return (disc_tab_addr + CONTROL_INTERFACE_OFFSET * sizeof(u32)); + return 0; +} + +int cpu_cl_clear_data(void) +{ + return 0; +} + +static bool wait_and_check(u32 bit_mask) +{ + u32 stall_cnt = 0; + + do { + cpu_cl_disc_tab.header.data = get_disc_tab_header(); + udelay(CPU_CRASHLOG_WAIT_STALL); + stall_cnt++; + } while (((cpu_cl_disc_tab.header.data & bit_mask) == 0) && + ((stall_cnt * CPU_CRASHLOG_WAIT_STALL) < CPU_CRASHLOG_WAIT_TIMEOUT)); + + return (cpu_cl_disc_tab.header.data & bit_mask); +} + +void cpu_cl_rearm(void) +{ + uintptr_t ctrl_sts_intfc_addr = get_control_status_interface(); + + if (!ctrl_sts_intfc_addr) { + printk(BIOS_ERR, "CPU crashlog control and status interface address not valid\n"); + return; + } + + /* Rearm the CPU crashlog. Crashlog does not get collected if rearming fails */ + cl_punit_control_interface_t punit_ctrl_intfc; + memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t)); + punit_ctrl_intfc.fields.set_re_arm = 1; + write32p(ctrl_sts_intfc_addr, punit_ctrl_intfc.data); + + if (!wait_and_check(CRASHLOG_RE_ARM_STATUS_MASK)) + printk(BIOS_ERR, "CPU crashlog re_arm not asserted\n"); + else + printk(BIOS_DEBUG, "CPU crashlog re_arm asserted\n"); +} + +void cpu_cl_cleanup(void) +{ + /* Perform any SOC specific cleanup after reading the crashlog data from SRAM */ + uintptr_t ctrl_sts_intfc_addr = get_control_status_interface(); + + if (!ctrl_sts_intfc_addr) { + printk(BIOS_ERR, "CPU crashlog control and status interface address not valid\n"); + return; + } + + /* If storage-off is supported, turn off the PUNIT SRAM + * stroage to save power. This clears crashlog records also. + */ + + if (!cpu_cl_disc_tab.header.fields.storage_off_support) { + printk(BIOS_INFO, "CPU crashlog storage_off not supported\n"); + return; + } + + cl_punit_control_interface_t punit_ctrl_intfc; + memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t)); + punit_ctrl_intfc.fields.set_storage_off = 1; + write32p(ctrl_sts_intfc_addr, punit_ctrl_intfc.data); + + if (!wait_and_check(CRASHLOG_PUNIT_STORAGE_OFF_MASK)) + printk(BIOS_ERR, "CPU crashlog storage_off not asserted\n"); + else + printk(BIOS_DEBUG, "CPU crashlog storage_off asserted\n"); +} + +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_crash_log_size; +} + +int cl_get_cpu_record_size(void) +{ + return m_cpu_crash_log_size; +} + +bool cl_cpu_data_present(void) +{ + return m_cpu_crash_log_present; +} + +bool cl_pmc_data_present(void) +{ + return m_pmc_crash_log_present; +} + +bool cpu_crashlog_support(void) +{ + return m_cpu_crash_log_support; +} + +bool pmc_crashlog_support(void) +{ + return m_pmc_crash_log_support; +} + +void update_new_pmc_crashlog_size(u32 *pmc_crash_size) +{ + m_pmc_crash_log_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_crash_log_size = *cpu_crash_size; +} diff --git a/src/soc/intel/pantherlake/cse_telemetry.c b/src/soc/intel/pantherlake/cse_telemetry.c new file mode 100644 index 0000000..6a599c9 --- /dev/null +++ b/src/soc/intel/pantherlake/cse_telemetry.c @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/console.h> +#include <intelblocks/cse.h> +#include <timestamp.h> + +void soc_cbmem_inject_telemetry_data(s64 *ts, s64 current_time) +{ + s64 start_stamp; + + if (!ts) { + printk(BIOS_ERR, "%s: Failed to insert CSME timestamps\n", __func__); + return; + } + + start_stamp = current_time - ts[PERF_DATA_CSME_GET_PERF_RESPONSE]; + + timestamp_add(TS_ME_ROM_START, start_stamp); + timestamp_add(TS_ME_BOOT_STALL_END, + start_stamp + ts[PERF_DATA_CSME_RBE_BOOT_STALL_DONE_TO_PMC]); + timestamp_add(TS_ME_ICC_CONFIG_START, + start_stamp + ts[PERF_DATA_CSME_GOT_ICC_CFG_START_MSG_FROM_PMC]); + timestamp_add(TS_ME_HOST_BOOT_PREP_END, + start_stamp + ts[PERF_DATA_CSME_HOST_BOOT_PREP_DONE]); + timestamp_add(TS_ME_RECEIVED_CRDA_FROM_PMC, + start_stamp + ts[PERF_DATA_PMC_SENT_CRDA]); + timestamp_add(TS_ISSE_DMU_LOAD_END, + start_stamp + ts[PERF_DATA_ISSE_DMU_LOAD_COMPLETED]); +} diff --git a/src/soc/intel/pantherlake/elog.c b/src/soc/intel/pantherlake/elog.c new file mode 100644 index 0000000..fce408f --- /dev/null +++ b/src/soc/intel/pantherlake/elog.c @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <console/console.h> +#include <device/pci_ops.h> +#include <elog.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/xhci.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_info.h> +#include <types.h> + +struct pme_map { + unsigned int devfn; + unsigned int wake_source; +}; + +static void pch_log_gpio_gpe(u32 gpe0_sts, u32 gpe0_en, int start) +{ + int i; + + gpe0_sts &= gpe0_en; + + for (i = 0; i <= 31; i++) { + if (gpe0_sts & (1 << i)) + elog_add_event_wake(ELOG_WAKE_SOURCE_GPE, i + start); + } +} + +static void pch_log_rp_wake_source(void) +{ + size_t i; + uint8_t max_port = get_max_pcie_port(); + + const struct pme_map pme_map[] = { + { PCI_DEVFN_PCIE1, ELOG_WAKE_SOURCE_PME_PCIE1 }, + { PCI_DEVFN_PCIE2, ELOG_WAKE_SOURCE_PME_PCIE2 }, + { PCI_DEVFN_PCIE3, ELOG_WAKE_SOURCE_PME_PCIE3 }, + { PCI_DEVFN_PCIE4, ELOG_WAKE_SOURCE_PME_PCIE4 }, + { PCI_DEVFN_PCIE5, ELOG_WAKE_SOURCE_PME_PCIE5 }, + { PCI_DEVFN_PCIE6, ELOG_WAKE_SOURCE_PME_PCIE6 }, + { PCI_DEVFN_PCIE7, ELOG_WAKE_SOURCE_PME_PCIE7 }, + { PCI_DEVFN_PCIE8, ELOG_WAKE_SOURCE_PME_PCIE8 }, + { PCI_DEVFN_PCIE9, ELOG_WAKE_SOURCE_PME_PCIE9 }, + { PCI_DEVFN_PCIE10, ELOG_WAKE_SOURCE_PME_PCIE10 }, +#if CONFIG(SOC_INTEL_PANTHERLAKE_U_H) + { PCI_DEVFN_PCIE11, ELOG_WAKE_SOURCE_PME_PCIE11 }, + { PCI_DEVFN_PCIE12, ELOG_WAKE_SOURCE_PME_PCIE12 }, +#endif + }; + + 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..05ec3ea --- /dev/null +++ b/src/soc/intel/pantherlake/finalize.c @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/io.h> +#include <bootstate.h> +#include <console/console.h> +#include <cpu/x86/smm.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_finalize(void) +{ + /* TCO Lock down */ + tco_lockdown(); + + 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..bc7b5b1 --- /dev/null +++ b/src/soc/intel/pantherlake/fsp_params.c @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <soc/ramstage.h> + +__weak void mainboard_update_soc_chip_config(struct soc_intel_pantherlake_config *config) +{ + /* Override settings per board. */ +} + +/* UPD parameters to be initialized before SiliconInit */ +void platform_fsp_silicon_init_params_cb(FSPS_UPD *supd) +{ + /* Override settings per board. */ +} + +/* 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..387d3e3 --- /dev/null +++ b/src/soc/intel/pantherlake/gspi.c @@ -0,0 +1,17 @@ +/* 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; + case 2: + return PCI_DEVFN_GSPI2; + } + 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..2ca9a10 --- /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 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..5b988e9 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/crashlog.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_CRASHLOG_H_ +#define _SOC_PANTHERLAKE_CRASHLOG_H_ + +#include <types.h> + +/* DVSEC capability Registers */ +#define TEL_DVSEC_OFFSET 0x100 +#define TEL_DVSEC_PCIE_CAP_ID 0x0 +#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 + +typedef union { + struct { + u32 reserved1 :27; + u32 set_storage_off :1; + u32 set_re_arm :1; + u32 reserved2 :1; + u32 set_clr :1; + u32 reserved3 :1; + } fields; + u32 data; +} __packed cl_punit_control_interface_t; + +#endif /* _SOC_PANTHERLAKE_CRASHLOG_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/dptf.h b/src/soc/intel/pantherlake/include/soc/dptf.h new file mode 100644 index 0000000..60b9deb --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/dptf.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_DPTF_H_ +#define _SOC_PANTHERLAKE_DPTF_H_ + +/* + * Below is a list of unique ACPI Device IDs for thermal and DPTF + * (Dynamic Platform and Thermal Framework) + */ +/* DPTF ACPI Device ID */ +#define DPTF_DPTF_DEVICE "INTC10D4" +/* Generic ACPI Device ID for TSR0/1/2/3 and charger */ +#define DPTF_GEN_DEVICE "INTC10D5" +/* Fan ACPI Device ID */ +#define DPTF_FAN_DEVICE "INTC10D6" +/* TPCH ACPI Device ID */ +#define DPTF_TPCH_DEVICE "INTC10D7" +/* TPWR ACPI Device ID */ +#define DPTF_TPWR_DEVICE "INTC10D8" +/* BAT1 ACPI Device ID */ +#define DPTF_BAT1_DEVICE "INTC10D9" + +#endif diff --git a/src/soc/intel/pantherlake/include/soc/iomap.h b/src/soc/intel/pantherlake/include/soc/iomap.h index 652bed8..2ecd28e 100644 --- a/src/soc/intel/pantherlake/include/soc/iomap.h +++ b/src/soc/intel/pantherlake/include/soc/iomap.h @@ -20,6 +20,9 @@ #define SAF_BASE_ADDRESS 0x3ffe000000 #define SAF_BASE_SIZE 0x2000000
+/* Add dummy entry to cater common/block/acpi/acpi/northbridge.asl */ +#define DMI_BASE_SIZE 0 + #define EP_BASE_ADDRESS 0xfeda1000 #define EP_BASE_SIZE 0x1000
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..5d94ed2 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/irq.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_PANTHERLAKE_IRQ_H_ +#define _SOC_PANTHERLAKE_IRQ_H_ + +#define GPIO_IRQ14 14 +#define GPIO_IRQ15 15 + +#define PCH_IRQ10 10 +#define PCH_IRQ11 11 + +#endif 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..c6032f4 --- /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 diff --git a/src/soc/intel/pantherlake/include/soc/p2sb.h b/src/soc/intel/pantherlake/include/soc/p2sb.h index c431ad6..9bf7e2d 100644 --- a/src/soc/intel/pantherlake/include/soc/p2sb.h +++ b/src/soc/intel/pantherlake/include/soc/p2sb.h @@ -8,7 +8,7 @@
#define PCH_P2SB_EPMASK0 0x220
-extern struct device_operations soc_p2sb_ops; -extern struct device_operations soc_p2sb_2_ops; +extern struct device_operations pcd_p2sb_ops; +extern struct device_operations pcd_p2sb_2_ops;
-#endif /* _SOC_PANTHERLAKE_P2SB_H_ */ +#endif 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..89f9c37 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/pcie.h @@ -0,0 +1,11 @@ +/* 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); +const struct pcie_rp_group *get_tbt_pcie_rp_table(void); + +#endif diff --git a/src/soc/intel/pantherlake/include/soc/pmc.h b/src/soc/intel/pantherlake/include/soc/pmc.h index daa60f2..415bf07 100644 --- a/src/soc/intel/pantherlake/include/soc/pmc.h +++ b/src/soc/intel/pantherlake/include/soc/pmc.h @@ -23,7 +23,7 @@ #define MEM_SR BIT(21) #define ALLOW_SPXB_CG_INC0 BIT(20) #define ALLOW_L1LOW_C0 BIT(19) -#define MS4V BIT(18) +#define MS4V BIT_FLAG_32(18) #define ALLOW_L1LOW_OPI_ON BIT(17) #define SUS_PWR_FLR BIT(16) #define PME_B0_S5_DIS BIT(15) 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..c906f7d --- /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 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..def5565 --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/serialio.h @@ -0,0 +1,35 @@ +/* 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 { + PchSerialIoIndexGSPI0, + PchSerialIoIndexGSPI1, + PchSerialIoIndexGSPI2, +}; + +enum { + PchSerialIoIndexUART0, + PchSerialIoIndexUART1, + PchSerialIoIndexUART2 +}; + +#endif /* _SOC_PANTHERLAKE_SERIALIO_H_ */ diff --git a/src/soc/intel/pantherlake/include/soc/systemagent.h b/src/soc/intel/pantherlake/include/soc/systemagent.h index c791e5b..fbe8dd2 100644 --- a/src/soc/intel/pantherlake/include/soc/systemagent.h +++ b/src/soc/intel/pantherlake/include/soc/systemagent.h @@ -15,6 +15,9 @@ /* MCHBAR offsets */ #define VTDBAR 0x5410 #define GFXVTBAR VTDBAR +#define GFXVT_ENABLED BIT(0) +#define NONGFXVT_ENABLED BIT(1) +#define IOCVT_ENABLED BIT(2) #define REGBAR 0x5420 #define MCH_DDR_POWER_LIMIT_LO 0x58e0 #define MCH_DDR_POWER_LIMIT_HI 0x58e4 @@ -50,18 +53,6 @@ #define LT_SECURITY_SIZE (384 * KiB) #define APIC_SIZE (1 * MiB)
-#define MASK_PCIEXBAR_LENGTH 0x0000000E // bits [3:1] -#define PCIEXBAR_LENGTH_LSB 1 // used to shift right - -#define DSM_BASE_ADDR_REG 0xB0 -#define MASK_DSM_LENGTH 0xFF00 // [15:8] -#define MASK_DSM_LENGTH_LSB 8 // used to shift right -#define MASK_GSM_LENGTH 0xC0 // [7:6] -#define MASK_GSM_LENGTH_LSB 6 // used to shift right -#define DPR_REG 0x5C -#define MASK_DPR_LENGTH 0xFF0 // [11:4] -#define MASK_DPR_LENGTH_LSB 4 // used to shift right - uint64_t get_mmcfg_size(const struct device *dev); uint64_t get_dsm_size(const struct device *dev); uint64_t get_gsm_size(const struct device *dev); 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..79604bc --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/tcss.h @@ -0,0 +1,19 @@ +/* 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) + +#define BIAS_CTRL_VW_INDEX_SHIFT 24 +#define BIAS_CTRL_BIT_POS_SHIFT 16 + +#endif 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..1e68d8d --- /dev/null +++ b/src/soc/intel/pantherlake/include/soc/usb.h @@ -0,0 +1,155 @@ +/* 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; + uint8_t type_c; +}; + +/* 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, \ + .type_c = 1, \ +} + +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/p2sb.c b/src/soc/intel/pantherlake/p2sb.c new file mode 100644 index 0000000..52b3690 --- /dev/null +++ b/src/soc/intel/pantherlake/p2sb.c @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pci_def.h> +#include <intelblocks/p2sb.h> +#include <soc/iomap.h> + +void p2sb_soc_get_sb_mask(uint32_t *ep_mask, size_t count) +{ + uint32_t mask; + + if (count != P2SB_EP_MASK_MAX_REG) { + printk(BIOS_ERR, "Unable to program EPMASK registers\n"); + return; + } + + /* Remove the host accessing right to PSF register range. + * Set p2sb PCI offset EPMASK5 [29, 28, 27, 26] to disable Sideband + * access for PCI Root Bridge. + */ + mask = BIT(29) | BIT(28) | BIT(27) | BIT(26); + + ep_mask[P2SB_EP_MASK_5_REG] = mask; + + /* + * Set p2sb PCI offset EPMASK7 [31, 30] to disable Sideband + * access for Broadcast and Multicast. + */ + mask = BIT(31) | BIT(30); + + ep_mask[P2SB_EP_MASK_7_REG] = mask; +} + +static void p2sb2_read_resources(struct device *dev) +{ + /* Add the fixed MMIO resource for P2SB#2 */ + mmio_range(dev, PCI_BASE_ADDRESS_0, IOE_P2SB_BAR, IOE_P2SB_SIZE); +} + +static void p2sb_read_resources(struct device *dev) +{ + /* Add the fixed MMIO resource for P2SB#1 */ + mmio_range(dev, PCI_BASE_ADDRESS_0, P2SB_BAR, P2SB_SIZE); +} + +struct device_operations pcd_p2sb_2_ops = { + .read_resources = p2sb2_read_resources, + .set_resources = noop_set_resources, + .scan_bus = scan_static_bus, +}; + +struct device_operations pcd_p2sb_ops = { + .read_resources = p2sb_read_resources, + .set_resources = noop_set_resources, + .scan_bus = scan_static_bus, +}; diff --git a/src/soc/intel/pantherlake/pcie_rp.c b/src/soc/intel/pantherlake/pcie_rp.c new file mode 100644 index 0000000..374c3aa --- /dev/null +++ b/src/soc/intel/pantherlake/pcie_rp.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <intelblocks/pcie_rp.h> +#include <soc/pci_devs.h> +#include <soc/pcie.h> +#include <soc/soc_info.h> + +/* + * TBT's LCAP registers are returning port index which starts from 0x10 (Usually for other PCIe + * root ports index starts from 1). Thus keeping lcap_port_base 0x10 for TBT, so that coreboot's + * PCIe remapping logic can return correct index (0-based) + */ + +static const struct pcie_rp_group tbt_rp_groups[] = { + { .slot = PCI_DEV_SLOT_TBT, .count = CONFIG_MAX_TBT_ROOT_PORTS, .lcap_port_base = 0x10 }, + { 0 } +}; + +static const struct pcie_rp_group ptl_rp_groups[] = { + { .slot = PCI_DEV_SLOT_PCIE_1, .count = 8, .lcap_port_base = 1 }, +#if CONFIG(SOC_INTEL_PANTHERLAKE_U_H) + { .slot = PCI_DEV_SLOT_PCIE_2, .count = 4, .lcap_port_base = 1 }, +#else + { .slot = PCI_DEV_SLOT_PCIE_2, .count = 2, .lcap_port_base = 1 }, +#endif + { 0 } +}; + +const struct pcie_rp_group *get_pcie_rp_table(void) +{ + return ptl_rp_groups; +} + +const struct pcie_rp_group *get_tbt_pcie_rp_table(void) +{ + return tbt_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..91aeecd --- /dev/null +++ b/src/soc/intel/pantherlake/pmc.c @@ -0,0 +1,200 @@ +/* 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(); + if (pmcbase == NULL) { + printk(BIOS_ERR, "PMC MMIO regs could not be retrieved.\n"); + return; + } + + printk(BIOS_DEBUG, "%sabling Deep S%c\n", + enable ? "En" : "Dis", sx + '0'); + reg = read32(pmcbase + offset); + if (enable) + reg |= mask; + else + reg &= ~mask; + write32(pmcbase + offset, reg); +} + +static void config_deep_s5(int on_ac, int on_dc) +{ + /* Treat S4 the same as S5. */ + config_deep_sX(S4_PWRGATE_POL, S4AC_GATE_SUS, 4, on_ac); + config_deep_sX(S4_PWRGATE_POL, S4DC_GATE_SUS, 4, on_dc); + config_deep_sX(S5_PWRGATE_POL, S5AC_GATE_SUS, 5, on_ac); + config_deep_sX(S5_PWRGATE_POL, S5DC_GATE_SUS, 5, on_dc); +} + +static void config_deep_s3(int on_ac, int on_dc) +{ + config_deep_sX(S3_PWRGATE_POL, S3AC_GATE_SUS, 3, on_ac); + config_deep_sX(S3_PWRGATE_POL, S3DC_GATE_SUS, 3, on_dc); +} + +static void config_deep_sx(uint32_t deepsx_config) +{ + uint32_t reg; + uint8_t *pmcbase = pmc_mmio_regs(); + + reg = read32(pmcbase + DSX_CFG); + reg &= ~DSX_CFG_MASK; + reg |= deepsx_config; + write32(pmcbase + DSX_CFG, reg); +} + +static void soc_pmc_enable(struct device *dev) +{ + const config_t *config = config_of_soc(); + + rtc_init(); + + pmc_set_power_failure_state(true); + pmc_gpe_init(); + + config_deep_s3(config->deep_s3_enable_ac, config->deep_s3_enable_dc); + config_deep_s5(config->deep_s5_enable_ac, config->deep_s5_enable_dc); + config_deep_sx(config->deep_sx_config); +} + +static void soc_pmc_read_resources(struct device *dev) +{ + struct resource *res; + + /* Add the fixed MMIO resource */ + mmio_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"); + /* Hide the device so that Windows does not complain on missing driver */ + acpigen_write_STA(ACPI_STATUS_DEVICE_HIDDEN_ON); + + /* + * 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 ptl_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(&ptl_pmc_lpm); + } + + printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name, + dev_path(dev)); +} + +static void soc_pmc_init(struct device *dev) +{ + /* + * pmc_set_acpi_mode() should be delayed until BS_DEV_INIT in order + * to ensure the ordering does not break the assumptions that other + * drivers make about ACPI mode (e.g. Chrome EC). Since it disables + * ACPI mode, other drivers may take different actions based on this + * (e.g. Chrome EC will flush any pending hostevent bits). Because + * PTL has its PMC device available for device_operations, it can be + * done from the "ops->init" callback. + */ + pmc_set_acpi_mode(); + + /* + * Disable ACPI PM timer based on Kconfig + * + * Disabling ACPI PM timer is necessary for XTAL OSC shutdown. + * Disabling ACPI PM timer also switches off TCO + */ + if (!CONFIG(USE_PM_ACPI_TIMER)) + setbits8(pmc_mmio_regs() + PCH_PWRM_ACPI_TMR_CTL, ACPI_TIM_DIS); +} + +static void pm1_enable_pwrbtn_smi(void *unused) +{ + /* Enable power button SMI after BS_DEV_INIT_CHIPS (FSP-S) is done. */ + pmc_update_pm1_enable(PWRBTN_EN); +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, pm1_enable_pwrbtn_smi, NULL); + +/* + * `pmc_final` function is native implementation of equivalent events performed by + * each FSP NotifyPhase() API invocations. + * + * + * Clear PMCON status bits (Global Reset/Power Failure/Host Reset Status bits) + * + * Perform the PMCON status bit clear operation from `.final` + * to cover any such chances where later boot stage requested a global + * reset and PMCON status bit remains set. + */ +static void pmc_final(struct device *dev) +{ + pmc_clear_pmcon_sts(); +} + +struct device_operations pmc_ops = { + .read_resources = soc_pmc_read_resources, + .set_resources = noop_set_resources, + .init = soc_pmc_init, + .enable = soc_pmc_enable, +#if CONFIG(HAVE_ACPI_TABLES) + .acpi_fill_ssdt = soc_pmc_fill_ssdt, +#endif + .scan_bus = scan_static_bus, + .final = pmc_final, +}; diff --git a/src/soc/intel/pantherlake/pmutil.c b/src/soc/intel/pantherlake/pmutil.c new file mode 100644 index 0000000..892972c --- /dev/null +++ b/src/soc/intel/pantherlake/pmutil.c @@ -0,0 +1,267 @@ +/* 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 <intelblocks/pmclib.h> +#include <intelblocks/rtc.h> +#include <intelblocks/tco.h> +#include <intelpch/espi.h> +#include <security/vboot/vbnv.h> +#include <soc/gpe.h> +#include <soc/gpio.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/smbus.h> +#include <soc/soc_chip.h> +#include <types.h> + +/* + * SMI + */ +const char *const *soc_smi_sts_array(size_t *a) +{ + static const char *const smi_sts_bits[] = { + [BIOS_STS_BIT] = "BIOS", + [LEGACY_USB_STS_BIT] = "LEGACY_USB", + [SMI_ON_SLP_EN_STS_BIT] = "SLP_SMI", + [APM_STS_BIT] = "APM", + [SWSMI_TMR_STS_BIT] = "SWSMI_TMR", + [PM1_STS_BIT] = "PM1", + [GPE0_STS_BIT] = "GPE0", + [GPIO_STS_BIT] = "GPI", + [MCSMI_STS_BIT] = "MCSMI", + [DEVMON_STS_BIT] = "DEVMON", + [TCO_STS_BIT] = "TCO", + [PERIODIC_STS_BIT] = "PERIODIC", + [SERIRQ_SMI_STS_BIT] = "SERIRQ_SMI", + [SMBUS_SMI_STS_BIT] = "SMBUS_SMI", + [PCI_EXP_SMI_STS_BIT] = "PCI_EXP_SMI", + [MONITOR_STS_BIT] = "MONITOR", + [SPI_SMI_STS_BIT] = "SPI", + [GPIO_UNLOCK_SMI_STS_BIT] = "GPIO_UNLOCK", + [ESPI_SMI_STS_BIT] = "ESPI_SMI", + }; + + *a = ARRAY_SIZE(smi_sts_bits); + return smi_sts_bits; +} + +/* + * TCO + */ +const char *const *soc_tco_sts_array(size_t *a) +{ + static const char *const tco_sts_bits[] = { + [0] = "NMI2SMI", + [1] = "SW_TCO", + [2] = "TCO_INT", + [3] = "TIMEOUT", + [7] = "NEWCENTURY", + [8] = "BIOSWR", + [9] = "DMISCI", + [10] = "DMISMI", + [12] = "DMISERR", + [13] = "SLVSEL", + [16] = "INTRD_DET", + [17] = "SECOND_TO", + [18] = "BOOT", + [20] = "SMLINK_SLV" + }; + + *a = ARRAY_SIZE(tco_sts_bits); + return tco_sts_bits; +} + +/* + * GPE0 + */ +const char *const *soc_std_gpe_sts_array(size_t *a) +{ + static const char *const gpe_sts_bits[] = { + [1] = "HOTPLUG", + [2] = "SWGPE", + [6] = "TCO_SCI", + [7] = "SMB_WAK", + [9] = "PCI_EXP", + [10] = "BATLOW", + [11] = "PME", + [12] = "ME", + [13] = "PME_B0", + [14] = "eSPI", + [15] = "GPIO Tier-2", + [16] = "LAN_WAKE", + [18] = "WADT" + }; + + *a = ARRAY_SIZE(gpe_sts_bits); + return gpe_sts_bits; +} + +void pmc_set_disb(void) +{ + /* Set the DISB after DRAM init */ + uint8_t disb_val; + /* Only care about bits [23:16] of register GEN_PMCON_A */ + uint8_t *addr = (uint8_t *)(pmc_mmio_regs() + GEN_PMCON_A + 2); + + disb_val = read8(addr); + disb_val |= (DISB >> 16); + + /* Don't clear bits that are write-1-to-clear */ + disb_val &= ~((MS4V | SUS_PWR_FLR) >> 16); + write8(addr, disb_val); +} + +/* + * PMC controller gets hidden from PCI bus + * during FSP-Silicon init call. Hence PWRMBASE + * can't be accessible using PCI configuration space + * read/write. + */ +uint8_t *pmc_mmio_regs(void) +{ + return (void *)(uintptr_t)PCH_PWRM_BASE_ADDRESS; +} + +uintptr_t soc_read_pmc_base(void) +{ + return (uintptr_t)pmc_mmio_regs(); +} + +uint32_t *soc_pmc_etr_addr(void) +{ + return (uint32_t *)(soc_read_pmc_base() + ETR); +} + +void soc_get_gpi_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2) +{ + DEVTREE_CONST struct soc_intel_pantherlake_config *config; + + config = config_of_soc(); + if (config == NULL) { + printk(BIOS_ERR, "Configuration could not be retrieved.\n"); + return; + } + /* 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..c14c044 --- /dev/null +++ b/src/soc/intel/pantherlake/retimer.c @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/console.h> +#include <device/device.h> +#include <drivers/intel/usb4/retimer/retimer.h> +#include <intelblocks/tcss.h> + +int retimer_get_index_for_typec(uint8_t typec_port) +{ + 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), + }; + + for (int i = 0, ec_port = 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..ab1d0bc --- /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, /* Custom address for SNDW driver */ + .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..f7d751f --- /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_GSPI0: + return 1; + case PCI_DEVFN_GSPI1: + return 2; + case PCI_DEVFN_GSPI2: + return 3; + } + 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..b325e90 --- /dev/null +++ b/src/soc/intel/pantherlake/systemagent.c @@ -0,0 +1,211 @@ +/* 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 <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[] = { + { 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" }, + /* 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" }, + { 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 = sa_get_mmcfg_size(); + if (size > 0) + set_mmio_resource(&(cfg_rsrc[count++]), CONFIG_ECAM_MMCONF_BASE_ADDRESS, + size, "MMCONF"); + + /* DSM */ + size = sa_get_dsm_size(); + if (size > 0) { + base = pci_read_config32(dev, BDSM) & 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 = sa_get_gsm_size(); + if (size > 0) { + base = sa_get_gsm_base(); + set_mmio_resource(&(cfg_rsrc[count++]), base, size, "GSM"); + } + + /* DPR */ + size = sa_get_dpr_size(); + 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); +} + +static void configure_tdp(struct device *dev) +{ + struct soc_power_limits_config *soc_config; + struct device *sa; + uint16_t sa_pci_id; + u8 tdp; + size_t i; + bool config_tdp = false; + config_t *config; + + 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; + + if (sa_pci_id == 0xFFFF) { + printk(BIOS_WARNING, "Unknown SA PCI Device!\n"); + return; + } + + tdp = get_cpu_tdp(); + + /* + * Choose power limits configuration based on the CPU SA PCI ID and + * CPU TDP value. + */ + for (i = 0; i < ARRAY_SIZE(cpuid_to_ptl); i++) { + if (sa_pci_id == cpuid_to_ptl[i].cpu_id && + tdp == cpuid_to_ptl[i].cpu_tdp) { + soc_config = &config->power_limits_config[cpuid_to_ptl[i].limits]; + set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_config); + config_tdp = true; + printk(BIOS_DEBUG, "Configured power limits for SA PCI ID: 0x%4x\n", + sa_pci_id); + break; + } + } + + if (!config_tdp) { + printk(BIOS_WARNING, "Skipped power limits configuration for SA PCI ID: 0x%4x\n", + sa_pci_id); + return; + } +} + +/* + * SoC implementation + * + * Perform System Agent Initialization during ramstage phase. + */ +void soc_systemagent_init(struct device *dev) +{ + /* Enable Power Aware Interrupt Routing */ + enable_power_aware_intr(); + + /* Configure TDP */ + configure_tdp(dev); +} + +uint32_t soc_systemagent_max_chan_capacity_mib(u8 capid0_a_ddrsz) +{ + switch (capid0_a_ddrsz) { + case 1: + return 8192; + case 2: + return 4096; + case 3: + return 2048; + default: + return 65536; + } +} diff --git a/src/soc/intel/pantherlake/tcss.c b/src/soc/intel/pantherlake/tcss.c new file mode 100644 index 0000000..99cbdd2 --- /dev/null +++ b/src/soc/intel/pantherlake/tcss.c @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <intelblocks/tcss.h> +#include <soc/soc_chip.h> + +const struct soc_tcss_ops tcss_ops = { +/* TODO: Implement AUX BIAS PAD Programming if required */ + .configure_aux_bias_pads = NULL, + .valid_tbt_auth = NULL, +}; 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..ed265d8 --- /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 CONFIG_SOC_INTEL_USB2_DEV_MAX +#define XHCI_USB3_PORT_NUM CONFIG_SOC_INTEL_USB3_DEV_MAX + +#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; +}