From f1baed6f7983ce6f748bbce6e1b9686be5df50f4 Mon Sep 17 00:00:00 2001 From: Subrata Banik Date: Wed, 18 Mar 2026 13:49:32 +0530 Subject: [PATCH] soc/qualcomm/common: Implement asynchronous PCIe initialization Introduce SOC_QUALCOMM_PCIE_ASYNCHRONOUS_INIT to allow the PCIe link training to proceed without blocking the boot flow. Refactor qcom_setup_pcie_host into two logical phases: 1. Initiate: Power on endpoints and trigger LTSSM (Romstage). 2. Verify: Wait for link-up status (Ramstage). When the async Kconfig is enabled, the initiation happens in romstage, but the blocking 'wait_link_up' call is deferred to ramstage. This allows other SoC and mainboard initializations to run in between the hardware link training, reducing overall boot time. BUG=b:449871690 TEST=Verified PCIe link still enumerates correctly on Bluey with asynchronous init enabled. Change-Id: Idf368731325b5efcf4db0d1912a8c75417ef11ab Signed-off-by: Subrata Banik Reviewed-on: https://review.coreboot.org/c/coreboot/+/91723 Reviewed-by: Kapil Porwal Tested-by: build bot (Jenkins) --- src/soc/qualcomm/common/Kconfig | 10 +++++ src/soc/qualcomm/common/pcie_common.c | 57 ++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/soc/qualcomm/common/Kconfig b/src/soc/qualcomm/common/Kconfig index 373ba51c40..a572234cf6 100644 --- a/src/soc/qualcomm/common/Kconfig +++ b/src/soc/qualcomm/common/Kconfig @@ -61,4 +61,14 @@ config SOC_QUALCOMM_DEBUG_TSENS When enabled, a call to monitor TSENS will dump the sensor data on the debug console. +config SOC_QUALCOMM_PCIE_ASYNCHRONOUS_INIT + bool + default n + help + When enabled, qcom_setup_pcie_host will initiate the PCIe + hardware power-up sequence but will not block the boot flow + to wait for the link-up status. This can reduce overall + boot time, but requires late-stage drivers to verify link + readiness before access. + endif diff --git a/src/soc/qualcomm/common/pcie_common.c b/src/soc/qualcomm/common/pcie_common.c index ab8af642d1..7485fe55cc 100644 --- a/src/soc/qualcomm/common/pcie_common.c +++ b/src/soc/qualcomm/common/pcie_common.c @@ -178,6 +178,9 @@ static enum cb_err qcom_pcie_dw_link_up(struct qcom_pcie_cntlr_t *pcie) /* enable link training */ setbits32(pcie->cntlr_cfg->parf + PCIE_PARF_LTSSM, LTSSM_EN); + if (CONFIG(SOC_QUALCOMM_PCIE_ASYNCHRONOUS_INIT)) + return CB_SUCCESS; + /* Check that link was established */ if (wait_link_up(pcie)) { printk(BIOS_INFO, "PCIe link is up\n"); @@ -562,8 +565,7 @@ void qcom_pci_domain_read_resources(struct device *dev) res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; } -/* PCI domain ops enable callback */ -void qcom_setup_pcie_host(struct device *dev) +static enum cb_err pcie_initiate_link(void) { gcom_pcie_get_config(&qcom_pcie_cfg); @@ -576,6 +578,57 @@ void qcom_setup_pcie_host(struct device *dev) qcom_pcie_configure_gpios(qcom_pcie_cfg.cntlr_cfg); if (!qcom_dw_pcie_enable(&qcom_pcie_cfg)) + return CB_SUCCESS; + else + return CB_ERR; +} + +static enum cb_err pcie_verify_link_status(void) +{ + gcom_pcie_get_config(&qcom_pcie_cfg); + + if (is_pcie_link_up(&qcom_pcie_cfg)) { + printk(BIOS_INFO, "PCIe Link is already up\n"); + return CB_SUCCESS; + } + + /* Check that link was established */ + if (wait_link_up(&qcom_pcie_cfg)) { + printk(BIOS_INFO, "PCIe link is up\n"); + return CB_SUCCESS; + } + + /* + * Link can be established in Gen 1 as it failed to establish in Gen2. + * So allow some time to do it. + */ + udelay(100); + + return is_pcie_link_up(&qcom_pcie_cfg) ? CB_SUCCESS : CB_ERR; +} + +/* PCI domain ops enable callback */ +void qcom_setup_pcie_host(struct device *dev) +{ + /* STAGE 1: Initiate Hardware (Sync or Async) + * In Romstage (or if Async is disabled), we always start the hardware. + */ + if (ENV_SEPARATE_ROMSTAGE || !CONFIG(SOC_QUALCOMM_PCIE_ASYNCHRONOUS_INIT)) { + if (pcie_initiate_link() != CB_SUCCESS) { + printk(BIOS_EMERG, "Failed to enable PCIe\n"); + return; + } + + /* Async in Romstage */ + if (ENV_SEPARATE_ROMSTAGE) + return; + } + + /* STAGE 2: Late Check (Async only) + * If we are in Ramstage and Async is enabled, the hardware was already + * kicked off in Romstage. Now we just verify the result. + */ + if (pcie_verify_link_status() == CB_SUCCESS) printk(BIOS_NOTICE, "PCIe enumerated succussfully..\n"); else printk(BIOS_EMERG, "Failed to enable PCIe\n");