Saurabh Mishra has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/81874?usp=email )
Change subject: soc/intel/lnl: Do initial Lunar Lake SoC commit till ramstage ......................................................................
soc/intel/lnl: Do initial Lunar Lake SoC commit till ramstage
List of changes: 1. Add required SoC programming till ramstage 2. Include only required headers into include/soc 3. Fill required FSP-S UPD to call FSP-S API
Change-Id: I979584002af13ee04cc8a37a2881118cdba554b7 Signed-off-by: Saurabh Mishra mishra.saurabh@intel.com --- A src/soc/intel/lnl_dev/acpi.c M src/soc/intel/lnl_dev/acpi/xhci.asl A src/soc/intel/lnl_dev/chip.c A src/soc/intel/lnl_dev/cpu.c A src/soc/intel/lnl_dev/crashlog.c A src/soc/intel/lnl_dev/dptf.c A src/soc/intel/lnl_dev/elog.c A src/soc/intel/lnl_dev/finalize.c A src/soc/intel/lnl_dev/gspi.c A src/soc/intel/lnl_dev/i2c.c A src/soc/intel/lnl_dev/include/soc/acpi.h A src/soc/intel/lnl_dev/include/soc/cpu.h A src/soc/intel/lnl_dev/include/soc/crashlog.h A src/soc/intel/lnl_dev/include/soc/elog.h A src/soc/intel/lnl_dev/include/soc/gpio.h A src/soc/intel/lnl_dev/include/soc/gpio_defs.h A src/soc/intel/lnl_dev/include/soc/irq.h A src/soc/intel/lnl_dev/include/soc/itss.h A src/soc/intel/lnl_dev/include/soc/me.h A src/soc/intel/lnl_dev/include/soc/nvs.h A src/soc/intel/lnl_dev/include/soc/pch.h M src/soc/intel/lnl_dev/include/soc/pci_devs.h A src/soc/intel/lnl_dev/include/soc/pcie.h A src/soc/intel/lnl_dev/include/soc/powerlimit.h A src/soc/intel/lnl_dev/include/soc/ramstage.h A src/soc/intel/lnl_dev/include/soc/serialio.h M src/soc/intel/lnl_dev/include/soc/soc_info.h A src/soc/intel/lnl_dev/include/soc/tcss.h A src/soc/intel/lnl_dev/include/soc/usb.h A src/soc/intel/lnl_dev/lockdown.c A src/soc/intel/lnl_dev/lunarlake/acpi.c A src/soc/intel/lnl_dev/lunarlake/chip.c A src/soc/intel/lnl_dev/lunarlake/cpu.c A src/soc/intel/lnl_dev/lunarlake/elog.c A src/soc/intel/lnl_dev/lunarlake/fsp_params.c A src/soc/intel/lnl_dev/lunarlake/gpio.c A src/soc/intel/lnl_dev/lunarlake/include/gpio_soc_defs.h A src/soc/intel/lnl_dev/lunarlake/include/gpio_std_defs.h A src/soc/intel/lnl_dev/lunarlake/pcie_rp.c A src/soc/intel/lnl_dev/lunarlake/systemagent.c A src/soc/intel/lnl_dev/me.c A src/soc/intel/lnl_dev/pmc.c A src/soc/intel/lnl_dev/pmutil.c A src/soc/intel/lnl_dev/retimer.c A src/soc/intel/lnl_dev/smihandler.c A src/soc/intel/lnl_dev/soc_info.c A src/soc/intel/lnl_dev/soundwire.c A src/soc/intel/lnl_dev/spi.c A src/soc/intel/lnl_dev/tcss.c A src/soc/intel/lnl_dev/uart.c A src/soc/intel/lnl_dev/xhci.c 51 files changed, 4,860 insertions(+), 52 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/74/81874/1
diff --git a/src/soc/intel/lnl_dev/acpi.c b/src/soc/intel/lnl_dev/acpi.c new file mode 100644 index 0000000..d175ea3 --- /dev/null +++ b/src/soc/intel/lnl_dev/acpi.c @@ -0,0 +1,247 @@ +/* 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 <device/mmio.h> +#include <arch/smp/mpspec.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci_ops.h> +#include <fw_config.h> +#include <intelblocks/cpulib.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/acpi.h> +#include <soc/cpu.h> +#include <soc/iomap.h> +#include <soc/nvs.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_chip.h> +#include <soc/systemagent.h> +#include <string.h> +#include <types.h> +#include <soc/acpi.h> + +/* + * List of supported C-states in this processor. + */ +enum { + C_STATE_C0, /* 0 */ + C_STATE_C1, /* 1 */ + C_STATE_C1E, /* 2 */ + C_STATE_C6_SHORT_LAT, /* 3 */ + C_STATE_C6_LONG_LAT, /* 4 */ + C_STATE_C7_SHORT_LAT, /* 5 */ + C_STATE_C7_LONG_LAT, /* 6 */ + C_STATE_C7S_SHORT_LAT, /* 7 */ + C_STATE_C7S_LONG_LAT, /* 8 */ + C_STATE_C8, /* 9 */ + C_STATE_C9, /* 10 */ + C_STATE_C10, /* 11 */ + NUM_C_STATES +}; + +static const acpi_cstate_t cstate_map[NUM_C_STATES] = { + [C_STATE_C0] = {}, + [C_STATE_C1] = { + .latency = C1_LATENCY, + .power = C1_POWER, + .resource = MWAIT_RES(0, 0), + }, + [C_STATE_C1E] = { + .latency = C1_LATENCY, + .power = C1_POWER, + .resource = MWAIT_RES(0, 1), + }, + [C_STATE_C6_SHORT_LAT] = { + .latency = C6_LATENCY, + .power = C6_POWER, + .resource = MWAIT_RES(2, 0), + }, + [C_STATE_C6_LONG_LAT] = { + .latency = C6_LATENCY, + .power = C6_POWER, + .resource = MWAIT_RES(2, 1), + }, + [C_STATE_C7_SHORT_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 0), + }, + [C_STATE_C7_LONG_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 1), + }, + [C_STATE_C7S_SHORT_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 2), + }, + [C_STATE_C7S_LONG_LAT] = { + .latency = C7_LATENCY, + .power = C7_POWER, + .resource = MWAIT_RES(3, 3), + }, + [C_STATE_C8] = { + .latency = C8_LATENCY, + .power = C8_POWER, + .resource = MWAIT_RES(4, 0), + }, + [C_STATE_C9] = { + .latency = C9_LATENCY, + .power = C9_POWER, + .resource = MWAIT_RES(5, 0), + }, + [C_STATE_C10] = { + .latency = C10_LATENCY, + .power = C10_POWER, + .resource = MWAIT_RES(6, 0), + }, +}; + +static int cstate_set_non_s0ix[] = { + C_STATE_C1, + C_STATE_C6_LONG_LAT, + C_STATE_C7S_LONG_LAT +}; + +static int cstate_set_s0ix[] = { + C_STATE_C1, + C_STATE_C7S_LONG_LAT, + C_STATE_C10 +}; + + +const acpi_cstate_t *soc_get_cstate_map(size_t *entries) +{ + static acpi_cstate_t map[MAX(ARRAY_SIZE(cstate_set_s0ix), + ARRAY_SIZE(cstate_set_non_s0ix))]; + int *set; + int i; + + config_t *config = config_of_soc(); + + int is_s0ix_enable = config->s0ix_enable; + + if (is_s0ix_enable) { + *entries = ARRAY_SIZE(cstate_set_s0ix); + set = cstate_set_s0ix; + } else { + *entries = ARRAY_SIZE(cstate_set_non_s0ix); + set = cstate_set_non_s0ix; + } + + for (i = 0; i < *entries; i++) { + map[i] = cstate_map[set[i]]; + map[i].ctype = i + 1; + } + return map; +} + +void soc_power_states_generation(int core_id, int cores_per_package) +{ + config_t *config = config_of_soc(); + + if (config->eist_enable) + /* Generate P-state tables */ + generate_p_state_entries(core_id, cores_per_package); +} + +void soc_fill_fadt(acpi_fadt_t *fadt) +{ + const uint16_t pmbase = ACPI_BASE_ADDRESS; + + config_t *config = config_of_soc(); + + fadt->pm_tmr_blk = pmbase + PM1_TMR; + fadt->pm_tmr_len = 4; + + fill_fadt_extended_pm_io(fadt); + + if (config->s0ix_enable) + fadt->flags |= ACPI_FADT_LOW_PWR_IDLE_S0; +} + +static struct min_sleep_state min_pci_sleep_states[] = { + { SA_DEVFN_ROOT, ACPI_DEVICE_SLEEP_D3 }, + { SA_DEVFN_IGD, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_IPU, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TBT0, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TBT1, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TBT2, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_TCSS_XHCI, ACPI_DEVICE_SLEEP_D3 }, + { SA_DEVFN_TCSS_DMA0, ACPI_DEVICE_SLEEP_D3 }, + { SA_DEVFN_TCSS_DMA1, ACPI_DEVICE_SLEEP_D3 }, + { PCI_DEVFN_VMD, 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_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); +} + +__attribute__((weak)) unsigned long soc_fill_dmar(unsigned long current) +{ + return 0; +} + +__attribute__((weak)) unsigned long sa_write_acpi_tables(const struct device *dev, unsigned long current, + struct acpi_rsdp *rsdp) +{ + return 0; +} + +void soc_fill_gnvs(struct global_nvs *gnvs) +{ + config_t *config = config_of_soc(); + + /* Enable DPTF based on mainboard configuration */ + gnvs->dpte = config->dptf_enable; + + /* Set USB2/USB3 wake enable bitmaps. */ + gnvs->u2we = config->usb2_wake_enable_bitmap; + gnvs->u3we = config->usb3_wake_enable_bitmap; +} + +int soc_madt_sci_irq_polarity(int sci) +{ + return MP_IRQ_POLARITY_HIGH; +} diff --git a/src/soc/intel/lnl_dev/acpi/xhci.asl b/src/soc/intel/lnl_dev/acpi/xhci.asl index dda4878..20334c6 100644 --- a/src/soc/intel/lnl_dev/acpi/xhci.asl +++ b/src/soc/intel/lnl_dev/acpi/xhci.asl @@ -17,17 +17,13 @@ Method (_PS0, 0, Serialized) { /* Disable Clock Gating */ -#if CONFIG(SOC_INTEL_LUNARLAKE) ^^PCRA (PID_XHCI, 0x0, ~(1 << 3)) -#endif }
Method (_PS3, 0, Serialized) { /* Enable Clock Gating */ -#if CONFIG(SOC_INTEL_LUNARLAKE) ^^PCRO (PID_XHCI, 0x0, 1 << 3) -#endif }
/* Root Hub for Lunarlake */ diff --git a/src/soc/intel/lnl_dev/chip.c b/src/soc/intel/lnl_dev/chip.c new file mode 100644 index 0000000..4c2ae54 --- /dev/null +++ b/src/soc/intel/lnl_dev/chip.c @@ -0,0 +1,153 @@ +/* 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/gpio.h> +#include <intelblocks/itss.h> +#include <intelblocks/p2sb.h> +#include <intelblocks/pcie_rp.h> +#include <intelblocks/systemagent.h> +#include <intelblocks/tcss.h> +#include <intelblocks/xdci.h> +#include <soc/intel/common/reset.h> +#include <soc/intel/common/vbt.h> +#include <soc/iomap.h> +#include <soc/itss.h> +#include <soc/p2sb.h> +#include <soc/pci_devs.h> +#include <soc/pcie.h> +#include <soc/ramstage.h> +#include <soc/soc_chip.h> +#include <soc/tcss.h> + +#if CONFIG(HAVE_ACPI_TABLES) +__attribute__((weak)) const char *soc_acpi_name(const struct device *dev) +{ + return printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} +#endif + +/* SoC routine to fill GPIO PM mask and value for GPIO_MISCCFG register */ +static void soc_fill_gpio_pm_configuration(void) +{ + uint8_t value[TOTAL_GPIO_COMM]; + const config_t *config = config_of_soc(); + + if (config->gpio_override_pm) + memcpy(value, config->gpio_pm, sizeof(value)); + else + memset(value, MISCCFG_GPIO_PM_CONFIG_BITS, sizeof(value)); + + gpio_pm_configure(value, TOTAL_GPIO_COMM); +} + +void soc_init_pre_device(void *chip_info) +{ + /* Perform silicon specific init. */ + fsp_silicon_init(); + + /* Display FIRMWARE_VERSION_INFO_HOB */ + fsp_display_fvi_version_hob(); + + soc_fill_gpio_pm_configuration(); + + /* Swap enabled PCI ports in device tree if needed. */ + pcie_rp_update_devicetree(get_pcie_rp_table()); + + /* + * 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 +}; + +void soc_enable(struct device *dev) +{ + /* + * Set the operations if it is a special bus type or a hidden PCI + * device. + */ + if (dev->path.type == DEVICE_PATH_DOMAIN) + dev->ops = &pci_domain_ops; + else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) + dev->ops = &cpu_bus_ops; + else if (dev->path.type == DEVICE_PATH_PCI && + dev->path.pci.devfn == PCI_DEVFN_PMC) + dev->ops = &pmc_ops; + else if (dev->path.type == DEVICE_PATH_PCI && + dev->path.pci.devfn == PCI_DEVFN_P2SB) + dev->ops = &soc_p2sb_ops; + else if (dev->path.type == DEVICE_PATH_GPIO) + block_gpio_enable(dev); +} + +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); +} + +__attribute__((weak)) struct chip_operations soc_intel_lnl_dev_ops = { + .name = "", + .enable_dev = NULL, + .init = NULL, + .final = NULL, +}; diff --git a/src/soc/intel/lnl_dev/cpu.c b/src/soc/intel/lnl_dev/cpu.c new file mode 100644 index 0000000..8295751 --- /dev/null +++ b/src/soc/intel/lnl_dev/cpu.c @@ -0,0 +1,180 @@ +/* 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> +#include <assert.h> + +bool cpu_soc_is_in_untrusted_mode(void) +{ + msr_t msr; + + msr = rdmsr(MSR_BIOS_DONE); + return !!(msr.lo & ENABLE_IA_UNTRUSTED); +} + +void cpu_soc_bios_done(void) +{ + msr_t msr; + + msr = rdmsr(MSR_BIOS_DONE); + msr.lo |= ENABLE_IA_UNTRUSTED; + wrmsr(MSR_BIOS_DONE, msr); +} + +__attribute__((weak)) uint8_t get_supported_lpm_mask(void) +{ + return 0; +} + +static void soc_fsp_load(void) +{ + fsps_load(); +} + +static void configure_misc(void) +{ + msr_t msr; + + config_t *conf = (config_t *)config_of_soc(); + + msr = rdmsr(IA32_MISC_ENABLE); + msr.lo |= (1 << 0); /* Fast String enable */ + msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ + wrmsr(IA32_MISC_ENABLE, msr); + + /* Set EIST status */ + cpu_set_eist(conf->eist_enable); + + /* Disable Thermal interrupts */ + msr.lo = 0; + msr.hi = 0; + wrmsr(IA32_THERM_INTERRUPT, msr); + + /* Enable package critical interrupt only */ + msr.lo = 1 << 4; + msr.hi = 0; + wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr); + + /* Enable PROCHOT and Power Performance Platform Override */ + msr = rdmsr(MSR_POWER_CTL); + msr.lo |= (1 << 0); /* Enable Bi-directional PROCHOT as an input*/ + msr.lo |= (1 << 23); /* Lock it */ + msr.lo |= (1 << 18); /* Power Performance Platform Override */ + wrmsr(MSR_POWER_CTL, msr); +} + +enum core_type get_soc_cpu_type(void) +{ + if (cpu_is_hybrid_supported()) + return cpu_get_cpu_type(); + else + return CPUID_CORE_TYPE_INTEL_CORE; +} + +bool soc_is_nominal_freq_supported(void) +{ + return true; +} + +static void enable_x2apic(void) +{ + if (!CONFIG(X2APIC_LATE_WORKAROUND)) + return; + + enable_lapic_mode(true); +} + +/* All CPUs including BSP will run the following function. */ +void soc_core_init(struct device *cpu) +{ + /* Clear out pending MCEs */ + /* TODO(adurbin): This should only be done on a cold boot. Also, some + * of these banks are core vs package scope. For now every CPU clears + * every bank. */ + mca_configure(); + + enable_x2apic(); + + enable_lapic_tpr(); + + /* Configure Enhanced SpeedStep and Thermal Sensors */ + configure_misc(); + + enable_pm_timer_emulation(); + + /* Enable Direct Cache Access */ + configure_dca_cap(); + + /* Set energy policy */ + set_energy_perf_bias(ENERGY_POLICY_NORMAL); + + /* Enable Turbo */ + enable_turbo(); + + if (CONFIG(INTEL_TME) && is_tme_supported()) + set_tme_core_activate(); +} + +static void per_cpu_smm_trigger(void) +{ + /* Relocate the SMM handler. */ + smm_relocate(); +} + +static void post_mp_init(void) +{ + /* Set Max Ratio */ + cpu_set_max_ratio(); + + /* + * 1. Now that all APs have been relocated as well as the BSP let SMIs + * start flowing. + * 2. Skip enabling power button SMI and enable it after BS_CHIPS_INIT + * to avoid shutdown hang due to lack of init on certain IP in FSP-S. + */ + global_smi_enable_no_pwrbtn(); +} + +static const struct mp_ops mp_ops = { + /* + * Skip Pre MP init MTRR programming as MTRRs are mirrored from BSP, + * that are set prior to ramstage. + * Real MTRRs programming are being done after resource allocation. + */ + .pre_mp_init = soc_fsp_load, + .get_cpu_count = get_cpu_count, + .get_smm_info = smm_info, + .get_microcode_info = get_microcode_info, + .pre_mp_smm_init = smm_initialize, + .per_cpu_smm_trigger = per_cpu_smm_trigger, + .relocation_handler = smm_relocation_handler, + .post_mp_init = post_mp_init, +}; + +void mp_init_cpus(struct bus *cpu_bus) +{ + if (mp_init_with_smm(cpu_bus, &mp_ops)) + printk(BIOS_ERR, "MP initialization failure.\n"); + + /* Thermal throttle activation offset */ + configure_tcc_thermal_target(); +} diff --git a/src/soc/intel/lnl_dev/crashlog.c b/src/soc/intel/lnl_dev/crashlog.c new file mode 100644 index 0000000..3c5f5bd --- /dev/null +++ b/src/soc/intel/lnl_dev/crashlog.c @@ -0,0 +1,522 @@ +/* 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 <arch/bert_storage.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <string.h> + +#define CONTROL_INTERFACE_OFFSET 0x5 +#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_crashLog_support; +static bool m_pmc_crashLog_present; +static bool m_cpu_crashLog_support; +static bool m_cpu_crashLog_present; +static u32 m_pmc_crashLog_size; +static u32 m_cpu_crashLog_size; +static u32 cpu_crash_version; +static pmc_ipc_discovery_buf_t discovery_buf; +static pmc_crashlog_desc_table_t descriptor_table; +static tel_crashlog_devsc_cap_t cpu_cl_devsc_cap; +static cpu_crashlog_discovery_table_t cpu_cl_disc_tab; +static u32 disc_tab_addr; + +static u64 get_disc_tab_header(void) +{ + return read64((void *)disc_tab_addr); +} + +/* Get the SRAM BAR. */ +static uintptr_t get_sram_bar(pci_devfn_t sram_devfn) +{ + uintptr_t sram_bar; + const struct device *dev; + struct resource *res; + + dev = pcidev_path_on_root(sram_devfn); + if (!dev) { + printk(BIOS_ERR, "device: 0x%x not found!\n", sram_devfn); + return 0; + } + + res = probe_resource(dev, PCI_BASE_ADDRESS_0); + if (!res) { + printk(BIOS_ERR, "SOC SRAM device not found!\n"); + return 0; + } + + /* Get the base address of the resource */ + sram_bar = res->base; + + return sram_bar; +} + +static void configure_sram(const struct device *sram_dev, u32 base_addr) +{ + pci_update_config16(sram_dev, PCI_COMMAND, ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY), 0); + + /* Program BAR 0 and enable command register memory space decoding */ + pci_write_config32(sram_dev, PCI_BASE_ADDRESS_0, base_addr); + pci_or_config16(sram_dev, PCI_COMMAND, PCI_COMMAND_MEMORY); +} + +void cl_get_pmc_sram_data(cl_node_t *head) +{ + u32 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++) { + u32 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) +{ + u32 bar_addr = 0, desc_table_addr = 0; + + const struct pmc_ipc_buffer req = { 0 }; + struct pmc_ipc_buffer res; + uint32_t cmd_reg; + int r; + + cmd_reg = pmc_make_ipc_cmd(PMC_IPC_CMD_CRASHLOG, + PMC_IPC_CMD_ID_CRASHLOG_DISCOVERY, + PMC_IPC_CMD_SIZE_SHIFT); + printk(BIOS_DEBUG, "cmd_reg from pmc_make_ipc_cmd %d in %s\n", cmd_reg, __func__); + + r = pmc_send_ipc_cmd(cmd_reg, &req, &res); + + if (r < 0) { + printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__); + return false; + } + discovery_buf.conv_val_64_bits = ((u64)res.buf[1] << 32) | res.buf[0]; + + if ((discovery_buf.conv_bits64.supported != 1) || + (discovery_buf.conv_bits64.discov_mechanism == 0) || + (discovery_buf.conv_bits64.crash_dis_sts == 1)) { + printk(BIOS_INFO, "PCH crashlog feature not supported.\n"); + m_pmc_crashLog_support = false; + m_pmc_crashLog_size = 0; + printk(BIOS_DEBUG, "discovery_buf supported: %d, mechanism: %d, CrashDisSts: %d\n", + discovery_buf.conv_bits64.supported, + discovery_buf.conv_bits64.discov_mechanism, + discovery_buf.conv_bits64.crash_dis_sts); + return false; + } + + printk(BIOS_INFO, "PMC crashlog feature is supported.\n"); + m_pmc_crashLog_support = true; + + /* Program BAR 0 and enable command register memory space decoding */ + bar_addr = get_sram_bar(PCI_DEVFN_SRAM); + if (bar_addr == 0) { + printk(BIOS_ERR, "PCH SRAM not available, crashlog feature can't be enabled.\n"); + return false; + } + + configure_sram(PCI_DEV_SRAM, bar_addr); + + desc_table_addr = bar_addr + discovery_buf.conv_bits64.desc_tabl_offset; + m_pmc_crashLog_size = pmc_cl_gen_descriptor_table(desc_table_addr, + &descriptor_table); + printk(BIOS_DEBUG, "PMC CrashLog size in discovery mode: 0x%X\n", + m_pmc_crashLog_size); + m_pmc_crashLog_present = m_pmc_crashLog_size > 0; + + return true; +} + +u32 cl_get_cpu_bar_addr(void) +{ + u32 base_addr = 0; + if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR0) { + base_addr = pci_read_config32(PCI_DEV_TELEMETRY, PCI_BASE_ADDRESS_0) & + ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + } else if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR1) { + base_addr = pci_read_config32(PCI_DEV_TELEMETRY, PCI_BASE_ADDRESS_1) & + ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + } else { + printk(BIOS_ERR, "Invalid TEL_CFG_BAR value %d, discovery failure expected.\n", + cpu_cl_devsc_cap.discovery_data.fields.t_bir_q); + } + + return base_addr; +} + +u32 cl_get_cpu_tmp_bar(void) +{ + return get_sram_bar(PCI_DEVFN_SRAM); +} + +bool cl_pmc_sram_has_mmio_access(void) +{ + if (pci_read_config16(PCI_DEV_SRAM, PCI_VENDOR_ID) == 0xFFFF) { + printk(BIOS_ERR, "PMC SSRAM PCI device disabled. Can be enabled in device tree.\n"); + return false; + } + + return true; +} + +static bool cpu_cl_get_capability(tel_crashlog_devsc_cap_t *cl_devsc_cap) +{ + cl_devsc_cap->cap_data.data = pci_read_config32(PCI_DEV_TELEMETRY, + TEL_DVSEC_OFFSET + TEL_DVSEC_PCIE_CAP_ID); + if (cl_devsc_cap->cap_data.fields.pcie_cap_id != TELEMETRY_EXTENDED_CAP_ID) { + printk(BIOS_DEBUG, "Read ID for Telemetry: 0x%x differs from expected: 0x%x\n", + cl_devsc_cap->cap_data.fields.pcie_cap_id, TELEMETRY_EXTENDED_CAP_ID); + return false; + } + + /* walk through the entries until crashLog entry */ + cl_devsc_cap->devsc_data.data_32[1] = pci_read_config32(PCI_DEV_TELEMETRY, TEL_DVSEV_ID); + int new_offset = 0; + while (cl_devsc_cap->devsc_data.fields.devsc_id != CRASHLOG_DVSEC_ID) { + if (cl_devsc_cap->cap_data.fields.next_cap_offset == 0 + || cl_devsc_cap->cap_data.fields.next_cap_offset == 0xFFFF) { + printk(BIOS_DEBUG, "Read invalid pcie_cap_id value: 0x%x\n", + cl_devsc_cap->cap_data.fields.pcie_cap_id); + return false; + } + new_offset = cl_devsc_cap->cap_data.fields.next_cap_offset; + cl_devsc_cap->cap_data.data = pci_read_config32(PCI_DEV_TELEMETRY, + new_offset + TEL_DVSEC_PCIE_CAP_ID); + cl_devsc_cap->devsc_data.data_32[1] = pci_read_config32(PCI_DEV_TELEMETRY, + new_offset + TEL_DVSEV_ID); + } + cpu_crash_version = cl_devsc_cap->devsc_data.fields.devsc_ver; + + cl_devsc_cap->discovery_data.data = pci_read_config32(PCI_DEV_TELEMETRY, new_offset + + TEL_DVSEV_DISCOVERY_TABLE_OFFSET); + + return true; +} + +static u32 get_disc_table_offset(void) +{ + u32 offset = cpu_cl_devsc_cap.discovery_data.fields.discovery_table_offset; + if (cpu_get_cpuid() >= CPUID_METEORLAKE_B0) { + offset <<= 3; + printk(BIOS_DEBUG, "adjusted cpu discovery table offset: 0x%x\n", 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) +{ + u32 bar_addr = cl_get_cpu_bar_addr(); + + if (!bar_addr) + return false; + + disc_tab_addr = bar_addr + get_disc_table_offset(); + + u32 dw0 = read32((u32 *)disc_tab_addr); + if (!is_crashlog_data_valid(dw0)) + return false; + + memset(&cpu_cl_disc_tab, 0, sizeof(cpu_crashlog_discovery_table_t)); + cpu_cl_disc_tab.header.data = get_disc_tab_header(); + printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer count: 0x%x\n", + cpu_cl_disc_tab.header.fields.count); + + int cur_offset = 0; + for (int i = 0; i < cpu_cl_disc_tab.header.fields.count; i++) { + cur_offset = 8 + 24 * i; + + dw0 = read32((u32 *)disc_tab_addr + cur_offset); + if (!is_crashlog_data_valid(dw0)) + continue; + + 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 = read64((void *)(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_crashLog_size += cpu_cl_disc_tab.buffers[i].fields.size * sizeof(u32); + } + + if (m_cpu_crashLog_size > 0) + m_cpu_crashLog_present = true; + else + m_cpu_crashLog_present = false; + + return true; +} + +bool cpu_cl_discovery(void) +{ + memset(&cpu_cl_devsc_cap, 0, sizeof(tel_crashlog_devsc_cap_t)); + + if (!cpu_cl_get_capability(&cpu_cl_devsc_cap)) { + printk(BIOS_ERR, "CPU crashlog capability not found.\n"); + m_cpu_crashLog_support = false; + return false; + } + + m_cpu_crashLog_support = true; + + if (!cpu_cl_gen_discovery_table()) { + printk(BIOS_ERR, "CPU crashlog discovery table not valid.\n"); + m_cpu_crashLog_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_crashLog_size, m_cpu_crashLog_size); + return m_pmc_crashLog_size + m_cpu_crashLog_size; +} + +static u32 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) +{ + u32 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; + write32((u32 *)(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 */ + u32 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; + write32((u32 *)(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_crashLog_size; +} + +int cl_get_cpu_record_size(void) +{ + return m_cpu_crashLog_size; +} + +bool cl_cpu_data_present(void) +{ + return m_cpu_crashLog_present; +} + +bool cl_pmc_data_present(void) +{ + return m_pmc_crashLog_present; +} + +bool cpu_crashlog_support(void) +{ + return m_cpu_crashLog_support; +} + +bool pmc_crashlog_support(void) +{ + return m_pmc_crashLog_support; +} + +void update_new_pmc_crashlog_size(u32 *pmc_crash_size) +{ + m_pmc_crashLog_size = *pmc_crash_size; +} + +cpu_crashlog_discovery_table_t cl_get_cpu_discovery_table(void) +{ + return cpu_cl_disc_tab; +} + +void update_new_cpu_crashlog_size(u32 *cpu_crash_size) +{ + m_cpu_crashLog_size = *cpu_crash_size; +} diff --git a/src/soc/intel/lnl_dev/dptf.c b/src/soc/intel/lnl_dev/dptf.c new file mode 100644 index 0000000..9383843 --- /dev/null +++ b/src/soc/intel/lnl_dev/dptf.c @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <drivers/intel/dptf/dptf.h> + +/* UPDATEME: HID need to checked for LNL */ +static const struct dptf_platform_info dptf_platform_info = { + .use_eisa_hids = false, + /* _HID for the toplevel DPTF device, typically _SB.DPTF */ + .dptf_device_hid = "INTC1041", + /* _HID for Intel DPTF Generic Device (these require PTYP as well) */ + .generic_hid = "INTC1046", + /* _HID for Intel DPTF Fan Device */ + .fan_hid = "INTC1048", +}; + +const struct dptf_platform_info *get_dptf_platform_info(void) +{ + return &dptf_platform_info; +} diff --git a/src/soc/intel/lnl_dev/elog.c b/src/soc/intel/lnl_dev/elog.c new file mode 100644 index 0000000..aafde3f --- /dev/null +++ b/src/soc/intel/lnl_dev/elog.c @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <console/console.h> +#include <device/pci_ops.h> +#include <elog.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/xhci.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_info.h> +#include <stdint.h> +#include <types.h> +#include <soc/elog.h> + +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); + } +} + +__attribute__((weak)) void pch_log_rp_wake_source(void) +{ +} + +__attribute__((weak)) void pch_log_pme_internal_wake_source(void) +{ +} + +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/lnl_dev/finalize.c b/src/soc/intel/lnl_dev/finalize.c new file mode 100644 index 0000000..f1eb5aa --- /dev/null +++ b/src/soc/intel/lnl_dev/finalize.c @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/io.h> +#include <device/mmio.h> +#include <bootstate.h> +#include <console/console.h> +#include <cpu/x86/smm.h> +#include <delay.h> +#include <device/pci.h> +#include <intelblocks/cse.h> +#include <intelblocks/lpc_lib.h> +#include <intelblocks/pcr.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/systemagent.h> +#include <intelblocks/tco.h> +#include <intelblocks/thermal.h> +#include <spi-generic.h> +#include <intelpch/lockdown.h> +#include <soc/p2sb.h> +#include <soc/pci_devs.h> +#include <soc/pcr_ids.h> +#include <soc/pm.h> +#include <soc/smbus.h> +#include <soc/soc_chip.h> +#include <soc/systemagent.h> +#include <timer.h> + +static void pch_handle_sideband(config_t *config) +{ + +} + +static void pch_finalize(void) +{ + config_t *config = config_of_soc(); + + /* TCO Lock down */ + tco_lockdown(); + + /* TODO: Add Thermal Configuration */ + + pch_handle_sideband(config); + + pmc_clear_pmcon_sts(); +} + +static void tbt_finalize(void) +{ + int i; + const struct device *dev; + + /* Disable Thunderbolt PCIe root ports bus master */ + for (i = 0; i < NUM_TBT_FUNCTIONS; i++) { + dev = pcidev_path_on_root(PCI_DEVFN_TBT(i)); + if (dev) + pci_dev_disable_bus_master(dev); + } +} + +static void sa_finalize(void) +{ + if (get_lockdown_config() == CHIPSET_LOCKDOWN_COREBOOT) + sa_lock_pam(); +} + +static void 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/lnl_dev/gspi.c b/src/soc/intel/lnl_dev/gspi.c new file mode 100644 index 0000000..2a34ab6 --- /dev/null +++ b/src/soc/intel/lnl_dev/gspi.c @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <intelblocks/gspi.h> +#include <soc/pci_devs.h> + +int gspi_soc_bus_to_devfn(unsigned int gspi_bus) +{ + switch (gspi_bus) { + case 0: + return PCI_DEVFN_GSPI0; + case 1: + return PCI_DEVFN_GSPI1; + } + return -1; +} diff --git a/src/soc/intel/lnl_dev/i2c.c b/src/soc/intel/lnl_dev/i2c.c new file mode 100644 index 0000000..50ab4a7 --- /dev/null +++ b/src/soc/intel/lnl_dev/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/lnl_dev/include/soc/acpi.h b/src/soc/intel/lnl_dev/include/soc/acpi.h new file mode 100644 index 0000000..02c83fb --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/acpi.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_ACPI_H_ +#define _SOC_INTEL_LNL_ACPI_H_ + +unsigned long soc_fill_dmar(unsigned long current); + +#endif /* _SOC_INTEL_LNL_ACPI_H_ */ diff --git a/src/soc/intel/lnl_dev/include/soc/cpu.h b/src/soc/intel/lnl_dev/include/soc/cpu.h new file mode 100644 index 0000000..c2d1bb8 --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/cpu.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_CPU_H_ +#define _SOC_INTEL_LNL_CPU_H_ + +/* Latency times in us */ +#define C1_LATENCY 1 +#define C6_LATENCY 127 +#define C7_LATENCY 253 +#define C8_LATENCY 260 +#define C9_LATENCY 487 +#define C10_LATENCY 1048 + +/* Power in units of mW */ +#define C1_POWER 0x3e8 +#define C6_POWER 0x15e +#define C7_POWER 0xc8 +#define C8_POWER 0xc8 +#define C9_POWER 0xc8 +#define C10_POWER 0xc8 + +/* Get a bitmask of supported LPM states */ +uint8_t get_supported_lpm_mask(void); + +#endif //_SOC_INTEL_LNL_CPU_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/crashlog.h b/src/soc/intel/lnl_dev/include/soc/crashlog.h new file mode 100644 index 0000000..94e57ab --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/crashlog.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_CRASHLOG_H_ +#define _SOC_INTEL_LNL_CRASHLOB_H_ + +#include <types.h> + + +/* DVSEC capability Registers */ +#define TEL_DVSEC_OFFSET 0x100 +#define TEL_DVSEC_PCIE_CAP_ID 0x0 +#define TEL_DVSEC_NEXT_CAP 0x2 +#define TEL_DVSEV_ID 0x8 +#define TEL_DVSEV_DISCOVERY_TABLE_OFFSET 0xC +#define TELEMETRY_EXTENDED_CAP_ID 0x23 +#define CRASHLOG_DVSEC_ID 0x04 +#define TEL_DVSEC_TBIR_BAR0 0 +#define TEL_DVSEC_TBIR_BAR1 1 + +/* CPU CrashLog MMIO Registers */ +#define CRASHLOG_MAILBOX_INTF_ADDRESS 0x6038 +#define CRASHLOG_POINTER_SIZE_FIELD_OFFSET 0x04 + +#endif /* _SOC_INTEL_LNL_CRASHLOG_H_ */ diff --git a/src/soc/intel/lnl_dev/include/soc/elog.h b/src/soc/intel/lnl_dev/include/soc/elog.h new file mode 100644 index 0000000..05f068d --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/elog.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_ELOG_H_ +#define _SOC_INTEL_LNL_ELOG_H_ + +struct pme_map { + unsigned int devfn; + unsigned int wake_source; +}; + +void pch_log_rp_wake_source(void); +void pch_log_pme_internal_wake_source(void); + + +#endif /* _SOC_INTEL_LNL_ELOG_H_ */ diff --git a/src/soc/intel/lnl_dev/include/soc/gpio.h b/src/soc/intel/lnl_dev/include/soc/gpio.h new file mode 100644 index 0000000..a7107dd --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/gpio.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_GPIO_H_ +#define _SOC_INTEL_LNL_GPIO_H_ + +#include <soc/gpio_defs.h> +#include <intelblocks/gpio.h> +#include <platform_soc_defs.h> + +/* Enable GPIO community power management configuration */ +#define MISCCFG_GPIO_PM_CONFIG_BITS (MISCCFG_GPVNNREQEN | \ + MISCCFG_GPPGCBDPCGEN | MISCCFG_GPSIDEDPCGEN | \ + MISCCFG_GPRCOMPCDLCGEN | MISCCFG_GPRTCDLCGEN | MISCCFG_GSXSLCGEN \ + | MISCCFG_GPDPCGEN | MISCCFG_GPDLCGEN) + +#endif //_SOC_INTEL_LNL_GPIO_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/gpio_defs.h b/src/soc/intel/lnl_dev/include/soc/gpio_defs.h new file mode 100644 index 0000000..74c0b64 --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/gpio_defs.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_GPIO_DEFS_H_ +#define _SOC_INTEL_LNL_GPIO_DEFS_H_ + +#ifndef __ACPI__ +#include <stddef.h> +#endif + +#include <gpio_std_defs.h> +#include <gpio_soc_defs.h> + +#endif //_SOC_INTEL_LNL_DEFS_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/irq.h b/src/soc/intel/lnl_dev/include/soc/irq.h new file mode 100644 index 0000000..c59628f --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/irq.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_IRQ_H_ +#define _SOC_INTEL_LNL_IRQ_H_ + +#define GPIO_IRQ14 14 +#define GPIO_IRQ15 15 + +#define PCH_IRQ10 10 +#define PCH_IRQ11 11 + +#define LPSS_UART0_IRQ 16 +#define LPSS_UART1_IRQ 17 +#define LPSS_UART2_IRQ 31 + +#endif //_SOC_INTEL_LNL_IRQ_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/itss.h b/src/soc/intel/lnl_dev/include/soc/itss.h new file mode 100644 index 0000000..2ef79ce --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/itss.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_ITSS_H +#define _SOC_INTEL_LNL_ITSS_H + +#define GPIO_IRQ_START 50 +#define GPIO_IRQ_END ITSS_MAX_IRQ + +#define ITSS_MAX_IRQ 119 +#define IRQS_PER_IPC 32 +#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1)/IRQS_PER_IPC) + +#endif /* _SOC_INTEL_LNL_ITSS_H */ diff --git a/src/soc/intel/lnl_dev/include/soc/me.h b/src/soc/intel/lnl_dev/include/soc/me.h new file mode 100644 index 0000000..e3ec5d5 --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/me.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_ME_H_ +#define _SOC_INTEL_LNL_ME_H_ + +#include <stdint.h> + +/* ME Host Firmware Status register 1 */ +union me_hfsts1 { + u32 data; + struct { + u32 working_state: 4; + u32 mfg_mode: 1; + u32 fpt_bad: 1; + u32 operation_state: 3; + u32 fw_init_complete: 1; + u32 ft_bup_ld_flr: 1; + u32 update_in_progress: 1; + u32 error_code: 4; + u32 operation_mode: 4; + u32 reset_count: 4; + u32 boot_options_present: 1; + u32 invoke_enhance_dbg_mode: 1; + u32 bist_test_state: 1; + u32 bist_reset_request: 1; + u32 current_power_source: 2; + u32 reserved: 1; + u32 d0i3_support_valid: 1; + } __packed fields; +}; + +/* ME Host Firmware Status Register 3 */ +union me_hfsts3 { + u32 data; + struct { + u32 reserved_0: 4; + u32 fw_sku: 3; + u32 reserved_7: 2; + u32 reserved_9: 2; + u32 resered_11: 3; + u32 resered_14: 16; + u32 reserved_30: 2; + } __packed fields; +}; +#endif //_SOC_INTEL_LNL_ME_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/nvs.h b/src/soc/intel/lnl_dev/include/soc/nvs.h new file mode 100644 index 0000000..33e522a --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/nvs.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_NVS_H_ +#define _SOC_INTEL_LNL_NVS_H_ + +#include <intelblocks/nvs.h> + +#endif //_SOC_INTEL_LNL_NVS_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/pch.h b/src/soc/intel/lnl_dev/include/soc/pch.h new file mode 100644 index 0000000..d16e4cf --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/pch.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_PCH_H_ +#define _SOC_INTEL_LNL_PCH_H_ + +#include <platform_soc_defs.h> + +#define PCR_PSFX_TO_SHDW_BAR0 0 +#define PCR_PSFX_TO_SHDW_BAR1 0x4 +#define PCR_PSFX_TO_SHDW_BAR2 0x8 +#define PCR_PSFX_TO_SHDW_BAR3 0xC +#define PCR_PSFX_TO_SHDW_BAR4 0x10 +#define PCR_PSFX_TO_SHDW_PCIEN_IOEN 0x01 +#define PCR_PSFX_T0_SHDW_PCIEN 0x1C + +#define PCR_DMI_ACPIBA 0x27B4 +#define PCR_DMI_ACPIBDID 0x27B8 +#define PCR_DMI_PMBASEA 0x27AC +#define PCR_DMI_PMBASEC 0x27B0 + + +#endif /* _SOC_INTEL_LNL_PCH_H_ */ diff --git a/src/soc/intel/lnl_dev/include/soc/pci_devs.h b/src/soc/intel/lnl_dev/include/soc/pci_devs.h index 80ee26a..00fe611 100644 --- a/src/soc/intel/lnl_dev/include/soc/pci_devs.h +++ b/src/soc/intel/lnl_dev/include/soc/pci_devs.h @@ -34,14 +34,7 @@
#define PCI_DEV_SLOT_TBT 0x07 #define PCI_DEVFN_TBT(x) _PCI_DEVFN(TBT, (x)) -#if CONFIG(SOC_INTEL_LUNARLAKE) #define NUM_TBT_FUNCTIONS 3 -#endif -#if CONFIG(SOC_INTEL_PANTHERLAKE) -#define NUM_TBT_FUNCTIONS 4 -#define PCI_DEVFN_TBT3 _PCI_DEVFN(TBT, 3) -#define PCI_DEV_TBT3 _PCI_DEV(TBT, 3) -#endif #define PCI_DEVFN_TBT0 _PCI_DEVFN(TBT, 0) #define PCI_DEVFN_TBT1 _PCI_DEVFN(TBT, 1) #define PCI_DEVFN_TBT2 _PCI_DEVFN(TBT, 2) @@ -53,20 +46,10 @@ #define PCI_DEVFN_NPU _PCI_DEVFN(NPU, 0) #define PCI_DEV_NPU _PCI_DEV(NPU, 0)
-#if CONFIG(SOC_INTEL_PANTHERLAKE) -#define PCI_DEV_SLOT_IAA 0xc -#define PCI_DEVFN_IAA _PCI_DEVFN(IAA, 0) -#define PCI_DEV_IAA _PCI_DEV(IAA, 0) -#endif - #define PCI_DEV_SLOT_TCSS 0x0d #define NUM_TCSS_DMA_FUNCTIONS 2 #define PCI_DEVFN_TCSS_DMA(x) _PCI_DEVFN(TCSS, ((x) + 2)) #define PCI_DEVFN_TCSS_XHCI _PCI_DEVFN(TCSS, 0) -#if CONFIG(SOC_INTEL_PANTHERLAKE) -#define PCI_DEVFN_TCSS_XDCI _PCI_DEVFN(TCSS, 1) -#define PCI_DEV_TCSS_XDCI _PCI_DEV(TCSS, 1) -#endif #define PCI_DEVFN_TCSS_DMA0 _PCI_DEVFN(TCSS, 2) #define PCI_DEVFN_TCSS_DMA1 _PCI_DEVFN(TCSS, 3) #define PCI_DEV_TCSS_XHCI _PCI_DEV(TCSS, 0) @@ -92,12 +75,10 @@ #define PCI_DEV_SLOT_ISH 0x12 #define PCI_DEVFN_ISH _PCI_DEVFN(ISH, 0) #define PCI_DEVFN_P2SB2 _PCI_DEVFN(ISH, 1) -#if CONFIG(SOC_INTEL_LUNARLAKE) #define PCI_DEVFN_GSPI2 _PCI_DEVFN(ISH, 6) #define PCI_DEVFN_UFS _PCI_DEVFN(ISH, 7) #define PCI_DEV_GSPI2 _PCI_DEV(ISH, 6) #define PCI_DEV_UFS _PCI_DEV(ISH, 7) -#endif #define PCI_DEV_ISH _PCI_DEV(ISH, 0) #define PCI_DEV_P2SB2 _PCI_DEV(ISH, 1)
@@ -114,12 +95,6 @@ #define PCI_DEVFN_USBOTG _PCI_DEVFN(XHCI, 1) #define PCI_DEVFN_SRAM _PCI_DEVFN(XHCI, 2) #define PCI_DEVFN_CNVI_WIFI _PCI_DEVFN(XHCI, 3) -#if CONFIG(SOC_INTEL_PANTHERLAKE) -#define PCI_DEVFN_IEH _PCI_DEVFN(XHCI, 5) -#define PCI_DEVFN_CNVI_BT _PCI_DEVFN(XHCI, 7) -#define PCI_DEV_IEH _PCI_DEV(XHCI, 5) -#define PCI_DEV_CNVI_BT _PCI_DEV(XHCI, 7) -#endif #define PCI_DEV_XHCI _PCI_DEV(XHCI, 0) #define PCI_DEV_USBOTG _PCI_DEV(XHCI, 1) #define PCI_DEV_SRAM _PCI_DEV(XHCI, 2) @@ -148,15 +123,7 @@ #define PCI_DEV_CSE_KT _PCI_DEV(CSE, 3) #define PCI_DEV_CSE_3 _PCI_DEV(CSE, 4) #define PCI_DEV_CSE_4 _PCI_DEV(CSE, 5) -#if CONFIG(SOC_INTEL_PANTHERLAKE) -#define PCI_DEV_CSE_WLAN _PCI_DEV(CSE, 7) -#endif
-#if CONFIG(SOC_INTEL_PANTHERLAKE) -#define PCI_DEV_SLOT_UFS 0x17 -#define PCI_DEVFN_UFS _PCI_DEVFN(UFS, 0) -#define PCI_DEV_UFS _PCI_DEV(UFS, 0) -#endif #define PCI_DEV_SLOT_ESE 0x18 #define PCI_DEVFN_ESE1 _PCI_DEVFN(ESE, 0) #define PCI_DEVFN_ESE2 _PCI_DEVFN(ESE, 1) @@ -187,20 +154,6 @@ #define PCI_DEV_PCIE5 _PCI_DEV(PCIE_1, 4) #define PCI_DEV_PCIE6 _PCI_DEV(PCIE_1, 5)
-#if CONFIG(SOC_INTEL_PANTHERLAKE) -#define PCI_DEV_SLOT_PCIE_2 0x6 -#define PCI_DEVFN_PCIE9 _PCI_DEVFN(PCIE_2, 0) -#define PCI_DEVFN_PCIE10 _PCI_DEVFN(PCIE_2, 1) -#define PCI_DEVFN_PCIE11 _PCI_DEVFN(PCIE_2, 2) -#define PCI_DEV_PCIE9 _PCI_DEV(PCIE_2, 0) -#define PCI_DEV_PCIE10 _PCI_DEV(PCIE_2, 1) -#define PCI_DEV_PCIE11 _PCI_DEV(PCIE_2, 2) - -#define PCI_DEV_SLOT_PCIE_3 0x1 -#define PCI_DEVFN_PCIE12 _PCI_DEVFN(PCIE_3, 0) -#define PCI_DEV_PCIE12 _PCI_DEV(PCIE_3, 0) -#endif - #define PCI_DEV_SLOT_SIO2 0x1e #define PCI_DEVFN_UART0 _PCI_DEVFN(SIO2, 0) #define PCI_DEVFN_UART1 _PCI_DEVFN(SIO2, 1) diff --git a/src/soc/intel/lnl_dev/include/soc/pcie.h b/src/soc/intel/lnl_dev/include/soc/pcie.h new file mode 100644 index 0000000..4016ddc --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/pcie.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_PCIE_H_ +#define _SOC_INTEL_LNL_PCIE_H_ + +#include <intelblocks/pcie_rp.h> + +const struct pcie_rp_group *get_pcie_rp_table(void); + +#endif /* _SOC_INTEL_LNL_PCIE_H_ */ diff --git a/src/soc/intel/lnl_dev/include/soc/powerlimit.h b/src/soc/intel/lnl_dev/include/soc/powerlimit.h new file mode 100644 index 0000000..3e5a286 --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/powerlimit.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_POWERLIMIT_H_ +#define _SOC_INTEL_LNL_POWERLIMIT_H_ + +/* Types of different SKUs */ +enum soc_intel_lnl_power_limits { + LNL_M_POWER_LIMITS, + LNL_POWER_LIMITS_COUNT +}; + +#endif /* _SOC_INTEL_LNL_POWERLIMIT_H_ */ diff --git a/src/soc/intel/lnl_dev/include/soc/ramstage.h b/src/soc/intel/lnl_dev/include/soc/ramstage.h new file mode 100644 index 0000000..ea4982e --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/ramstage.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_RAMSTAGE_H_ +#define _SOC_INTEL_LNL_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_lnl_dev_config *config); +void soc_init_pre_device(void *chip_info); +void soc_enable(struct device *dev); +void soc_init_final_device(void *chip_info); + +#endif //_SOC_INTEL_LNL_RAMSTAGE_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/serialio.h b/src/soc/intel/lnl_dev/include/soc/serialio.h new file mode 100644 index 0000000..bc94a8c --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/serialio.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_SERIALIO_H_ +#define _SOC_INTEL_LNL_SERIALIO_H_ + +enum { + PchSerialIoDisabled, + PchSerialIoPci, + PchSerialIoHidden, + PchSerialIoLegacyUart, + PchSerialIoSkipInit +}; + +enum { + PchSerialIoIndexI2C0, + PchSerialIoIndexI2C1, + PchSerialIoIndexI2C2, + PchSerialIoIndexI2C3, + PchSerialIoIndexI2C4, + PchSerialIoIndexI2C5 +}; + +enum { + PchSerialIoIndexI3C0, + PchSerialIoIndexI3C1 +}; + +enum { + PchSerialIoIndexGSPI0, + PchSerialIoIndexGSPI1, + PchSerialIoIndexGSPI2, +}; + +enum { + PchSerialIoIndexUART0, + PchSerialIoIndexUART1, + PchSerialIoIndexUART2 +}; + +#endif //_SOC_INTEL_LNL_SERIALIO_H_ diff --git a/src/soc/intel/lnl_dev/include/soc/soc_info.h b/src/soc/intel/lnl_dev/include/soc/soc_info.h index 56d94a3..d21f639 100644 --- a/src/soc/intel/lnl_dev/include/soc/soc_info.h +++ b/src/soc/intel/lnl_dev/include/soc/soc_info.h @@ -7,7 +7,6 @@ enum { NOT_DETECTED = 0, LNLM, - PTLP, };
uint8_t get_soctype(void); diff --git a/src/soc/intel/lnl_dev/include/soc/tcss.h b/src/soc/intel/lnl_dev/include/soc/tcss.h new file mode 100644 index 0000000..dcffc86 --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/tcss.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _SOC_INTEL_LNL_TCSS_H_ +#define _SOC_INTEL_LNL_TCSS_H_ + +/* Thunderbolt firmware IMR status */ +#define IOM_CSME_IMR_TBT_STATUS 0x14 +#define TBT_VALID_AUTHENTICATION (1 << 30) + +/* IOM aux bias control registers in REGBAR MMIO space */ +#define IOM_AUX_BIAS_CTRL_PULLUP_OFFSET_0 0x1070 +#define IOM_AUX_BIAS_CTRL_PULLUP_OFFSET(x) (IOM_AUX_BIAS_CTRL_PULLUP_OFFSET_0 + (x) * 4) +#define IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET_0 0x1088 +#define IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET(x) (IOM_AUX_BIAS_CTRL_PULLDOWN_OFFSET_0 + (x) * 4) + +/* + * The PCI-SIG engineering change requirement provides the ACPI additions for firmware latency + * optimization. Both of FW_RESET_TIME and FW_D3HOT_TO_D0_TIME are applicable to the upstream + * port of the USB4/TBT topology. + */ +/* Number of microseconds to wait after a conventional reset */ +#define FW_RESET_TIME 50000 + +/* Number of microseconds to wait after data link layer active report */ +#define FW_DL_UP_TIME 1 + +/* Number of microseconds to wait after a function level reset */ +#define FW_FLR_RESET_TIME 1 + +/* Number of microseconds to wait from D3 hot to D0 transition */ +#define FW_D3HOT_TO_D0_TIME 50000 + +/* Number of microseconds to wait after setting the VF enable bit */ +#define FW_VF_ENABLE_TIME 1 + +#endif /* _SOC_INTEL_LNL_TCSS_H_ */ diff --git a/src/soc/intel/lnl_dev/include/soc/usb.h b/src/soc/intel/lnl_dev/include/soc/usb.h new file mode 100644 index 0000000..f133d5a --- /dev/null +++ b/src/soc/intel/lnl_dev/include/soc/usb.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_INTEL_LNL_USB_H_ +#define _SOC_INTEL_LNL_USB_H_ + +#include <stdint.h> + +/* Per Port HS Transmitter Emphasis */ +#define USB2_EMP_OFF 0 +#define USB2_DE_EMP_ON 1 +#define USB2_PRE_EMP_ON 2 +#define USB2_DE_EMP_ON_PRE_EMP_ON 3 + +/* Per Port Half Bit Pre-emphasis */ +#define USB2_FULL_BIT_PRE_EMP 0 +#define USB2_HALF_BIT_PRE_EMP 1 + +/* Per Port HS Preemphasis Bias */ +#define USB2_BIAS_0MV 0 +#define USB2_BIAS_11P25MV 1 +#define USB2_BIAS_16P9MV 2 +#define USB2_BIAS_28P15MV 3 +#define USB2_BIAS_39P35MV 5 +#define USB2_BIAS_45MV 6 +#define USB2_BIAS_56P3MV 7 + +struct usb2_port_config { + uint8_t enable; + uint8_t ocpin; + uint8_t tx_bias; + uint8_t tx_emp_enable; + uint8_t pre_emp_bias; + uint8_t pre_emp_bit; +}; + +/* USB Overcurrent pins definition */ +enum { + OC0 = 0, + OC1, + OC2, + OC3, + OC4, + OC5, + OC6, + OC7, + OCMAX, + OC_SKIP = 0xff, /* Skip OC programming */ +}; + +/* Standard USB Port based on length: + * - External + * - Back Panel + * - OTG + * - M.2 + * - Internal device down */ + +#define USB2_PORT_EMPTY { \ + .enable = 0, \ + .ocpin = OC_SKIP, \ + .tx_bias = USB2_BIAS_0MV, \ + .tx_emp_enable = USB2_EMP_OFF, \ + .pre_emp_bias = USB2_BIAS_0MV, \ + .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \ +} + +/* Length = 11.5"-12" */ +#define USB2_PORT_LONG(pin) { \ + .enable = 1, \ + .ocpin = (pin), \ + .tx_bias = USB2_BIAS_39P35MV, \ + .tx_emp_enable = USB2_PRE_EMP_ON, \ + .pre_emp_bias = USB2_BIAS_56P3MV, \ + .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \ +} + +/* Length = 6"-11.49" */ +#define USB2_PORT_MID(pin) { \ + .enable = 1, \ + .ocpin = (pin), \ + .tx_bias = USB2_BIAS_0MV, \ + .tx_emp_enable = USB2_DE_EMP_ON_PRE_EMP_ON, \ + .pre_emp_bias = USB2_BIAS_45MV, \ + .pre_emp_bit = USB2_FULL_BIT_PRE_EMP, \ +} + +/* Length = 3"-5.99" */ +#define USB2_PORT_SHORT(pin) { \ + .enable = 1, \ + .ocpin = (pin), \ + .tx_bias = USB2_BIAS_39P35MV, \ + .tx_emp_enable = USB2_PRE_EMP_ON | USB2_DE_EMP_ON, \ + .pre_emp_bias = USB2_BIAS_39P35MV, \ + .pre_emp_bit = USB2_FULL_BIT_PRE_EMP, \ +} + +/* Max TX and Pre-emp settings */ +#define USB2_PORT_MAX(pin) { \ + .enable = 1, \ + .ocpin = (pin), \ + .tx_bias = USB2_BIAS_56P3MV, \ + .tx_emp_enable = USB2_PRE_EMP_ON, \ + .pre_emp_bias = USB2_BIAS_56P3MV, \ + .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \ +} + +/* Type-C Port, no BC1.2 charge detect module / MUX + * Length = 3.0" - 9.00" */ +#define USB2_PORT_TYPE_C(pin) { \ + .enable = 1, \ + .ocpin = (pin), \ + .tx_bias = USB2_BIAS_0MV, \ + .tx_emp_enable = USB2_PRE_EMP_ON, \ + .pre_emp_bias = USB2_BIAS_56P3MV, \ + .pre_emp_bit = USB2_HALF_BIT_PRE_EMP, \ +} + +struct usb3_port_config { + uint8_t enable; + uint8_t ocpin; + uint8_t tx_de_emp; + uint8_t tx_downscale_amp; +}; + +#define USB3_PORT_EMPTY { \ + .enable = 0, \ + .ocpin = OC_SKIP, \ + .tx_de_emp = 0x00, \ + .tx_downscale_amp = 0x00, \ +} + +#define USB3_PORT_DEFAULT(pin) { \ + .enable = 1, \ + .ocpin = (pin), \ + .tx_de_emp = 0x0, \ + .tx_downscale_amp = 0x00, \ +} + +struct tcss_port_config { + uint8_t enable; + uint8_t ocpin; +}; + +#define TCSS_PORT_EMPTY { \ + .enable = 0, \ + .ocpin = OC_SKIP, \ +} + +#define TCSS_PORT_DEFAULT(pin) { \ + .enable = 1, \ + .ocpin = (pin), \ +} + + +#endif //_SOC_INTEL_LNL_USB_H_ diff --git a/src/soc/intel/lnl_dev/lockdown.c b/src/soc/intel/lnl_dev/lockdown.c new file mode 100644 index 0000000..324c37b --- /dev/null +++ b/src/soc/intel/lnl_dev/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 (1 << 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/lnl_dev/lunarlake/acpi.c b/src/soc/intel/lnl_dev/lunarlake/acpi.c new file mode 100644 index 0000000..558d4b7 --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/acpi.c @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <arch/ioapic.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci_ops.h> +#include <soc/cpu.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/soc_chip.h> +#include <intelblocks/acpi.h> +#include <soc/systemagent.h> +#include <string.h> +#include <types.h> +#include <soc/acpi.h> +#include <platform_soc_defs.h> + +unsigned long soc_fill_dmar(unsigned long current) +{ + unsigned long tmp; + const uint64_t gfxvtbar = MCHBAR64(GFXVTBAR) & VTBAR_MASK; + const bool gfxvten = MCHBAR32(GFXVTBAR) & VTBAR_ENABLED; + + printk(BIOS_DEBUG, "%s - gfxvtbar:0x%llx 0x%x\n", + __func__, gfxvtbar, MCHBAR32(GFXVTBAR)); + if (is_devfn_enabled(PCI_DEVFN_IGD) && gfxvtbar && gfxvten) { + tmp = current; + current += acpi_create_dmar_drhd(current, 0, 0, gfxvtbar); + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0); + + acpi_dmar_drhd_fixup(tmp, current); + } + + tmp = current; + current += acpi_create_dmar_drhd(current, + DRHD_INCLUDE_PCI_ALL, 0, NONGFXVT_BASE_ADDRESS); + current += acpi_create_dmar_ds_ioapic_from_hw(current, + IO_APIC_ADDR, V_P2SB_CFG_IBDF_BUS, V_P2SB_CFG_IBDF_DEV, + V_P2SB_CFG_IBDF_FUNC); + current += acpi_create_dmar_ds_msi_hpet(current, + 0, V_P2SB_CFG_HBDF_BUS, V_P2SB_CFG_HBDF_DEV, + V_P2SB_CFG_HBDF_FUNC); + acpi_dmar_drhd_fixup(tmp, current); + + /* Add RMRR entry */ + if (is_devfn_enabled(PCI_DEVFN_IGD) && gfxvtbar && gfxvten) { + tmp = current; + current += acpi_create_dmar_rmrr(current, 0, + sa_get_gsm_base(), sa_get_tolud_base() - 1); + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0); + acpi_dmar_rmrr_fixup(tmp, current); + } + + tmp = current; + current += acpi_create_dmar_satc(current, ATC_REQUIRED, 0); + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IGD, 0); + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_IPU, 0); + if (is_devfn_enabled(PCI_DEVFN_NPU)) + current += acpi_create_dmar_ds_pci(current, 0, PCI_DEV_SLOT_NPU, 0); + acpi_dmar_satc_fixup(tmp, current); + + return current; +} + +unsigned long sa_write_acpi_tables(const struct device *dev, unsigned long current, + struct acpi_rsdp *rsdp) +{ + acpi_dmar_t *const dmar = (acpi_dmar_t *)current; + /* + * Create DMAR table only if we have VT-d capability and FSP does not override its + * feature. + */ + if ((pci_read_config32(dev, CAPID0_A) & VTD_DISABLE) || + !(MCHBAR32(GFXVTBAR) & VTBAR_ENABLED)) + return current; + printk(BIOS_DEBUG, "ACPI: * DMAR\n"); + acpi_create_dmar(dmar, DMAR_INTR_REMAP | DMA_CTRL_PLATFORM_OPT_IN_FLAG, soc_fill_dmar); + current += dmar->header.length; + current = acpi_align_current(current); + acpi_add_table(rsdp, dmar); + return current; +} + diff --git a/src/soc/intel/lnl_dev/lunarlake/chip.c b/src/soc/intel/lnl_dev/lunarlake/chip.c new file mode 100644 index 0000000..834e2b5 --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/chip.c @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <intelblocks/acpi.h> +#include <device/device.h> +#include <soc/pci_devs.h> +#include <soc/ramstage.h> + +#if CONFIG(HAVE_ACPI_TABLES) +const char *soc_acpi_name(const struct device *dev) +{ + if (dev->path.type == DEVICE_PATH_DOMAIN) + return "PCI0"; + + if (dev->path.type == DEVICE_PATH_USB) { + switch (dev->path.usb.port_type) { + case 0: + /* Root Hub */ + return "RHUB"; + case 2: + /* USB2 ports */ + switch (dev->path.usb.port_id) { + case 0: return "HS01"; + case 1: return "HS02"; + case 2: return "HS03"; + case 3: return "HS04"; + case 4: return "HS05"; + case 5: return "HS06"; + case 6: return "HS07"; + case 7: return "HS08"; + case 8: return "HS09"; + case 9: return "HS10"; + } + break; + case 3: + /* USB3 ports */ + switch (dev->path.usb.port_id) { + case 0: return "SS01"; + case 1: return "SS02"; + case 2: return "SS03"; + case 3: return "SS04"; + } + break; + } + printk(BIOS_DEBUG, "dev->path.type=%x\n", dev->path.usb.port_type); + return NULL; + } + if (dev->path.type != DEVICE_PATH_PCI) { + printk(BIOS_DEBUG, "dev->path.type=%x\n", dev->path.type); + return NULL; + } + + switch (dev->path.pci.devfn) { + case PCI_DEVFN_ROOT: return "MCHC"; + case PCI_DEVFN_TCSS_XHCI: return "TXHC"; + case PCI_DEVFN_TCSS_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_IPU: return "IPU0"; + case PCI_DEVFN_I3C1: return "I3C1"; + case PCI_DEVFN_I3C2: return "I3C2"; + case PCI_DEVFN_ISH: return "ISHB"; + case PCI_DEVFN_UFS: return "UFSB"; + case PCI_DEVFN_XHCI: return "XHCI"; + case PCI_DEVFN_I2C0: return "I2C0"; + case PCI_DEVFN_I2C1: return "I2C1"; + case PCI_DEVFN_I2C2: return "I2C2"; + case PCI_DEVFN_I2C3: return "I2C3"; + case PCI_DEVFN_I2C4: return "I2C4"; + case PCI_DEVFN_I2C5: return "I2C5"; + case PCI_DEVFN_PCIE1: return "RP01"; + case PCI_DEVFN_PCIE2: return "RP02"; + case PCI_DEVFN_PCIE3: return "RP03"; + case PCI_DEVFN_PCIE4: return "RP04"; + case PCI_DEVFN_PCIE5: return "RP05"; + case PCI_DEVFN_PCIE6: return "RP06"; + case PCI_DEVFN_PMC: return "PMC"; + case PCI_DEVFN_UART0: return "UAR0"; + case PCI_DEVFN_UART1: return "UAR1"; + case PCI_DEVFN_UART2: return "UAR2"; + case PCI_DEVFN_GSPI0: return "SPI0"; + case PCI_DEVFN_GSPI1: return "SPI1"; + /* Keeping ACPI device name coherent with ec.asl */ + case PCI_DEVFN_ESPI: return "LPCB"; + case PCI_DEVFN_HDA: return "HDAS"; + case PCI_DEVFN_SMBUS: return "SBUS"; + case PCI_DEVFN_GBE: return "GLAN"; + } + printk(BIOS_DEBUG, "Missing ACPI Name for PCI: 00:%02x.%01x\n", + PCI_SLOT(dev->path.pci.devfn), PCI_FUNC(dev->path.pci.devfn)); + return NULL; +} +#endif + +struct chip_operations soc_intel_lnl_dev_ops = { + + .name = "Intel Lunarlake", + .enable_dev = &soc_enable, + .init = &soc_init_pre_device, + .final = &soc_init_final_device, +}; + diff --git a/src/soc/intel/lnl_dev/lunarlake/cpu.c b/src/soc/intel/lnl_dev/lunarlake/cpu.c new file mode 100644 index 0000000..f2da469 --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/cpu.c @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <soc/soc_chip.h> +#include <soc/soc_info.h> +#include <soc/cpu.h> +#include <../chip.h> + +uint8_t get_supported_lpm_mask(void) +{ + uint8_t type = get_soctype(); + switch (type) { + case LNLM: + return LPM_S0i2_0 | LPM_S0i2_1 | LPM_S0i2_2; + default: + printk(BIOS_ERR, "Unknown LNL CPU type: %d\n", type); + return 0; + } +} diff --git a/src/soc/intel/lnl_dev/lunarlake/elog.c b/src/soc/intel/lnl_dev/lunarlake/elog.c new file mode 100644 index 0000000..8226aec --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/elog.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <console/console.h> +#include <device/pci_ops.h> +#include <elog.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/xhci.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_info.h> +#include <stdint.h> +#include <types.h> +#include <soc/elog.h> + +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 }, + }; + + 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); + } +} + +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 }, + }; + 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); +} diff --git a/src/soc/intel/lnl_dev/lunarlake/fsp_params.c b/src/soc/intel/lnl_dev/lunarlake/fsp_params.c new file mode 100644 index 0000000..7cabf18 --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/fsp_params.c @@ -0,0 +1,801 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <cbfs.h> +#include <console/console.h> +#include <cpu/intel/cpu_ids.h> +#include <cpu/intel/microcode.h> +#include <device/device.h> +#include <device/pci.h> +#include <fsp/api.h> +#include <fsp/fsp_debug_event.h> +#include <fsp/ppi/mp_service_ppi.h> +#include <fsp/util.h> +#include <option.h> +#include <intelblocks/cse.h> +#include <intelblocks/irq.h> +#include <intelblocks/lpss.h> +#include <intelblocks/mp_init.h> +#include <intelblocks/systemagent.h> +#include <intelblocks/xdci.h> +#include <intelpch/lockdown.h> +#include <intelblocks/tcss.h> +#include <security/vboot/vboot_common.h> +#include <soc/cpu.h> +#include <gpio_soc_defs.h> +#include <soc/intel/common/vbt.h> +#include <soc/pci_devs.h> +#include <soc/pcie.h> +#include <soc/ramstage.h> +#include <soc/soc_chip.h> +#include <soc/soc_info.h> +#include <soc/cpu.h> +#include <stdlib.h> +#include <string.h> +#include <types.h> + +/* THC assignment definition */ +#define THC_NONE 0 +#define THC_0 1 +#define THC_1 2 + +/* SATA DEVSLP idle timeout default values */ +#define DEF_DMVAL 15 +#define DEF_DITOVAL 625 + +#define MAX_ONBOARD_PCIE_DEVICES 256 + +/* + * ME End of Post configuration + * 0 - Disable EOP. + * 1 - Send in PEI (Applicable for FSP in API mode) + * 2 - Send in DXE (Not applicable for FSP in API mode) + */ +enum fsp_end_of_post { + EOP_DISABLE = 0, + EOP_PEI = 1, + EOP_DXE = 2, +}; + +static const pci_devfn_t i2c_dev[] = { + PCI_DEVFN_I2C0, + PCI_DEVFN_I2C1, + PCI_DEVFN_I2C2, + PCI_DEVFN_I2C3, + PCI_DEVFN_I2C4, + PCI_DEVFN_I2C5, +}; + +static const pci_devfn_t i3c_dev[] = { + PCI_DEVFN_I3C1, + PCI_DEVFN_I3C2, +}; + +static const pci_devfn_t gspi_dev[] = { + PCI_DEVFN_GSPI0, + PCI_DEVFN_GSPI1, + PCI_DEVFN_GSPI2, +}; + +static const pci_devfn_t uart_dev[] = { + PCI_DEVFN_UART0, + PCI_DEVFN_UART1, + PCI_DEVFN_UART2 +}; + +static const struct slot_irq_constraints irq_constraints[] = { + { + .slot = PCI_DEV_SLOT_IGD, + .fns = { + /* INTERRUPT_PIN is RO/0x01 */ + FIXED_INT_ANY_PIRQ(PCI_DEV_SLOT_IGD, PCI_INT_A), + }, + }, + { + .slot = PCI_DEV_SLOT_DPTF, + .fns = { + ANY_PIRQ(PCI_DEVFN_DPTF), + }, + }, + { + .slot = PCI_DEV_SLOT_IPU, + .fns = { + /* INTERRUPT_PIN is RO/0x01, and INTERRUPT_LINE is RW, + but S0ix fails when not set to 16 (b/193434192) */ + FIXED_INT_PIRQ(PCI_DEVFN_IPU, PCI_INT_A, PIRQ_A), + }, + }, + { + .slot = PCI_DEV_SLOT_TBT, + .fns = { + ANY_PIRQ(PCI_DEVFN_TBT0), + ANY_PIRQ(PCI_DEVFN_TBT1), + ANY_PIRQ(PCI_DEVFN_TBT2), + }, + }, + { + .slot = PCI_DEV_SLOT_NPU, + .fns = { + /* INTERRUPT_PIN is RO/0x01 */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_NPU, PCI_INT_A), + }, + }, + { + .slot = PCI_DEV_SLOT_TCSS, + .fns = { + ANY_PIRQ(PCI_DEVFN_TCSS_XHCI), + }, + }, + { + .slot = PCI_DEV_SLOT_THC, + .fns = { + ANY_PIRQ(PCI_DEVFN_THC0), + ANY_PIRQ(PCI_DEVFN_THC1), + }, + }, + { + .slot = PCI_DEV_SLOT_ISH, + .fns = { + DIRECT_IRQ(PCI_DEVFN_ISH), + ANY_PIRQ(PCI_DEVFN_UFS), + }, + }, + { + .slot = PCI_DEV_SLOT_XHCI, + .fns = { + ANY_PIRQ(PCI_DEVFN_XHCI), + DIRECT_IRQ(PCI_DEVFN_USBOTG), + ANY_PIRQ(PCI_DEVFN_CNVI_WIFI), + }, + }, + { + .slot = PCI_DEV_SLOT_SIO0, + .fns = { + DIRECT_IRQ(PCI_DEVFN_I2C0), + DIRECT_IRQ(PCI_DEVFN_I2C1), + DIRECT_IRQ(PCI_DEVFN_I2C2), + DIRECT_IRQ(PCI_DEVFN_I2C3), + }, + }, + { + .slot = PCI_DEV_SLOT_CSE, + .fns = { + ANY_PIRQ(PCI_DEVFN_CSE), + ANY_PIRQ(PCI_DEVFN_CSE_2), + ANY_PIRQ(PCI_DEVFN_CSE_IDER), + ANY_PIRQ(PCI_DEVFN_CSE_KT), + ANY_PIRQ(PCI_DEVFN_CSE_3), + ANY_PIRQ(PCI_DEVFN_CSE_4), + }, + }, + { + .slot = PCI_DEV_SLOT_SIO1, + .fns = { + DIRECT_IRQ(PCI_DEVFN_I2C4), + DIRECT_IRQ(PCI_DEVFN_I2C5), + DIRECT_IRQ(PCI_DEVFN_UART2), + }, + }, + { + .slot = PCI_DEV_SLOT_PCIE_1, + .fns = { + FIXED_INT_PIRQ(PCI_DEVFN_PCIE1, PCI_INT_A, PIRQ_A), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE2, PCI_INT_B, PIRQ_B), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE3, PCI_INT_C, PIRQ_C), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE4, PCI_INT_D, PIRQ_D), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE5, PCI_INT_A, PIRQ_A), + FIXED_INT_PIRQ(PCI_DEVFN_PCIE6, PCI_INT_B, PIRQ_B), + }, + }, + { + .slot = PCI_DEV_SLOT_SIO2, + .fns = { + /* UART0 shares an interrupt line with TSN0, so must use + a PIRQ */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_UART0, PCI_INT_A), + /* UART1 shares an interrupt line with TSN1, so must use + a PIRQ */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_UART1, PCI_INT_B), + DIRECT_IRQ(PCI_DEVFN_GSPI0), + DIRECT_IRQ(PCI_DEVFN_GSPI1), + }, + }, + { + .slot = PCI_DEV_SLOT_ESPI, + .fns = { + ANY_PIRQ(PCI_DEVFN_HDA), + ANY_PIRQ(PCI_DEVFN_SMBUS), + ANY_PIRQ(PCI_DEVFN_GBE), + /* INTERRUPT_PIN is RO/0x01 */ + FIXED_INT_ANY_PIRQ(PCI_DEVFN_NPK, PCI_INT_A), + }, + }, +}; + +static const SI_PCH_DEVICE_INTERRUPT_CONFIG *pci_irq_to_fsp(size_t *out_count) +{ + const struct pci_irq_entry *entry = get_cached_pci_irqs(); + SI_PCH_DEVICE_INTERRUPT_CONFIG *config; + size_t pch_total = 0; + size_t cfg_count = 0; + + if (!entry) + return NULL; + + /* Count PCH devices */ + while (entry) { + if (is_pch_slot(entry->devfn)) + ++pch_total; + entry = entry->next; + } + + /* Convert PCH device entries to FSP format */ + config = calloc(pch_total, sizeof(*config)); + entry = get_cached_pci_irqs(); + while (entry) { + if (!is_pch_slot(entry->devfn)) { + entry = entry->next; + continue; + } + + config[cfg_count].Device = PCI_SLOT(entry->devfn); + config[cfg_count].Function = PCI_FUNC(entry->devfn); + config[cfg_count].IntX = (SI_PCH_INT_PIN)entry->pin; + config[cfg_count].Irq = entry->irq; + ++cfg_count; + + entry = entry->next; + } + + *out_count = cfg_count; + + return config; +} + +/* + * Chip config parameter PcieRpL1Substates uses (UPD value + 1) + * because UPD value of 0 for PcieRpL1Substates means disabled for FSP. + * In order to ensure that mainboard setting does not disable L1 substates + * incorrectly, chip config parameter values are offset by 1 with 0 meaning + * use FSP UPD default. get_l1_substate_control() ensures that the right UPD + * value is set in fsp_params. + * 0: Use FSP UPD default + * 1: Disable L1 substates + * 2: Use L1.1 + * 3: Use L1.2 (FSP UPD default) + */ +static int get_l1_substate_control(enum L1_substates_control ctl) +{ + if (CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE)) + ctl = L1_SS_DISABLED; + else if ((ctl > L1_SS_L1_2) || (ctl == L1_SS_FSP_DEFAULT)) + ctl = L1_SS_L1_2; + return ctl - 1; +} + +/* + * get_aspm_control() ensures that the right UPD value is set in fsp_params. + * 0: Disable ASPM + * 1: L0s only + * 2: L1 only + * 3: L0s and L1 + * 4: Auto configuration + */ +static unsigned int get_aspm_control(enum ASPM_control ctl) +{ + if (ctl > ASPM_AUTO) + ctl = ASPM_AUTO; + return ctl; +} + +__weak void mainboard_update_soc_chip_config(struct soc_intel_lnl_dev_config *config) +{ + /* Override settings per board. */ +} + +static void fill_fsps_lpss_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + int max_port, i; + + max_port = get_max_i2c_port(); + for (i = 0; i < max_port; i++) { + s_cfg->SerialIoI2cMode[i] = is_devfn_enabled(i2c_dev[i]) ? + config->SerialIoI2cMode[i] : 0; + } + + max_port = get_max_i3c_port(); + for (i = 0; i < max_port; i++) { + s_cfg->SerialIoI3cMode[i] = is_devfn_enabled(i3c_dev[i]) ? + config->SerialIoI3cMode[i] : 0; + } + + max_port = get_max_gspi_port(); + for (i = 0; i < max_port; i++) { + s_cfg->SerialIoSpiCsMode[i] = config->SerialIoGSpiCsMode[i]; + s_cfg->SerialIoSpiCsState[i] = config->SerialIoGSpiCsState[i]; + s_cfg->SerialIoSpiMode[i] = is_devfn_enabled(gspi_dev[i]) ? + config->SerialIoGSpiMode[i] : 0; + } + + max_port = get_max_uart_port(); + for (i = 0; i < max_port; i++) { + s_cfg->SerialIoUartMode[i] = is_devfn_enabled(uart_dev[i]) ? + config->SerialIoUartMode[i] : 0; + } +} + +static void fill_fsps_microcode_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + const struct microcode *microcode_file; + size_t microcode_len; + + /* Locate microcode and pass to FSP-S for 2nd microcode loading */ + microcode_file = intel_microcode_find(); + + if (microcode_file != NULL) { + microcode_len = get_microcode_size(microcode_file); + if (microcode_len != 0) { + /* Update CPU Microcode patch base address/size */ + s_cfg->MicrocodeRegionBase = (uint32_t)(uintptr_t)microcode_file; + s_cfg->MicrocodeRegionSize = (uint32_t)microcode_len; + } + } +} + +static void fill_fsps_cpu_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* + * FIXME: FSP assumes ownership of the APs (Application Processors) + * upon passing `NULL` pointer to the CpuMpPpi FSP-S UPD. + * Hence, pass a valid pointer to the CpuMpPpi UPD unconditionally. + * This would avoid APs from getting hijacked by FSP while coreboot + * decides to set SkipMpInit UPD. + */ + s_cfg->CpuMpPpi = (uintptr_t) mp_fill_ppi_services_data(); + + /* + * Fill `2nd microcode loading FSP UPD` if FSP is running CPU feature + * programming. + */ + if (CONFIG(USE_FSP_FEATURE_PROGRAM_ON_APS)) + fill_fsps_microcode_params(s_cfg, config); +} + + +static void fill_fsps_igd_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* Load VBT before devicetree-specific config. */ + s_cfg->GraphicsConfigPtr = (uintptr_t)vbt_get(); + s_cfg->VbtSize = (CONFIG_VBT_DATA_SIZE_KB * KiB); + /* Check if IGD is present and fill Graphics init param accordingly */ + s_cfg->PeiGraphicsPeimInit = CONFIG(RUN_FSP_GOP) && is_devfn_enabled(PCI_DEVFN_IGD); + s_cfg->LidStatus = CONFIG(RUN_FSP_GOP); +} + +static void fill_fsps_tcss_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + const struct device *tcss_port_arr[] = { + DEV_PTR(tcss_usb3_port0), + DEV_PTR(tcss_usb3_port1), + DEV_PTR(tcss_usb3_port2), + }; + + s_cfg->TcssAuxOri = config->tcss_aux_ori; + + /* Explicitly clear this field to avoid using defaults */ + memset(s_cfg->IomTypeCPortPadCfg, 0, sizeof(s_cfg->IomTypeCPortPadCfg)); + + /* D3Hot and D3Cold for TCSS */ + s_cfg->D3HotEnable = !config->tcss_d3_hot_disable; + s_cfg->D3ColdEnable = CONFIG(D3COLD_SUPPORT); + s_cfg->UsbTcPortEn = 0; + + uint8_t _MAX_TYPE_C_PORTS = get_max_tcss_port(); + for (int i = 0; i < _MAX_TYPE_C_PORTS; i++) { + if (is_dev_enabled(tcss_port_arr[i])) + s_cfg->UsbTcPortEn |= BIT(i); + } +} + +static void fill_fsps_chipset_lockdown_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* Chipset Lockdown */ + const bool lockdown_by_fsp = get_lockdown_config() == CHIPSET_LOCKDOWN_FSP; + s_cfg->PchLockDownGlobalSmi = lockdown_by_fsp; + s_cfg->PchLockDownBiosInterface = lockdown_by_fsp; + s_cfg->PchUnlockGpioPads = !lockdown_by_fsp; + s_cfg->RtcMemoryLock = lockdown_by_fsp; + s_cfg->SkipPamLock = !lockdown_by_fsp; + + /* coreboot will send EOP before loading payload */ + s_cfg->EndOfPostMessage = EOP_DISABLE; + + /* Disable CpuCrashLogEnable */ + s_cfg->CpuCrashLogEnable = 0; +} + +static void fill_fsps_xhci_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + int i, max_port; + + max_port = get_max_usb20_port(); + for (i = 0; i < max_port; i++) { + s_cfg->PortUsb20Enable[i] = config->usb2_ports[i].enable; + s_cfg->Usb2PhyPetxiset[i] = config->usb2_ports[i].pre_emp_bias; + s_cfg->Usb2PhyTxiset[i] = config->usb2_ports[i].tx_bias; + s_cfg->Usb2PhyPredeemp[i] = config->usb2_ports[i].tx_emp_enable; + s_cfg->Usb2PhyPehalfbit[i] = config->usb2_ports[i].pre_emp_bit; + + if (config->usb2_ports[i].enable) + s_cfg->Usb2OverCurrentPin[i] = config->usb2_ports[i].ocpin; + else + s_cfg->Usb2OverCurrentPin[i] = OC_SKIP; + } + + max_port = get_max_usb30_port(); + for (i = 0; i < max_port; i++) { + s_cfg->PortUsb30Enable[i] = config->usb3_ports[i].enable; + if (config->usb3_ports[i].enable) + s_cfg->Usb3OverCurrentPin[i] = config->usb3_ports[i].ocpin; + else + s_cfg->Usb3OverCurrentPin[i] = OC_SKIP; + + if (config->usb3_ports[i].tx_de_emp) { + s_cfg->Usb3HsioTxDeEmphEnable[i] = 1; + s_cfg->Usb3HsioTxDeEmph[i] = config->usb3_ports[i].tx_de_emp; + } + if (config->usb3_ports[i].tx_downscale_amp) { + s_cfg->Usb3HsioTxDownscaleAmpEnable[i] = 1; + s_cfg->Usb3HsioTxDownscaleAmp[i] = + config->usb3_ports[i].tx_downscale_amp; + } + } + + max_port = get_max_tcss_port(); + for (i = 0; i < max_port; i++) { + s_cfg->PortUsb30Enable[i] = config->tcss_ports[i].enable; + if (config->tcss_ports[i].enable) + s_cfg->CpuUsb3OverCurrentPin[i] = config->tcss_ports[i].ocpin; + } +} + +static void fill_fsps_xdci_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + s_cfg->XdciEnable = xdci_can_enable(PCI_DEVFN_USBOTG); +} + +static void fill_fsps_uart_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* PCH UART selection for FSP Debug */ + ASSERT(ARRAY_SIZE(s_cfg->SerialIoUartAutoFlow) > CONFIG_UART_FOR_CONSOLE); + s_cfg->SerialIoUartAutoFlow[CONFIG_UART_FOR_CONSOLE] = 0; +} + +static void fill_fsps_thermal_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* Enable TCPU for processor thermal control */ + s_cfg->Device4Enable = is_devfn_enabled(PCI_DEVFN_DPTF); + +} + +static void fill_fsps_irq_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + if (!assign_pci_irqs(irq_constraints, ARRAY_SIZE(irq_constraints))) + die("ERROR: Unable to assign PCI IRQs, and no _PRT table available\n"); + + size_t pch_count = 0; + const SI_PCH_DEVICE_INTERRUPT_CONFIG *upd_irqs = pci_irq_to_fsp(&pch_count); + + s_cfg->DevIntConfigPtr = (UINT32)((uintptr_t)upd_irqs); + s_cfg->NumOfDevIntConfig = pch_count; + printk(BIOS_INFO, "IRQ: Using dynamically assigned PCI IO-APIC IRQs\n"); +} + +static void evaluate_ssid(const struct device *dev, uint16_t *svid, uint16_t *ssid) +{ + if (!(dev && svid && ssid)) + return; + + *svid = CONFIG_SUBSYSTEM_VENDOR_ID ? : (dev->subsystem_vendor ? : 0x8086); + *ssid = CONFIG_SUBSYSTEM_DEVICE_ID ? : (dev->subsystem_device ? : 0xfffe); +} + +/* + * Programming SSID before FSP-S is important because SSID registers of a few PCIE + * devices (e.g. IPU, Crashlog, XHCI, TCSS_XHCI etc.) are locked after FSP-S hence + * provide a custom SSID (same as DID by default) value via UPD. + */ +static void fill_fsps_pci_ssid_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + struct svid_ssid_init_entry { + union { + struct { + uint64_t reg:12; + uint64_t function:3; + uint64_t device:5; + uint64_t bus:8; + uint64_t ignore1:4; + uint64_t segment:16; + uint64_t ignore2:16; + }; + uint64_t data; + }; + struct { + uint16_t svid; + uint16_t ssid; + }; + uint32_t ignore3; + }; + + static struct svid_ssid_init_entry ssid_table[MAX_ONBOARD_PCIE_DEVICES]; + const struct device *dev; + int i = 0; + + for (dev = all_devices; dev; dev = dev->next) { + if (!(is_dev_enabled(dev) && dev->path.type == DEVICE_PATH_PCI && + dev->upstream->secondary == 0)) + continue; + + if (dev->path.pci.devfn == PCI_DEVFN_ROOT) { + evaluate_ssid(dev, &s_cfg->SiCustomizedSvid, &s_cfg->SiCustomizedSsid); + } else { + ssid_table[i].reg = PCI_SUBSYSTEM_VENDOR_ID; + ssid_table[i].device = PCI_SLOT(dev->path.pci.devfn); + ssid_table[i].function = PCI_FUNC(dev->path.pci.devfn); + evaluate_ssid(dev, &ssid_table[i].svid, &ssid_table[i].ssid); + i++; + } + } + + s_cfg->SiSsidTablePtr = (uintptr_t)ssid_table; + s_cfg->SiNumberOfSsidTableEntry = i; + + /* Ensure FSP will program the registers */ + s_cfg->SiSkipSsidProgramming = 0; +} + +static void fill_fsps_lan_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* LAN */ + s_cfg->PchLanEnable = is_devfn_enabled(PCI_DEVFN_GBE); +} + +static void fill_fsps_cnvi_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* CNVi */ + s_cfg->CnviMode = is_devfn_enabled(PCI_DEVFN_CNVI_WIFI); + s_cfg->CnviWifiCore = config->cnvi_wifi_core; + s_cfg->CnviBtCore = config->cnvi_bt_core; + s_cfg->CnviBtAudioOffload = config->cnvi_bt_audio_offload; + s_cfg->CnviModemEnable = 1; + /* Assert if CNVi WiFi is enabled without CNVi being enabled. */ + assert(s_cfg->CnviMode || !s_cfg->CnviWifiCore); + /* Assert if CNVi BT is enabled without CNVi being enabled. */ + assert(s_cfg->CnviMode || !s_cfg->CnviBtCore); + /* Assert if CNVi BT offload is enabled without CNVi BT being enabled. */ + assert(s_cfg->CnviBtCore || !s_cfg->CnviBtAudioOffload); + + /* CNVi BT Interface PCI */ + s_cfg->CnviBtInterface = 2; +} + +static void fill_fsps_pmcpd_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* PMC PD + This policy will enable/disable PMC-PD Solution vs EC-TCPC Solution + */ + s_cfg->PmcPdEnable = 1; +} + +static void fill_fsps_thc_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* THC */ + s_cfg->ThcAssignment[0] = is_devfn_enabled(PCI_DEVFN_THC0) ? THC_0 : THC_NONE; + s_cfg->ThcAssignment[1] = is_devfn_enabled(PCI_DEVFN_THC1) ? THC_1 : THC_NONE; +} + +static void fill_fsps_tbt_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + int max_port = get_max_tbt_pcie_port(); + + memset(s_cfg->ITbtPcieRootPortEn, 0, sizeof(s_cfg->ITbtPcieRootPortEn)); + for (int i = 0; i < max_port; i++) + s_cfg->ITbtPcieRootPortEn[i] = is_devfn_enabled(PCI_DEVFN_TBT(i)); +} + +static void fill_fsps_8254_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* Legacy 8254 timer support */ + s_cfg->Enable8254ClockGating = !CONFIG(USE_LEGACY_8254_TIMER); + s_cfg->Enable8254ClockGatingOnS3 = !CONFIG(USE_LEGACY_8254_TIMER); +} + +static void fill_fsps_pm_timer_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* + * Legacy PM ACPI Timer (and TCO Timer) + * This *must* be 1 in any case to keep FSP from + * 1) enabling PM ACPI Timer emulation in uCode. + * 2) disabling the PM ACPI Timer. + * We handle both by ourself! + */ + s_cfg->EnableTcoTimer = 1; +} + +static void fill_fsps_pcie_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + int max_port = get_max_pcie_port(); + uint32_t enable_mask = pcie_rp_enable_mask(get_pcie_rp_table()); + for (int i = 0; i < max_port; i++) { + if (!(enable_mask & BIT(i))) + continue; + const struct pcie_rp_config *rp_cfg = &config->pcie_rp[i]; + s_cfg->PcieRpL1Substates[i] = + get_l1_substate_control(rp_cfg->PcieRpL1Substates); + s_cfg->PcieRpLtrEnable[i] = !!(rp_cfg->flags & PCIE_RP_LTR); + s_cfg->PcieRpAdvancedErrorReporting[i] = !!(rp_cfg->flags & PCIE_RP_AER); + s_cfg->PcieRpHotPlug[i] = !!(rp_cfg->flags & PCIE_RP_HOTPLUG) + || CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE); + s_cfg->PcieRpClkReqDetect[i] = !!(rp_cfg->flags & PCIE_RP_CLK_REQ_DETECT); + if (rp_cfg->pcie_rp_aspm) + s_cfg->PcieRpAspm[i] = get_aspm_control(rp_cfg->pcie_rp_aspm); + } + s_cfg->PcieComplianceTestMode = CONFIG(SOC_INTEL_COMPLIANCE_TEST_MODE); +} + +static void fill_fsps_misc_power_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + /* Skip setting D0I3 bit for all HECI devices */ + s_cfg->DisableD0I3SettingForHeci = 1; + + s_cfg->Hwp = 1; + s_cfg->Cx = 1; + s_cfg->PsOnEnable = 1; + /* Enable the energy efficient turbo mode */ + s_cfg->EnergyEfficientTurbo = 1; + + /* + * Disable Pch Pm Energy Report + * Energy Report is disabled to enhance boottime. + */ + s_cfg->PchPmDisableEnergyReport = 1; + + s_cfg->PmcLpmS0ixSubStateEnableMask = get_supported_lpm_mask(); +} + + +static void fill_fsps_ufs_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + s_cfg->UfsEnable[0] = is_devfn_enabled(PCI_DEVFN_UFS); +} + +static void fill_fsps_ai_params(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) +{ + s_cfg->NpuEnable = is_devfn_enabled(PCI_DEVFN_NPU); +} + +static void arch_silicon_init_params(FSPS_ARCH2_UPD *s_arch_cfg) +{ + /* + * EnableMultiPhaseSiliconInit for running MultiPhaseSiInit + */ + + /* Assign FspEventHandler arch Upd to use coreboot debug event handler */ + if (CONFIG(FSP_USES_CB_DEBUG_EVENT_HANDLER) && CONFIG(CONSOLE_SERIAL) && + CONFIG(FSP_ENABLE_SERIAL_DEBUG)) + s_arch_cfg->FspEventHandler = (uintptr_t)((FSP_EVENT_HANDLER *) + fsp_debug_event_handler); + +} + +static void soc_silicon_init_params(FSP_S_CONFIG *s_cfg, + struct soc_intel_lnl_dev_config *config) +{ + /* Override settings per board if required. */ + mainboard_update_soc_chip_config(config); + + const void (*fill_fsps_params[])(FSP_S_CONFIG *s_cfg, + const struct soc_intel_lnl_dev_config *config) = { + fill_fsps_lpss_params, + fill_fsps_cpu_params, + fill_fsps_igd_params, + fill_fsps_tcss_params, + fill_fsps_chipset_lockdown_params, + fill_fsps_xhci_params, + fill_fsps_xdci_params, + fill_fsps_uart_params, + fill_fsps_thermal_params, + fill_fsps_lan_params, + fill_fsps_cnvi_params, + fill_fsps_pmcpd_params, + fill_fsps_thc_params, + fill_fsps_tbt_params, + fill_fsps_8254_params, + fill_fsps_pm_timer_params, + fill_fsps_pcie_params, + fill_fsps_misc_power_params, + fill_fsps_ufs_params, + fill_fsps_ai_params, + fill_fsps_irq_params, + fill_fsps_pci_ssid_params, + }; + + for (size_t i = 0; i < ARRAY_SIZE(fill_fsps_params); i++) + fill_fsps_params[i](s_cfg, config); +} + +/* UPD parameters to be initialized before SiliconInit */ +void platform_fsp_silicon_init_params_cb(FSPS_UPD *supd) +{ + struct soc_intel_lnl_dev_config *config; + FSP_S_CONFIG *s_cfg = &supd->FspsConfig; + FSPS_ARCH2_UPD *s_arch_cfg = &supd->FspsArchUpd; + + config = config_of_soc(); + arch_silicon_init_params(s_arch_cfg); + soc_silicon_init_params(s_cfg, config); + mainboard_silicon_init_params(s_cfg); +} + +/* + * Callbacks for SoC/Mainboard specific overrides for FspMultiPhaseSiInit + * This platform supports below MultiPhaseSIInit Phase(s): + * Phase | FSP return point | Purpose + * ------- + ------------------------------------------------ + ------------------------------- + * 1 | After TCSS initialization completed | for TCSS specific init + * 2 | Before BIOS Reset CPL is set by FSP-S | for CPU specific init + */ +void platform_fsp_silicon_multi_phase_init_cb(uint32_t phase_index) +{ + switch (phase_index) { + case 1: + /* TCSS specific initialization here */ + printk(BIOS_DEBUG, "FSP MultiPhaseSiInit %s/%s called\n", + __FILE__, __func__); + + if (CONFIG(SOC_INTEL_COMMON_BLOCK_TCSS)) { + const config_t *config = config_of_soc(); + tcss_configure(config->typec_aux_bias_pads); + } + break; + case 2: + /* CPU specific initialization here */ + printk(BIOS_DEBUG, "FSP MultiPhaseSiInit %s/%s called\n", + __FILE__, __func__); + before_post_cpus_init(); + /* Enable BIOS Reset CPL */ + enable_bios_reset_cpl(); + break; + default: + break; + } +} + +/* Mainboard GPIO Configuration */ +__weak void mainboard_silicon_init_params(FSP_S_CONFIG *s_cfg) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} diff --git a/src/soc/intel/lnl_dev/lunarlake/gpio.c b/src/soc/intel/lnl_dev/lunarlake/gpio.c new file mode 100644 index 0000000..4fd149a --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/gpio.c @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <intelblocks/gpio.h> +#include <intelblocks/pcr.h> +#include <soc/pcr_ids.h> +#include <soc/pmc.h> + +static const struct reset_mapping rst_map[] = { + { .logical = PAD_CFG0_LOGICAL_RESET_RSMRST, .chipset = 0U << 30 }, + { .logical = PAD_CFG0_LOGICAL_RESET_DEEP, .chipset = 1U << 30 }, + { .logical = PAD_CFG0_LOGICAL_RESET_PLTRST, .chipset = 2U << 30 }, +}; +static const struct reset_mapping rst_map_com3[] = { + { .logical = PAD_CFG0_LOGICAL_RESET_PWROK, .chipset = 0U << 30 }, + { .logical = PAD_CFG0_LOGICAL_RESET_DEEP, .chipset = 1U << 30 }, + { .logical = PAD_CFG0_LOGICAL_RESET_PLTRST, .chipset = 2U << 30 }, + { .logical = PAD_CFG0_LOGICAL_RESET_RSMRST, .chipset = 3U << 30 }, +}; + +/* + * The GPIO pinctrl driver for Lunar Lake on Linux expects 32 GPIOs per pad + * group, regardless of whether or not there is a physical pad for each + * exposed GPIO number. + * + * This results in the OS having a sparse GPIO map, and devices that need + * to export an ACPI GPIO must use the OS expected number. + * + * Not all pins are usable as GPIO and those groups do not have a pad base. + */ +static const struct pad_group lnl_community0_groups[] = { + INTEL_GPP_BASE(GPP_V0, GPP_V0, GPP_V23, 0), /* GPP_V */ + INTEL_GPP_BASE(GPP_V0, GPP_C0, GPP_C23, 32), /* GPP_C */ +}; + +static const struct pad_group lnl_community1_groups[] = { + INTEL_GPP_BASE(GPP_F0, GPP_F0, GPP_GSPI0A_CLK_LOOPBK, 0), /* GPP_F */ + INTEL_GPP_BASE(GPP_F0, GPP_E0, GPP_THC0_GSPI_CLK_LPBK, 32), /* GPP_E */ + INTEL_GPP(GPP_F0, GPP_JTAG_ON, GPP_JTAG_TRST_B), /* GPP_JTAG */ +}; + +static const struct pad_group lnl_community3_groups[] = { + INTEL_GPP_BASE(GPP_A0, GPP_A0, GPP_A15, 0), /* GPP_A */ + INTEL_GPP(GPP_A0, GPP_SPI0_IO_2, GPP_SPI0_CLK_LOOPBK), /* GPP_SPI0 */ + INTEL_GPP_BASE(GPP_A0, GPP_H0, GPP_ISHI3C1_CLK_LOOPBK, 32), /* GPP_H */ +}; + +static const struct pad_group lnl_community4_groups[] = { + INTEL_GPP_BASE(GPP_S0, GPP_S0, GPP_S7, 0), /* GPP_S */ +}; + +static const struct pad_group lnl_community5_groups[] = { + INTEL_GPP_BASE(GPP_B0, GPP_B0, GPP_ACI3C0_CLK_LPBK, 0), /* GPP_B */ + INTEL_GPP_BASE(GPP_B0, GPP_D0, GPP_D23, 32), /* GPP_D */ + INTEL_GPP(GPP_B0, GPP_VGPIO0, GPP_VGPIO17), /* GPP_VGPIO0 */ +}; + +static const struct pad_community lnl_communities[] = { + [COMM_0] = { /* GPP V,C */ + .port = PID_GPIOCOM0, + .first_pad = GPIO_COM0_START, + .last_pad = GPIO_COM0_END, + .num_gpi_regs = NUM_GPIO_COM0_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPP_BTA", + .acpi_path = "\_SB.PCI0.GPI0", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = lnl_community0_groups, + .num_groups = ARRAY_SIZE(lnl_community0_groups), + }, + [COMM_1] = { /* GPP F, E , JTAG*/ + .port = PID_GPIOCOM1, + .first_pad = GPIO_COM1_START, + .last_pad = GPIO_COM1_END, + .num_gpi_regs = NUM_GPIO_COM1_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPP_SDH", + .acpi_path = "\_SB.PCI0.GPI1", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = lnl_community1_groups, + .num_groups = ARRAY_SIZE(lnl_community1_groups), + }, + [COMM_3] = { /* GPP H, A, SPI0, VGPIO3 */ + .port = PID_GPIOCOM3, + .first_pad = GPIO_COM3_START, + .last_pad = GPIO_COM3_END, + .num_gpi_regs = NUM_GPIO_COM3_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPD", + .acpi_path = "\_SB.PCI0.GPI3", + .reset_map = rst_map_com3, + .num_reset_vals = ARRAY_SIZE(rst_map_com3), + .groups = lnl_community3_groups, + .num_groups = ARRAY_SIZE(lnl_community3_groups), + }, + [COMM_4] = { /* GPP S */ + .port = PID_GPIOCOM4, + .first_pad = GPIO_COM4_START, + .last_pad = GPIO_COM4_END, + .num_gpi_regs = NUM_GPIO_COM4_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPP_FCE", + .acpi_path = "\_SB.PCI0.GPI4", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = lnl_community4_groups, + .num_groups = ARRAY_SIZE(lnl_community4_groups), + }, + [COMM_5] = { /* GPP B, D, VGPIO0 */ + .port = PID_GPIOCOM5, + .first_pad = GPIO_COM5_START, + .last_pad = GPIO_COM5_END, + .num_gpi_regs = NUM_GPIO_COM5_GPI_REGS, + .pad_cfg_base = PAD_CFG_BASE, + .host_own_reg_0 = HOSTSW_OWN_REG_0, + .gpi_int_sts_reg_0 = GPI_INT_STS_0, + .gpi_int_en_reg_0 = GPI_INT_EN_0, + .gpi_smi_sts_reg_0 = GPI_SMI_STS_0, + .gpi_smi_en_reg_0 = GPI_SMI_EN_0, + .max_pads_per_group = GPIO_MAX_NUM_PER_GROUP, + .name = "GPP_RSPI0", + .acpi_path = "\_SB.PCI0.GPI5", + .reset_map = rst_map, + .num_reset_vals = ARRAY_SIZE(rst_map), + .groups = lnl_community5_groups, + .num_groups = ARRAY_SIZE(lnl_community5_groups), + } +}; + +const struct pad_community *soc_gpio_get_community(size_t *num_communities) +{ + *num_communities = ARRAY_SIZE(lnl_communities); + return lnl_communities; +} + +const struct pmc_to_gpio_route *soc_pmc_gpio_routes(size_t *num) +{ + static const struct pmc_to_gpio_route routes[] = { + { PMC_GPP_V, GPP_V }, + { PMC_GPP_C, GPP_C }, + { PMC_GPP_F, GPP_F }, + { PMC_GPP_E, GPP_E }, + { PMC_GPP_A, GPP_A }, + { PMC_GPP_H, GPP_H }, + { PMC_GPP_S, GPP_S }, + { PMC_GPP_B, GPP_B }, + { PMC_GPP_D, GPP_D }, + }; + *num = ARRAY_SIZE(routes); + return routes; +} diff --git a/src/soc/intel/lnl_dev/lunarlake/include/gpio_soc_defs.h b/src/soc/intel/lnl_dev/lunarlake/include/gpio_soc_defs.h new file mode 100644 index 0000000..1a88a96 --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/include/gpio_soc_defs.h @@ -0,0 +1,343 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_LUNARLAKE_GPIO_SOC_DEFS_H_ +#define _SOC_LUNARLAKE_GPIO_SOC_DEFS_H_ + +/* + * Most of the fixed numbers and macros are based on the GPP groups. + * The GPIO groups are accessed through register blocks called + * communities. + */ +/* GPIO COMM 0 */ +#define GPP_V 0x0 +#define GPP_C 0x1 +/* GPIO COMM 1 */ +#define GPP_F 0x2 +#define GPP_E 0x3 +/* GPIO COMM 3 */ +#define GPP_A 0x4 +#define GPP_H 0x5 +/* GPIO COMM 4 */ +#define GPP_S 0x6 +/* GPIO COMM 5 */ +#define GPP_B 0x7 +#define GPP_D 0x8 + +#define GPIO_MAX_NUM_PER_GROUP 26 + +#define COMM_0 0 +#define COMM_1 1 +#define COMM_3 2 +#define COMM_4 3 +#define COMM_5 4 +/* + * GPIOs are ordered monotonically increasing to match ACPI/OS driver. + */ + +/* Group V */ +#define GPP_V0 0 +#define GPP_V1 1 +#define GPP_V2 2 +#define GPP_V3 3 +#define GPP_V4 4 +#define GPP_V5 5 +#define GPP_V6 6 +#define GPP_V7 7 +#define GPP_V8 8 +#define GPP_V9 9 +#define GPP_V10 10 +#define GPP_V11 11 +#define GPP_V12 12 +#define GPP_V13 13 +#define GPP_V14 14 +#define GPP_V15 15 +#define GPP_V16 16 +#define GPP_V17 17 +#define GPP_V18 18 +#define GPP_V19 19 +#define GPP_V20 20 +#define GPP_V21 21 +#define GPP_V22 22 +#define GPP_V23 23 + +/* Group C */ +#define GPP_C0 24 +#define GPP_C1 25 +#define GPP_C2 26 +#define GPP_C3 27 +#define GPP_C4 28 +#define GPP_C5 29 +#define GPP_C6 30 +#define GPP_C7 31 +#define GPP_C8 32 +#define GPP_C9 33 +#define GPP_C10 34 +#define GPP_C11 35 +#define GPP_C12 36 +#define GPP_C13 37 +#define GPP_C14 38 +#define GPP_C15 39 +#define GPP_C16 40 +#define GPP_C17 41 +#define GPP_C18 42 +#define GPP_C19 43 +#define GPP_C20 44 +#define GPP_C21 45 +#define GPP_C22 46 +#define GPP_C23 47 + +#define GPIO_COM0_START GPP_V0 +#define GPIO_COM0_END GPP_C23 +#define NUM_GPIO_COM0_PADS (GPP_C23 - GPP_V0 + 1) + +/* Group F */ +#define GPP_F0 48 +#define GPP_F1 49 +#define GPP_F2 50 +#define GPP_F3 51 +#define GPP_F4 52 +#define GPP_F5 53 +#define GPP_F6 54 +#define GPP_F7 55 +#define GPP_F8 56 +#define GPP_F9 57 +#define GPP_F10 58 +#define GPP_F11 59 +#define GPP_F12 60 +#define GPP_F13 61 +#define GPP_F14 62 +#define GPP_F15 63 +#define GPP_F16 64 +#define GPP_F17 65 +#define GPP_F18 66 +#define GPP_F19 67 +#define GPP_F20 68 +#define GPP_F21 69 +#define GPP_F22 70 +#define GPP_F23 71 +#define GPP_THC1_GSPI1_CLK_LPBK 72 +#define GPP_GSPI0A_CLK_LOOPBK 73 + + +/* Group E */ +#define GPP_E0 74 +#define GPP_E1 75 +#define GPP_E2 76 +#define GPP_E3 77 +#define GPP_E4 78 +#define GPP_E5 79 +#define GPP_E6 80 +#define GPP_E7 81 +#define GPP_E8 82 +#define GPP_E9 83 +#define GPP_E10 84 +#define GPP_E11 85 +#define GPP_E12 86 +#define GPP_E13 87 +#define GPP_E14 88 +#define GPP_E15 89 +#define GPP_E16 90 +#define GPP_E17 91 +#define GPP_E18 92 +#define GPP_E19 93 +#define GPP_E20 94 +#define GPP_E21 95 +#define GPP_E22 96 +#define GPP_E23 97 +#define GPP_THC0_GSPI_CLK_LPBK 98 + +/* Group JTAG */ +#define GPP_JTAG_ON 99 +#define GPP_JTAG_PWRGD 100 +#define GPP_JTAG_MBPB0 101 +#define GPP_JTAG_MBPB1 102 +#define GPP_JTAG_MBPB2 103 +#define GPP_JTAG_MBPB3 104 +#define GPP_JTAG_TD0 105 +#define GPP_PRDY_B 106 +#define GPP_PREQ_B 107 +#define GPP_JTAG_TDI 108 +#define GPP_JTAG_TMS 109 +#define GPP_JTAG_TCK 110 +#define GPP_DBG_PMODE 111 +#define GPP_JTAG_TRST_B 112 + +#define GPIO_COM1_START GPP_F0 +#define GPIO_COM1_END GPP_JTAG_TRST_B +#define NUM_GPIO_COM1_PADS (GPP_JTAG_TRST_B - GPP_F0 + 1) + +/* Group A */ +#define GPP_A0 113 +#define GPP_A1 114 +#define GPP_A2 115 +#define GPP_A3 116 +#define GPP_A4 117 +#define GPP_A5 118 +#define GPP_A6 119 +#define GPP_A7 120 +#define GPP_A8 121 +#define GPP_A9 122 +#define GPP_A10 123 +#define GPP_A11 124 +#define GPP_A12 125 +#define GPP_A13 126 +#define GPP_A14 127 +#define GPP_A15 128 + + +/* Group SPI0 */ +#define GPP_SPI0_IO_2 129 +#define GPP_SPI0_IO_3 130 +#define GPP_SPI0_MOSI_IO_0 131 +#define GPP_SPI0_MOSI_IO_1 132 +#define GPP_SPI0_TPM_CS_B 133 +#define GPP_SPI0_FLASH_0_CS_B 134 +#define GPP_SPI0_FLASH_1_CS_B 135 +#define GPP_SPI0_CLK 136 +#define GPP_ESPI0_CLK_LOOPBK 137 +#define GPP_SPI0_CLK_LOOPBK 138 + +/* Group H */ +#define GPP_H0 139 +#define GPP_H1 140 +#define GPP_H2 141 +#define GPP_H3 142 +#define GPP_H4 143 +#define GPP_H5 144 +#define GPP_H6 145 +#define GPP_H7 146 +#define GPP_H8 147 +#define GPP_H9 148 +#define GPP_H10 149 +#define GPP_H11 150 +#define GPP_H12 151 +#define GPP_H13 152 +#define GPP_H14 153 +#define GPP_H15 154 +#define GPP_H16 155 +#define GPP_H17 156 +#define GPP_H18 157 +#define GPP_H19 158 +#define GPP_H20 159 +#define GPP_H21 160 +#define GPP_H22 161 +#define GPP_LPI3C1_CLK_LPBK 162 +#define GPP_LPI3C0_CLK_LPBK 163 +#define GPP_ISHI3C1_CLK_LOOPBK 164 + + +/* Group vGPIO3 */ +#define GPP_VGPIO3_USB0 165 +#define GPP_VGPIO3_USB1 166 +#define GPP_VGPIO3_USB2 167 +#define GPP_VGPIO3_USB3 168 +#define GPP_VGPIO3_USB4 169 +#define GPP_VGPIO3_USB5 170 +#define GPP_VGPIO3_USB6 171 +#define GPP_VGPIO3_USB7 172 +#define GPP_VGPIO3_TS0 173 +#define GPP_VGPIO3_TS1 174 +#define GPP_VGPIO3_THC0 175 +#define GPP_VGPIO3_THC1 176 +#define GPP_VGPIO3_THC2 177 +#define GPP_VGPIO3_THC3 178 + +#define GPIO_COM3_START GPP_A0 +#define GPIO_COM3_END GPP_VGPIO3_THC3 +#define NUM_GPIO_COM3_PADS (GPP_A0 - GPP_VGPIO3_THC3 + 1) + +/* Group S */ +#define GPP_S0 179 +#define GPP_S1 180 +#define GPP_S2 181 +#define GPP_S3 182 +#define GPP_S4 183 +#define GPP_S5 184 +#define GPP_S6 185 +#define GPP_S7 186 + +#define GPIO_COM4_START GPP_S0 +#define GPIO_COM4_END GPP_S7 +#define NUM_GPIO_COM4_PADS (GPP_S7 - GPP_S0 + 1) + +/* Group B */ +#define GPP_B0 187 +#define GPP_B1 188 +#define GPP_B2 189 +#define GPP_B3 190 +#define GPP_B4 191 +#define GPP_B5 192 +#define GPP_B6 193 +#define GPP_B7 194 +#define GPP_B8 195 +#define GPP_B9 196 +#define GPP_B10 197 +#define GPP_B11 198 +#define GPP_B12 199 +#define GPP_B13 200 +#define GPP_B14 201 +#define GPP_B15 202 +#define GPP_B16 203 +#define GPP_B17 204 +#define GPP_B18 205 +#define GPP_B19 206 +#define GPP_B20 207 +#define GPP_B21 208 +#define GPP_B22 209 +#define GPP_B23 210 +#define GPP_ACI3C0_CLK_LPBK 211 + +/* Group D */ +#define GPP_D0 212 +#define GPP_D1 213 +#define GPP_D2 214 +#define GPP_D3 215 +#define GPP_D4 216 +#define GPP_D5 217 +#define GPP_D6 218 +#define GPP_D7 219 +#define GPP_D8 220 +#define GPP_D9 221 +#define GPP_D10 222 +#define GPP_D11 223 +#define GPP_D12 224 +#define GPP_D13 225 +#define GPP_D14 226 +#define GPP_D15 227 +#define GPP_D16 228 +#define GPP_D17 229 +#define GPP_D18 230 +#define GPP_D19 231 +#define GPP_D20 232 +#define GPP_D21 233 +#define GPP_D22 234 +#define GPP_D23 235 + +/* Group vGPIO */ +#define GPP_VGPIO0 236 +#define GPP_VGPIO1 237 +#define GPP_VGPIO2 238 +#define GPP_VGPIO3 239 +#define GPP_VGPIO4 240 +#define GPP_VGPIO5 241 +#define GPP_VGPIO6 242 +#define GPP_VGPIO7 243 +#define GPP_VGPIO8 244 +#define GPP_VGPIO9 245 +#define GPP_VGPIO10 246 +#define GPP_VGPIO11 247 +#define GPP_VGPIO12 248 +#define GPP_VGPIO13 249 +#define GPP_VGPIO14 250 +#define GPP_VGPIO15 251 +#define GPP_VGPIO16 252 +#define GPP_VGPIO17 253 + +#define GPIO_COM5_START GPP_B0 +#define GPIO_COM5_END GPP_VGPIO17 +#define NUM_GPIO_COM5_PADS (GPP_VGPIO17 - GPP_B0 + 1) + +#define TOTAL_GPIO_COMM (COMM_5 + 1) +#define TOTAL_PADS (GPIO_COM5_END + 1) + +#endif //_SOC_LUNARLAKE_GPIO_SOC_DEFS_H_ diff --git a/src/soc/intel/lnl_dev/lunarlake/include/gpio_std_defs.h b/src/soc/intel/lnl_dev/lunarlake/include/gpio_std_defs.h new file mode 100644 index 0000000..f1027a8 --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/include/gpio_std_defs.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_LUNARLAKE_GPIO_STD_DEFS_H_ +#define _SOC_LUNARLAKE_GPIO_STD_DEFS_H_ + +#ifndef __ACPI__ +#include <stddef.h> +#endif +#include <gpio_soc_defs.h> + +#define GPIO_NUM_PAD_CFG_REGS 4 /* DW0, DW1, DW2, DW3 */ + +#define NUM_GPIO_COMx_GPI_REGS(n) \ + (ALIGN_UP((n), GPIO_MAX_NUM_PER_GROUP) / GPIO_MAX_NUM_PER_GROUP) + +#define NUM_GPIO_COM0_GPI_REGS NUM_GPIO_COMx_GPI_REGS(NUM_GPIO_COM0_PADS) +#define NUM_GPIO_COM1_GPI_REGS NUM_GPIO_COMx_GPI_REGS(NUM_GPIO_COM1_PADS) +#define NUM_GPIO_COM3_GPI_REGS NUM_GPIO_COMx_GPI_REGS(NUM_GPIO_COM3_PADS) +#define NUM_GPIO_COM4_GPI_REGS NUM_GPIO_COMx_GPI_REGS(NUM_GPIO_COM4_PADS) +#define NUM_GPIO_COM5_GPI_REGS NUM_GPIO_COMx_GPI_REGS(NUM_GPIO_COM5_PADS) + +#define NUM_GPI_STATUS_REGS \ + ((NUM_GPIO_COM0_GPI_REGS) +\ + (NUM_GPIO_COM1_GPI_REGS) +\ + (NUM_GPIO_COM3_GPI_REGS) +\ + (NUM_GPIO_COM4_GPI_REGS) +\ + (NUM_GPIO_COM5_GPI_REGS)) + +/* + * IOxAPIC IRQs for the GPIOs + */ + +/* Group A */ +#define GPP_A0_IRQ 0x71 +#define GPP_A1_IRQ 0x72 +#define GPP_A2_IRQ 0x73 +#define GPP_A3_IRQ 0x74 +#define GPP_A4_IRQ 0x75 +#define GPP_A5_IRQ 0x76 +#define GPP_A6_IRQ 0x77 +#define GPP_A7_IRQ 0x18 +#define GPP_A8_IRQ 0x19 +#define GPP_A9_IRQ 0x1A +#define GPP_A10_IRQ 0x1B +#define GPP_A11_IRQ 0x1C +#define GPP_A12_IRQ 0x1D +#define GPP_A13_IRQ 0x1E +#define GPP_A14_IRQ 0x1F +#define GPP_A15_IRQ 0x20 + +/* Group B */ +#define GPP_B0_IRQ 0x18 +#define GPP_B1_IRQ 0x19 +#define GPP_B2_IRQ 0x1A +#define GPP_B3_IRQ 0x1B +#define GPP_B4_IRQ 0x1C +#define GPP_B5_IRQ 0x1D +#define GPP_B6_IRQ 0x1E +#define GPP_B7_IRQ 0x1F +#define GPP_B8_IRQ 0x20 +#define GPP_B9_IRQ 0x21 +#define GPP_B10_IRQ 0x22 +#define GPP_B11_IRQ 0x23 +#define GPP_B12_IRQ 0x24 +#define GPP_B13_IRQ 0x25 +#define GPP_B14_IRQ 0x26 +#define GPP_B15_IRQ 0x27 +#define GPP_B16_IRQ 0x28 +#define GPP_B17_IRQ 0x29 +#define GPP_B18_IRQ 0x2A +#define GPP_B19_IRQ 0x2B +#define GPP_B20_IRQ 0x2C +#define GPP_B21_IRQ 0x2D +#define GPP_B22_IRQ 0x2E +#define GPP_B23_IRQ 0x2F + +/* Group C */ +#define GPP_C0_iIRQ 0x6E +#define GPP_C1_IRQ 0x6F +#define GPP_C2_IRQ 0x70 +#define GPP_C3_IRQ 0x71 +#define GPP_C4_IRQ 0x72 +#define GPP_C5_IRQ 0x73 +#define GPP_C6_IRQ 0x74 +#define GPP_C7_IRQ 0x75 +#define GPP_C8_IRQ 0x76 +#define GPP_C9_IRQ 0x77 +#define GPP_C10_IRQ 0x18 +#define GPP_C11_IRQ 0x19 +#define GPP_C12_IRQ 0x1A +#define GPP_C13_IRQ 0x1B +#define GPP_C14_IRQ 0x1C +#define GPP_C15_IRQ 0x1D +#define GPP_C16_IRQ 0x1E +#define GPP_C17_IRQ 0x1F +#define GPP_C18_IRQ 0x20 +#define GPP_C19_IRQ 0x21 +#define GPP_C20_IRQ 0x22 +#define GPP_C21_IRQ 0x23 +#define GPP_C22_IRQ 0x24 +#define GPP_C23_IRQ 0x25 + +/* Group D */ +#define GPP_D0_IRQ 0x59 +#define GPP_D1_IRQ 0x5A +#define GPP_D2_IRQ 0x5B +#define GPP_D3_IRQ 0x5C +#define GPP_D4_IRQ 0x5D +#define GPP_D5_IRQ 0x5E +#define GPP_D6_IRQ 0x5F +#define GPP_D7_IRQ 0x60 +#define GPP_D8_IRQ 0x61 +#define GPP_D9_IRQ 0x62 +#define GPP_D10_IRQ 0x63 +#define GPP_D11_IRQ 0x64 +#define GPP_D12_IRQ 0x65 +#define GPP_D13_IRQ 0x66 +#define GPP_D14_IRQ 0x67 +#define GPP_D15_IRQ 0x68 +#define GPP_D16_IRQ 0x69 +#define GPP_D17_IRQ 0x6A +#define GPP_D18_IRQ 0x6B +#define GPP_D19_IRQ 0x6C +#define GPP_D20_IRQ 0x6D +#define GPP_D21_IRQ 0x6E +#define GPP_D22_IRQ 0x6F +#define GPP_D23_IRQ 0x70 +#define GPP_D24_IRQ 0x71 + +/* Group E */ +#define GPP_E0_IRQ 0x5A +#define GPP_E1_IRQ 0x5B +#define GPP_E2_IRQ 0x5C +#define GPP_E3_IRQ 0x5D +#define GPP_E4_IRQ 0x5E +#define GPP_E5_IRQ 0x5F +#define GPP_E6_IRQ 0x60 +#define GPP_E7_IRQ 0x61 +#define GPP_E8_IRQ 0x62 +#define GPP_E9_IRQ 0x63 +#define GPP_E10_IRQ 0x64 +#define GPP_E11_IRQ 0x65 +#define GPP_E12_IRQ 0x66 +#define GPP_E13_IRQ 0x67 +#define GPP_E14_IRQ 0x68 +#define GPP_E15_IRQ 0x69 +#define GPP_E16_IRQ 0x6A +#define GPP_E17_IRQ 0x6B +#define GPP_E18_IRQ 0x6C +#define GPP_E19_IRQ 0x6D +#define GPP_E20_IRQ 0x6E +#define GPP_E21_IRQ 0x6F +#define GPP_E22_IRQ 0x70 + +/* Group F */ +#define GPP_F0_IRQ 0x42 +#define GPP_F1_IRQ 0x43 +#define GPP_F2_IRQ 0x44 +#define GPP_F3_IRQ 0x45 +#define GPP_F4_IRQ 0x46 +#define GPP_F5_IRQ 0x47 +#define GPP_F6_IRQ 0x48 +#define GPP_F7_IRQ 0x49 +#define GPP_F8_IRQ 0x4A +#define GPP_F9_IRQ 0x4B +#define GPP_F10_IRQ 0x4C +#define GPP_F11_IRQ 0x4D +#define GPP_F12_IRQ 0x4E +#define GPP_F13_IRQ 0x4F +#define GPP_F14_IRQ 0x50 +#define GPP_F15_IRQ 0x51 +#define GPP_F16_IRQ 0x52 +#define GPP_F17_IRQ 0x53 +#define GPP_F18_IRQ 0x54 +#define GPP_F19_IRQ 0x55 +#define GPP_F20_IRQ 0x56 +#define GPP_F21_IRQ 0x57 +#define GPP_F22_IRQ 0x58 +#define GPP_F23_IRQ 0x59 + +/* Group H */ +#define GPP_H0_IRQ 0x21 +#define GPP_H1_IRQ 0x22 +#define GPP_H2_IRQ 0x23 +#define GPP_H3_IRQ 0x24 +#define GPP_H4_IRQ 0x25 +#define GPP_H5_IRQ 0x26 +#define GPP_H6_IRQ 0x27 +#define GPP_H7_IRQ 0x28 +#define GPP_H8_IRQ 0x29 +#define GPP_H9_IRQ 0x2A +#define GPP_H10_IRQ 0x2B +#define GPP_H11_IRQ 0x2C +#define GPP_H12_IRQ 0x2D +#define GPP_H13_IRQ 0x2E +#define GPP_H14_IRQ 0x2F +#define GPP_H15_IRQ 0x30 +#define GPP_H16_IRQ 0x31 +#define GPP_H17_IRQ 0x32 +#define GPP_H18_IRQ 0x33 +#define GPP_H19_IRQ 0x34 +#define GPP_H20_IRQ 0x35 +#define GPP_H21_IRQ 0x36 +#define GPP_H22_IRQ 0x37 + +/* Group S */ +#define GPP_S0_IRQ 0x71 +#define GPP_S1_IRQ 0x72 +#define GPP_S2_IRQ 0x73 +#define GPP_S3_IRQ 0x74 +#define GPP_S4_IRQ 0x75 +#define GPP_S5_IRQ 0x76 +#define GPP_S6_IRQ 0x77 +#define GPP_S7_IRQ 0x18 + +/* Group GPD */ +#define GPD0_IRQ 0x60 +#define GPD1_IRQ 0x61 +#define GPD2_IRQ 0x62 +#define GPD3_IRQ 0x63 +#define GPD4_IRQ 0x64 +#define GPD5_IRQ 0x65 +#define GPD6_IRQ 0x66 +#define GPD7_IRQ 0x67 +#define GPD8_IRQ 0x68 +#define GPD9_IRQ 0x69 +#define GPD10_IRQ 0x6A +#define GPD11_IRQ 0x6B + +/* Register defines. */ +#define GPIO_MISCCFG 0x10 +#define GPE_DW_SHIFT 8 +#define GPE_DW_MASK 0xfff00 +#define HOSTSW_OWN_REG_0 0xb0 +#define GPI_INT_STS_0 0x100 +#define GPI_INT_EN_0 0x110 +#define GPI_SMI_STS_0 0x180 +#define GPI_SMI_EN_0 0x1A0 +#define PAD_CFG_BASE 0x600 + +#endif //_SOC_LUNARLAKE_GPIO_DEFS_LNL_H_ diff --git a/src/soc/intel/lnl_dev/lunarlake/pcie_rp.c b/src/soc/intel/lnl_dev/lunarlake/pcie_rp.c new file mode 100644 index 0000000..2f08a8b --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/pcie_rp.c @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <intelblocks/pcie_rp.h> +#include <soc/pci_devs.h> +#include <soc/pcie.h> +#include <soc/soc_info.h> +#include <console/console.h> + +static const struct pcie_rp_group lnlm_rp_groups[] = { + { .slot = PCI_DEV_SLOT_PCIE_1, .count = 8, .lcap_port_base = 1 }, + { 0 } +}; + +const struct pcie_rp_group *get_pcie_rp_table(void) +{ + printk(BIOS_INFO, "soc_info: LNLM RP table is selected\n"); + return lnlm_rp_groups; +} diff --git a/src/soc/intel/lnl_dev/lunarlake/systemagent.c b/src/soc/intel/lnl_dev/lunarlake/systemagent.c new file mode 100644 index 0000000..56b7f23 --- /dev/null +++ b/src/soc/intel/lnl_dev/lunarlake/systemagent.c @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/ioapic.h> +#include <console/console.h> +#include <cpu/x86/msr.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <delay.h> +#include <intelblocks/cpulib.h> +#include <intelblocks/msr.h> +#include <intelblocks/power_limit.h> +#include <intelblocks/systemagent.h> +#include <soc/iomap.h> +#include <soc/soc_chip.h> +#include <soc/systemagent.h> +#include <soc/powerlimit.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" }, + { 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" }, + // PCH_PRESERVERD covers: + // TraceHub SW BAR, PMC MBAR, SPI BAR0, SerialIo BAR in ACPI mode + // eSPI LGMR BAR, eSPI2 SEGMR BAR, TraceHub MTB BAR, TraceHub FW BAR + // IOE PMC BAR, Tracehub RTIT BAR (SOC), HECI{1,2,3} BAR0 + // see fsp/ClientOneSiliconPkg/Fru/MtlSoc/Include/PchReservedResources.h + { 0, PCH_PRESERVED_BASE_ADDRESS, PCH_PRESERVED_BASE_SIZE, "PCH_RESERVED" }, + }; + + sa_add_fixed_mmio_resources(dev, index, soc_fixed_resources, + ARRAY_SIZE(soc_fixed_resources)); + + /* Add Vt-d resources if VT-d is enabled */ + if ((pci_read_config32(dev, CAPID0_A) & VTD_DISABLE)) + return; + + sa_add_fixed_mmio_resources(dev, index, soc_vtd_resources, + ARRAY_SIZE(soc_vtd_resources)); +} + +/* + * SoC implementation + * + * Perform System Agent Initialization during Ramstage phase. + */ +void soc_systemagent_init(struct device *dev) +{ + struct soc_power_limits_config *soc_config; + const struct device *sa; + uint16_t sa_pci_id; + config_t *config; + + /* Enable Power Aware Interrupt Routing */ + enable_power_aware_intr(); + + /* Enable BIOS Reset CPL */ + enable_bios_reset_cpl(); + + /* Configure turbo power limits 1ms after reset complete bit */ + mdelay(1); + config = (config_t *)config_of_soc(); + + /* Get System Agent PCI ID */ + sa = pcidev_path_on_root(PCI_DEVFN_ROOT); + sa_pci_id = sa ? pci_read_config16(sa, PCI_DEVICE_ID) : 0xFFFF; + + /* Choose a power limits configuration based on the SoC SKU type, + * differentiated here based on SA PCI ID. */ + switch (sa_pci_id) { + case PCI_DID_INTEL_LNL_M_ID: + soc_config = &config->power_limits_config[LNL_M_POWER_LIMITS]; + break; + default: + printk(BIOS_ERR, "unknown SA ID: 0x%4x, skipping power limits configuration\n", + sa_pci_id); + return; + } + + /* UPDATEME: Need to enable later */ + set_power_limits(MOBILE_SKU_PL1_TIME_SEC, soc_config); +} + diff --git a/src/soc/intel/lnl_dev/me.c b/src/soc/intel/lnl_dev/me.c new file mode 100644 index 0000000..ea94902 --- /dev/null +++ b/src/soc/intel/lnl_dev/me.c @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <intelblocks/cse.h> +#include <console/console.h> +#include <soc/me.h> +#include <stdint.h> + +/* Host Firmware Status Register 2 */ +union me_hfsts2 { + uint32_t data; + struct { + uint32_t nftp_load_failure : 1; + uint32_t icc_prog_status : 2; + uint32_t invoke_mebx : 1; + uint32_t cpu_replaced : 1; + uint32_t rsvd0 : 1; + uint32_t mfs_failure : 1; + uint32_t warm_reset_rqst : 1; + uint32_t cpu_replaced_valid : 1; + uint32_t low_power_state : 1; + uint32_t me_power_gate : 1; + uint32_t ipu_needed : 1; + uint32_t forced_safe_boot : 1; + uint32_t rsvd1 : 2; + uint32_t listener_change : 1; + uint32_t status_data : 8; + uint32_t current_pmevent : 4; + uint32_t phase : 4; + } __packed fields; +}; + +/* Host Firmware Status Register 4 */ +union me_hfsts4 { + uint32_t data; + struct { + uint32_t rsvd0 : 9; + uint32_t enforcement_flow : 1; + uint32_t sx_resume_type : 1; + uint32_t rsvd1 : 1; + uint32_t tpms_disconnected : 1; + uint32_t rvsd2 : 1; + uint32_t fwsts_valid : 1; + uint32_t boot_guard_self_test : 1; + uint32_t rsvd3 : 16; + } __packed fields; +}; + +/* Host Firmware Status Register 5 */ +union me_hfsts5 { + uint32_t data; + struct { + uint32_t acm_active : 1; + uint32_t valid : 1; + uint32_t result_code_source : 1; + uint32_t error_status_code : 5; + uint32_t acm_done_sts : 1; + uint32_t timeout_count : 7; + uint32_t scrtm_indicator : 1; + uint32_t inc_boot_guard_acm : 4; + uint32_t inc_key_manifest : 4; + uint32_t inc_boot_policy : 4; + uint32_t rsvd0 : 2; + uint32_t start_enforcement : 1; + } __packed fields; +}; + +/* Host Firmware Status Register 6 */ +union me_hfsts6 { + uint32_t data; + struct { + uint32_t force_boot_guard_acm : 1; + uint32_t cpu_debug_disable : 1; + uint32_t bsp_init_disable : 1; + uint32_t protect_bios_env : 1; + uint32_t rsvd0 : 2; + uint32_t error_enforce_policy : 2; + uint32_t measured_boot : 1; + uint32_t verified_boot : 1; + uint32_t boot_guard_acmsvn : 4; + uint32_t kmsvn : 4; + uint32_t bpmsvn : 4; + uint32_t key_manifest_id : 4; + uint32_t boot_policy_status : 1; + uint32_t error : 1; + uint32_t boot_guard_disable : 1; + uint32_t fpf_disable : 1; + uint32_t fpf_soc_lock : 1; + uint32_t txt_support : 1; + } __packed fields; +}; + +static void dump_me_status(void *unused) +{ + union me_hfsts1 hfsts1; + union me_hfsts2 hfsts2; + union me_hfsts3 hfsts3; + union me_hfsts4 hfsts4; + union me_hfsts5 hfsts5; + union me_hfsts6 hfsts6; + + if (!is_cse_enabled()) + return; + + hfsts1.data = me_read_config32(PCI_ME_HFSTS1); + hfsts2.data = me_read_config32(PCI_ME_HFSTS2); + hfsts3.data = me_read_config32(PCI_ME_HFSTS3); + hfsts4.data = me_read_config32(PCI_ME_HFSTS4); + hfsts5.data = me_read_config32(PCI_ME_HFSTS5); + hfsts6.data = me_read_config32(PCI_ME_HFSTS6); + + printk(BIOS_DEBUG, "ME: HFSTS1 : 0x%08X\n", hfsts1.data); + printk(BIOS_DEBUG, "ME: HFSTS2 : 0x%08X\n", hfsts2.data); + printk(BIOS_DEBUG, "ME: HFSTS3 : 0x%08X\n", hfsts3.data); + printk(BIOS_DEBUG, "ME: HFSTS4 : 0x%08X\n", hfsts4.data); + printk(BIOS_DEBUG, "ME: HFSTS5 : 0x%08X\n", hfsts5.data); + printk(BIOS_DEBUG, "ME: HFSTS6 : 0x%08X\n", hfsts6.data); + + /* + * Lock Descriptor, and Fuses must be programmed on a + * production system to indicate ME Manufacturing mode is disabled. + */ + printk(BIOS_DEBUG, "ME: Manufacturing Mode : %s\n", + ((hfsts1.fields.mfg_mode == 0) && + (hfsts6.fields.fpf_soc_lock == 1)) ? "NO" : "YES"); + /* + * The SPI Protection Mode bit reflects SPI descriptor + * locked(0) or unlocked(1). + */ + printk(BIOS_DEBUG, "ME: SPI Protection Mode Enabled : %s\n", + hfsts1.fields.mfg_mode ? "NO" : "YES"); + printk(BIOS_DEBUG, "ME: FW Partition Table : %s\n", + hfsts1.fields.fpt_bad ? "BAD" : "OK"); + printk(BIOS_DEBUG, "ME: Bringup Loader Failure : %s\n", + hfsts1.fields.ft_bup_ld_flr ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Firmware Init Complete : %s\n", + hfsts1.fields.fw_init_complete ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Boot Options Present : %s\n", + hfsts1.fields.boot_options_present ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Update In Progress : %s\n", + hfsts1.fields.update_in_progress ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: D0i3 Support : %s\n", + hfsts1.fields.d0i3_support_valid ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Low Power State Enabled : %s\n", + hfsts2.fields.low_power_state ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Replaced : %s\n", + hfsts2.fields.cpu_replaced ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Replacement Valid : %s\n", + hfsts2.fields.cpu_replaced_valid ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: Current Working State : %u\n", + hfsts1.fields.working_state); + printk(BIOS_DEBUG, "ME: Current Operation State : %u\n", + hfsts1.fields.operation_state); + printk(BIOS_DEBUG, "ME: Current Operation Mode : %u\n", + hfsts1.fields.operation_mode); + printk(BIOS_DEBUG, "ME: Error Code : %u\n", + hfsts1.fields.error_code); + printk(BIOS_DEBUG, "ME: Enhanced Debug Mode : %s\n", + hfsts1.fields.invoke_enhance_dbg_mode ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: CPU Debug Disabled : %s\n", + hfsts6.fields.cpu_debug_disable ? "YES" : "NO"); + printk(BIOS_DEBUG, "ME: TXT Support : %s\n", + hfsts6.fields.txt_support ? "YES" : "NO"); +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_EXIT, print_me_fw_version, NULL); +BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_EXIT, dump_me_status, NULL); diff --git a/src/soc/intel/lnl_dev/pmc.c b/src/soc/intel/lnl_dev/pmc.c new file mode 100644 index 0000000..e6e6524 --- /dev/null +++ b/src/soc/intel/lnl_dev/pmc.c @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + + +#include <acpi/acpigen.h> +#include <console/console.h> +#include <device/mmio.h> +#include <device/device.h> +#include <drivers/intel/pmc_mux/chip.h> +#include <intelblocks/acpi.h> +#include <intelblocks/pmc.h> +#include <intelblocks/pmc_ipc.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/rtc.h> +#include <soc/cpu.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/soc_chip.h> +#include <stdint.h> +#include <bootstate.h> +#include <platform_soc_defs.h> + +#define PMC_HID "INTC1026" + +static void config_deep_sX(uint32_t offset, uint32_t mask, int sx, int enable) +{ + uint32_t reg; + uint8_t *pmcbase = pmc_mmio_regs(); + + printk(BIOS_DEBUG, "%sabling Deep S%c\n", + enable ? "En" : "Dis", sx + '0'); + reg = read32(pmcbase + offset); + if (enable) + reg |= mask; + else + reg &= ~mask; + write32(pmcbase + offset, reg); +} + +static void config_deep_s5(int on_ac, int on_dc) +{ + /* Treat S4 the same as S5. */ + config_deep_sX(S4_PWRGATE_POL, S4AC_GATE_SUS, 4, on_ac); + config_deep_sX(S4_PWRGATE_POL, S4DC_GATE_SUS, 4, on_dc); + config_deep_sX(S5_PWRGATE_POL, S5AC_GATE_SUS, 5, on_ac); + config_deep_sX(S5_PWRGATE_POL, S5DC_GATE_SUS, 5, on_dc); +} + +static void config_deep_s3(int on_ac, int on_dc) +{ + config_deep_sX(S3_PWRGATE_POL, S3AC_GATE_SUS, 3, on_ac); + config_deep_sX(S3_PWRGATE_POL, S3DC_GATE_SUS, 3, on_dc); +} + +static void config_deep_sx(uint32_t deepsx_config) +{ + uint32_t reg; + uint8_t *pmcbase = pmc_mmio_regs(); + + reg = read32(pmcbase + DSX_CFG); + reg &= ~DSX_CFG_MASK; + reg |= deepsx_config; + write32(pmcbase + DSX_CFG, reg); +} + +static void soc_pmc_enable(struct device *dev) +{ + const config_t *config = config_of_soc(); + + rtc_init(); + + pmc_set_power_failure_state(true); + pmc_gpe_init(); + + config_deep_s3(config->deep_s3_enable_ac, config->deep_s3_enable_dc); + config_deep_s5(config->deep_s5_enable_ac, config->deep_s5_enable_dc); + config_deep_sx(config->deep_sx_config); +} + +static void soc_pmc_read_resources(struct device *dev) +{ + struct resource *res; + + /* Add the fixed MMIO resource */ + mmio_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", PMC_FILL_SSDT); + + /* + * Part of the PCH's reserved 32 MB MMIO range (0xFC800000 - 0xFE7FFFFF). + * The PMC gets 0xFE000000 - 0xFE00FFFF. + */ + acpigen_write_name("_CRS"); + acpigen_write_resourcetemplate_header(); + acpigen_write_mem32fixed(1, PCH_PWRM_BASE_ADDRESS, PCH_PWRM_BASE_SIZE); + acpigen_write_resourcetemplate_footer(); + + /* Define IPC Write Method */ + if (CONFIG(PMC_IPC_ACPI_INTERFACE)) + pmc_ipc_acpi_fill_ssdt(); + + acpigen_pop_len(); /* PMC Device */ + acpigen_pop_len(); /* Scope */ + + if (CONFIG(SOC_INTEL_COMMON_BLOCK_ACPI_PEP)) { + const struct soc_pmc_lpm lnl_pmc_lpm = { + .num_substates = 8, + .num_req_regs = 6, + .lpm_ipc_offset = 0x1000, + .req_reg_stride = 0x30, + .lpm_enable_mask = get_supported_lpm_mask(), + }; + + generate_acpi_power_engine_with_lpm(&lnl_pmc_lpm); + } + + printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name, + dev_path(dev)); +} + +static void soc_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 + * LNL has its PMC device available for device_operations, it can be + * done from the "ops->init" callback. + */ + pmc_set_acpi_mode(); + + /* + * Disable ACPI PM timer based on Kconfig + * + * Disabling ACPI PM timer is necessary for XTAL OSC shutdown. + * Disabling ACPI PM timer also switches off TCO + */ + if (!CONFIG(USE_PM_ACPI_TIMER)) + setbits8(pmc_mmio_regs() + PCH_PWRM_ACPI_TMR_CTL, ACPI_TIM_DIS); +} + +static void pm1_enable_pwrbtn_smi(void *unused) +{ + /* Enable power button SMI after BS_DEV_INIT_CHIPS (FSP-S) is done. */ + pmc_update_pm1_enable(PWRBTN_EN); +} + +BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, pm1_enable_pwrbtn_smi, NULL); + +/* + * `pmc_final` function is native implementation of equivalent events performed by + * each FSP NotifyPhase() API invocations. + * + * + * Clear PMCON status bits (Global Reset/Power Failure/Host Reset Status bits) + * + * Perform the PMCON status bit clear operation from `.final` + * to cover any such chances where later boot stage requested a global + * reset and PMCON status bit remains set. + */ +static void pmc_final(struct device *dev) +{ + pmc_clear_pmcon_sts(); +} +struct device_operations pmc_ops = { + .read_resources = soc_pmc_read_resources, + .set_resources = noop_set_resources, + .init = soc_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/lnl_dev/pmutil.c b/src/soc/intel/lnl_dev/pmutil.c new file mode 100644 index 0000000..e34c0dd --- /dev/null +++ b/src/soc/intel/lnl_dev/pmutil.c @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Helper functions for dealing with power management registers + * and the differences between PCH variants. + */ + +#define __SIMPLE_DEVICE__ + +#include <acpi/acpi_pm.h> +#include <device/mmio.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_def.h> +#include <console/console.h> +#include <intelblocks/pmclib.h> +#include <intelblocks/rtc.h> +#include <intelblocks/tco.h> +#include <security/vboot/vbnv.h> +#include <soc/espi.h> +#include <soc/gpe.h> +#include <soc/gpio.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include <soc/smbus.h> +#include <soc/soc_chip.h> +#include <types.h> + +/* + * SMI + */ +const char *const *soc_smi_sts_array(size_t *a) +{ + static const char *const smi_sts_bits[] = { + [BIOS_STS_BIT] = "BIOS", + [LEGACY_USB_STS_BIT] = "LEGACY_USB", + [SMI_ON_SLP_EN_STS_BIT] = "SLP_SMI", + [APM_STS_BIT] = "APM", + [SWSMI_TMR_STS_BIT] = "SWSMI_TMR", + [PM1_STS_BIT] = "PM1", + [GPE0_STS_BIT] = "GPE0", + [GPIO_STS_BIT] = "GPI", + [MCSMI_STS_BIT] = "MCSMI", + [DEVMON_STS_BIT] = "DEVMON", + [TCO_STS_BIT] = "TCO", + [PERIODIC_STS_BIT] = "PERIODIC", + [SERIRQ_SMI_STS_BIT] = "SERIRQ_SMI", + [SMBUS_SMI_STS_BIT] = "SMBUS_SMI", + [PCI_EXP_SMI_STS_BIT] = "PCI_EXP_SMI", + [MONITOR_STS_BIT] = "MONITOR", + [SPI_SMI_STS_BIT] = "SPI", + [GPIO_UNLOCK_SMI_STS_BIT] = "GPIO_UNLOCK", + [ESPI_SMI_STS_BIT] = "ESPI_SMI", + }; + + *a = ARRAY_SIZE(smi_sts_bits); + return smi_sts_bits; +} + +/* + * TCO + */ +const char *const *soc_tco_sts_array(size_t *a) +{ + static const char *const tco_sts_bits[] = { + [0] = "NMI2SMI", + [1] = "SW_TCO", + [2] = "TCO_INT", + [3] = "TIMEOUT", + [7] = "NEWCENTURY", + [8] = "BIOSWR", + [9] = "DMISCI", + [10] = "DMISMI", + [12] = "DMISERR", + [13] = "SLVSEL", + [16] = "INTRD_DET", + [17] = "SECOND_TO", + [18] = "BOOT", + [20] = "SMLINK_SLV" + }; + + *a = ARRAY_SIZE(tco_sts_bits); + return tco_sts_bits; +} + +/* + * GPE0 + */ +const char *const *soc_std_gpe_sts_array(size_t *a) +{ + static const char *const gpe_sts_bits[] = { + [1] = "HOTPLUG", + [2] = "SWGPE", + [6] = "TCO_SCI", + [7] = "SMB_WAK", + [9] = "PCI_EXP", + [10] = "BATLOW", + [11] = "PME", + [12] = "ME", + [13] = "PME_B0", + [14] = "eSPI", + [15] = "GPIO Tier-2", + [16] = "LAN_WAKE", + [18] = "WADT" + }; + + *a = ARRAY_SIZE(gpe_sts_bits); + return gpe_sts_bits; +} + +void pmc_set_disb(void) +{ + /* Set the DISB after DRAM init */ + uint8_t disb_val; + /* Only care about bits [23:16] of register GEN_PMCON_A */ + uint8_t *addr = (uint8_t *)(pmc_mmio_regs() + GEN_PMCON_A + 2); + + disb_val = read8(addr); + disb_val |= (DISB >> 16); + + /* Don't clear bits that are write-1-to-clear */ + disb_val &= ~((MS4V | SUS_PWR_FLR) >> 16); + write8(addr, disb_val); +} + +/* + * PMC controller gets hidden from PCI bus + * during FSP-Silicon init call. Hence PWRMBASE + * can't be accessible using PCI configuration space + * read/write. + */ +uint8_t *pmc_mmio_regs(void) +{ + return (void *)(uintptr_t)PCH_PWRM_BASE_ADDRESS; +} + +uintptr_t soc_read_pmc_base(void) +{ + return (uintptr_t)pmc_mmio_regs(); +} + +uint32_t *soc_pmc_etr_addr(void) +{ + return (uint32_t *)(soc_read_pmc_base() + ETR); +} + +void soc_get_gpi_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2) +{ + DEVTREE_CONST struct soc_intel_lnl_dev_config *config; + + config = config_of_soc(); + + /* Assign to out variable */ + *dw0 = config->pmc_gpe0_dw0; + *dw1 = config->pmc_gpe0_dw1; + *dw2 = config->pmc_gpe0_dw2; +} + +static int rtc_failed(uint32_t gen_pmcon_b) +{ + return !!(gen_pmcon_b & RTC_BATTERY_DEAD); +} + +int soc_get_rtc_failed(void) +{ + const struct chipset_power_state *ps; + + if (acpi_fetch_pm_state(&ps, PS_CLAIMER_RTC) < 0) + return 1; + + return rtc_failed(ps->gen_pmcon_b); +} + +int vbnv_cmos_failed(void) +{ + return rtc_failed(read32(pmc_mmio_regs() + GEN_PMCON_B)); +} + +static inline int deep_s3_enabled(void) +{ + uint32_t deep_s3_pol; + + deep_s3_pol = read32(pmc_mmio_regs() + S3_PWRGATE_POL); + return !!(deep_s3_pol & (S3DC_GATE_SUS | S3AC_GATE_SUS)); +} + +/* Return 0, 3, or 5 to indicate the previous sleep state. */ +int soc_prev_sleep_state(const struct chipset_power_state *ps, int prev_sleep_state) +{ + /* + * Check for any power failure to determine if this a wake from + * S5 because the PCH does not set the WAK_STS bit when waking + * from a true G3 state. + */ + if (!(ps->pm1_sts & WAK_STS) && (ps->gen_pmcon_a & (PWR_FLR | SUS_PWR_FLR))) + prev_sleep_state = ACPI_S5; + + /* + * If waking from S3 determine if deep S3 is enabled. If not, + * need to check both deep sleep well and normal suspend well. + * Otherwise just check deep sleep well. + */ + if (prev_sleep_state == ACPI_S3) { + /* PWR_FLR represents deep sleep power well loss. */ + uint32_t mask = PWR_FLR; + + /* If deep s3 isn't enabled check the suspend well too. */ + if (!deep_s3_enabled()) + mask |= SUS_PWR_FLR; + + if (ps->gen_pmcon_a & mask) + prev_sleep_state = ACPI_S5; + } + + return prev_sleep_state; +} + +void soc_fill_power_state(struct chipset_power_state *ps) +{ + uint8_t *pmc; + + ps->tco1_sts = tco_read_reg(TCO1_STS); + ps->tco2_sts = tco_read_reg(TCO2_STS); + + printk(BIOS_DEBUG, "TCO_STS: %04x %04x\n", ps->tco1_sts, ps->tco2_sts); + + pmc = pmc_mmio_regs(); + ps->gen_pmcon_a = read32(pmc + GEN_PMCON_A); + ps->gen_pmcon_b = read32(pmc + GEN_PMCON_B); + ps->gblrst_cause[0] = read32(pmc + GBLRST_CAUSE0); + ps->gblrst_cause[1] = read32(pmc + GBLRST_CAUSE1); + ps->hpr_cause0 = read32(pmc + HPR_CAUSE0); + + printk(BIOS_DEBUG, "GEN_PMCON: %08x %08x\n", + ps->gen_pmcon_a, ps->gen_pmcon_b); + + printk(BIOS_DEBUG, "GBLRST_CAUSE: %08x %08x\n", + ps->gblrst_cause[0], ps->gblrst_cause[1]); + + printk(BIOS_DEBUG, "HPR_CAUSE0: %08x\n", ps->hpr_cause0); +} + +/* STM Support */ +uint16_t get_pmbase(void) +{ + return (uint16_t)ACPI_BASE_ADDRESS; +} + +/* + * Set which power state system will be after reapplying + * the power (from G3 State) + */ +void pmc_soc_set_afterg3_en(const bool on) +{ + uint8_t reg8; + uint8_t *const pmcbase = pmc_mmio_regs(); + + reg8 = read8(pmcbase + GEN_PMCON_A); + if (on) + reg8 &= ~SLEEP_AFTER_POWER_FAIL; + else + reg8 |= SLEEP_AFTER_POWER_FAIL; + write8(pmcbase + GEN_PMCON_A, reg8); +} diff --git a/src/soc/intel/lnl_dev/retimer.c b/src/soc/intel/lnl_dev/retimer.c new file mode 100644 index 0000000..8bf485d --- /dev/null +++ b/src/soc/intel/lnl_dev/retimer.c @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/console.h> +#include <device/device.h> +#include <drivers/intel/usb4/retimer/retimer.h> +#include <intelblocks/tcss.h> +#include <soc/soc_info.h> + +int retimer_get_index_for_typec(uint8_t typec_port) +{ + int ec_port = 0; + + const struct device *tcss_port_arr[] = { + DEV_PTR(tcss_usb3_port0), + DEV_PTR(tcss_usb3_port1), + DEV_PTR(tcss_usb3_port2), + }; + + uint8_t _MAX_TYPE_C_PORTS = get_max_tcss_port(); + for (uint8_t i = 0; i < _MAX_TYPE_C_PORTS ; i++) { + if (i == typec_port) { + printk(BIOS_INFO, "USB Type-C %d mapped to EC port %d\n", typec_port, + ec_port); + return ec_port; + } + + if (is_dev_enabled(tcss_port_arr[i])) + ec_port++; + } + + // Code should not come here if typec_port input is correct + return -1; +} diff --git a/src/soc/intel/lnl_dev/smihandler.c b/src/soc/intel/lnl_dev/smihandler.c new file mode 100644 index 0000000..6a21f0a --- /dev/null +++ b/src/soc/intel/lnl_dev/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/lnl_dev/soc_info.c b/src/soc/intel/lnl_dev/soc_info.c new file mode 100644 index 0000000..9c37c8e --- /dev/null +++ b/src/soc/intel/lnl_dev/soc_info.c @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <soc/pci_devs.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <soc/soc_info.h> +#include <intelblocks/tcss.h> +#include <console/console.h> + +uint8_t get_soctype(void) +{ + uint16_t did; + +#ifdef __SIMPLE_DEVICE__ + did = pci_read_config16(PCI_DEVFN_ROOT, PCI_DEVICE_ID); +#else + struct device *dev; + dev = pcidev_path_on_root(PCI_DEVFN_ROOT); + did = pci_read_config16(dev, PCI_DEVICE_ID); +#endif + printk(BIOS_DEBUG, "soc_info: DID:0x%04x\n", did); + + if (did == PCI_DID_INTEL_LNL_M_ID) + return LNLM; + else + return LNLM; +} + +uint8_t get_max_usb20_port(void) +{ + uint8_t usb20_port = MAX_USB2_PORT; + printk(BIOS_DEBUG, "soc_info: max_usb20_port:%d\n", usb20_port); + return usb20_port; +} + +uint8_t get_max_usb30_port(void) +{ + uint8_t usb30_port = CONFIG_SOC_INTEL_USB3_DEV_MAX; + printk(BIOS_DEBUG, "soc_info: max_usb30_port:%d\n", usb30_port); + return usb30_port; +} + +uint8_t get_max_tcss_port(void) +{ + uint8_t tcss_port = MAX_TCSS_PORT; + printk(BIOS_DEBUG, "soc_info: tcss_port:%d\n", tcss_port); + return tcss_port; +} + +uint8_t get_max_tbt_pcie_port(void) +{ + uint8_t tbt_pcie_port = MAX_TBT_PCIE_PORT; + printk(BIOS_DEBUG, "soc_info: max_tbt_pcie_port:%d\n", tbt_pcie_port); + return tbt_pcie_port; +} + +uint8_t get_max_pcie_port(void) +{ + uint8_t pcie_port = MAX_PCIE_PORT; + printk(BIOS_DEBUG, "soc_info: max_pcie_port:%d\n", pcie_port); + return pcie_port; +} + +uint8_t get_max_pcie_clock(void) +{ + uint8_t pcie_clock = MAX_PCIE_CLOCK; + printk(BIOS_DEBUG, "soc_info: max_pcie_clock:%d\n", pcie_clock); + return pcie_clock; +} + +uint8_t get_max_uart_port(void) +{ + uint8_t uart_port = CONFIG_SOC_INTEL_UART_DEV_MAX; + printk(BIOS_DEBUG, "soc_info: max_uart_port:%d\n", uart_port); + return uart_port; +} + +uint8_t get_max_i2c_port(void) +{ + uint8_t i2c_port = CONFIG_SOC_INTEL_I2C_DEV_MAX; + printk(BIOS_DEBUG, "soc_info: max_i2c_port:%d\n", i2c_port); + return i2c_port; +} + +uint8_t get_max_i3c_port(void) +{ + uint8_t i3c_port = CONFIG_SOC_INTEL_I3C_DEV_MAX; + printk(BIOS_DEBUG, "soc_info: max_i3c_port:%d\n", i3c_port); + return i3c_port; +} + +uint8_t get_max_gspi_port(void) +{ + uint8_t gspi_port = CONFIG_SOC_INTEL_COMMON_BLOCK_GSPI_MAX; + printk(BIOS_DEBUG, "soc_info: max_gspi_port:%d\n", gspi_port); + return gspi_port; +} diff --git a/src/soc/intel/lnl_dev/soundwire.c b/src/soc/intel/lnl_dev/soundwire.c new file mode 100644 index 0000000..c3ff05d --- /dev/null +++ b/src/soc/intel/lnl_dev/soundwire.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi_soundwire.h> +#include <console/console.h> +#include <device/mmio.h> +#include <device/soundwire.h> +#include <drivers/intel/soundwire/soundwire.h> +#include <intelblocks/pmclib.h> +#include <soc/pmc.h> +#include <stddef.h> +#include <string.h> + +static const struct soundwire_link link_xtal_38_4 = { + .clock_stop_mode0_supported = 1, + .clock_stop_mode1_supported = 1, + .clock_frequencies_supported_count = 1, + .clock_frequencies_supported = { 4800 * KHz }, + .default_frame_rate = 48 * KHz, + .default_frame_row_size = 50, + .default_frame_col_size = 4, + .dynamic_frame_shape = 1, + .command_error_threshold = 16, +}; + +static const struct soundwire_link link_xtal_24 = { + .clock_stop_mode0_supported = 1, + .clock_stop_mode1_supported = 1, + .clock_frequencies_supported_count = 1, + .clock_frequencies_supported = { 6 * MHz }, + .default_frame_rate = 48 * KHz, + .default_frame_row_size = 125, + .default_frame_col_size = 2, + .dynamic_frame_shape = 1, + .command_error_threshold = 16, +}; + +static struct intel_soundwire_controller intel_controller = { + .acpi_address = 0x40000000, + .sdw = { + .master_list_count = 4 + } +}; + +int soc_fill_soundwire_controller(struct intel_soundwire_controller **controller) +{ + const struct soundwire_link *link; + enum pch_pmc_xtal xtal = pmc_get_xtal_freq(); + size_t i; + + /* Select link config based on XTAL frequency and set IP clock. */ + switch (xtal) { + case XTAL_24_MHZ: + link = &link_xtal_24; + intel_controller.ip_clock = 24 * MHz; + break; + case XTAL_38_4_MHZ: + link = &link_xtal_38_4; + intel_controller.ip_clock = 38400 * KHz; + break; + case XTAL_19_2_MHZ: + default: + printk(BIOS_ERR, "%s: XTAL not supported: 0x%x\n", __func__, xtal); + return -1; + } + + /* Fill link config in controller map based on selected XTAL. */ + for (i = 0; i < intel_controller.sdw.master_list_count; i++) + memcpy(&intel_controller.sdw.master_list[i], link, sizeof(*link)); + + *controller = &intel_controller; + return 0; +} diff --git a/src/soc/intel/lnl_dev/spi.c b/src/soc/intel/lnl_dev/spi.c new file mode 100644 index 0000000..f2e3400 --- /dev/null +++ b/src/soc/intel/lnl_dev/spi.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <intelblocks/fast_spi.h> +#include <intelblocks/spi.h> +#include <soc/pci_devs.h> + +#define PSF_SPI_DESTINATION_ID 0x5140 + +int spi_soc_devfn_to_bus(unsigned int devfn) +{ + switch (devfn) { + case PCI_DEVFN_SPI: + return 0; + case PCI_DEVFN_GSPI0: + return 1; + case PCI_DEVFN_GSPI1: + return 2; + } + return -1; +} + +uint32_t soc_get_spi_psf_destination_id(void) +{ + return PSF_SPI_DESTINATION_ID; +} diff --git a/src/soc/intel/lnl_dev/tcss.c b/src/soc/intel/lnl_dev/tcss.c new file mode 100644 index 0000000..bd1997a --- /dev/null +++ b/src/soc/intel/lnl_dev/tcss.c @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <intelblocks/tcss.h> +#include <soc/soc_chip.h> + +const struct soc_tcss_ops tcss_ops = { + .configure_aux_bias_pads = tcss_configure_aux_bias_pads_regbar, + .valid_tbt_auth = tcss_valid_tbt_auth, +}; + +bool ioe_tcss_valid_tbt_auth(void) +{ + const config_t *config = config_of_soc(); + return config->tbt_authentication; +} diff --git a/src/soc/intel/lnl_dev/uart.c b/src/soc/intel/lnl_dev/uart.c new file mode 100644 index 0000000..9f549c5 --- /dev/null +++ b/src/soc/intel/lnl_dev/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/lnl_dev/xhci.c b/src/soc/intel/lnl_dev/xhci.c new file mode 100644 index 0000000..9b4ac1b --- /dev/null +++ b/src/soc/intel/lnl_dev/xhci.c @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/pci_type.h> +#include <intelblocks/xhci.h> +#include <soc/pci_devs.h> + +#define XHCI_USB2_PORT_STATUS_REG 0x480 +#define XHCI_USB3_PORT_STATUS_REG 0x540 +#define XHCI_USB2_PORT_NUM 10 +#define XHCI_USB3_PORT_NUM 4 + +#define TCSS_XHCI_USB2_PORT_STATUS_REG 0x480 +#define TCSS_XHCI_USB3_PORT_STATUS_REG 0x490 +#define TCSS_XHCI_USB2_PORT_NUM 0 +#define TCSS_XHCI_USB3_PORT_NUM 4 + +static const struct xhci_usb_info usb_info = { + .usb2_port_status_reg = XHCI_USB2_PORT_STATUS_REG, + .num_usb2_ports = XHCI_USB2_PORT_NUM, + .usb3_port_status_reg = XHCI_USB3_PORT_STATUS_REG, + .num_usb3_ports = XHCI_USB3_PORT_NUM, +}; + +static const struct xhci_usb_info tcss_usb_info = { + .usb2_port_status_reg = TCSS_XHCI_USB2_PORT_STATUS_REG, + .num_usb2_ports = TCSS_XHCI_USB2_PORT_NUM, + .usb3_port_status_reg = TCSS_XHCI_USB3_PORT_STATUS_REG, + .num_usb3_ports = TCSS_XHCI_USB3_PORT_NUM, +}; + +const struct xhci_usb_info *soc_get_xhci_usb_info(pci_devfn_t xhci_dev) +{ + if (xhci_dev == PCI_DEVFN_XHCI) + return &usb_info; + else if (xhci_dev == PCI_DEVFN_TCSS_XHCI) + return &tcss_usb_info; + + return NULL; +}