From 20165a8ac68ff375e4955b3f9fda0404229131bd Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Tue, 6 Jan 2026 18:04:45 +0530 Subject: [PATCH 1/2] dt-bindings: PCI: qcom,sa8255p-pcie-ep: Document firmware managed PCIe endpoint Document the required configuration to enable the PCIe Endpoint controller on SA8255p which is managed by firmware using power-domain based handling. Signed-off-by: Mrinmay Sarkar [mani: added MAINTAINERS entry] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260106-firmware_managed_ep-v5-1-1933432127ec@oss.qualcomm.com --- .../bindings/pci/qcom,sa8255p-pcie-ep.yaml | 110 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 111 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/qcom,sa8255p-pcie-ep.yaml diff --git a/Documentation/devicetree/bindings/pci/qcom,sa8255p-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/qcom,sa8255p-pcie-ep.yaml new file mode 100644 index 000000000000..e338797d5dc2 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/qcom,sa8255p-pcie-ep.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/qcom,sa8255p-pcie-ep.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm firmware managed PCIe Endpoint Controller + +description: + Qualcomm SA8255p SoC PCIe endpoint controller is based on the Synopsys + DesignWare PCIe IP which is managed by firmware. + +maintainers: + - Manivannan Sadhasivam + +properties: + compatible: + const: qcom,sa8255p-pcie-ep + + reg: + items: + - description: Qualcomm-specific PARF configuration registers + - description: DesignWare PCIe registers + - description: External local bus interface registers + - description: Address Translation Unit (ATU) registers + - description: Memory region used to map remote RC address space + - description: BAR memory region + - description: DMA register space + + reg-names: + items: + - const: parf + - const: dbi + - const: elbi + - const: atu + - const: addr_space + - const: mmio + - const: dma + + interrupts: + items: + - description: PCIe Global interrupt + - description: PCIe Doorbell interrupt + - description: DMA interrupt + + interrupt-names: + items: + - const: global + - const: doorbell + - const: dma + + iommus: + maxItems: 1 + + reset-gpios: + description: GPIO used as PERST# input signal + maxItems: 1 + + wake-gpios: + description: GPIO used as WAKE# output signal + maxItems: 1 + + power-domains: + maxItems: 1 + + dma-coherent: true + + num-lanes: + default: 2 + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-names + - reset-gpios + - power-domains + +additionalProperties: false + +examples: + - | + #include + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + pcie1_ep: pcie-ep@1c10000 { + compatible = "qcom,sa8255p-pcie-ep"; + reg = <0x0 0x01c10000 0x0 0x3000>, + <0x0 0x60000000 0x0 0xf20>, + <0x0 0x60000f20 0x0 0xa8>, + <0x0 0x60001000 0x0 0x4000>, + <0x0 0x60200000 0x0 0x100000>, + <0x0 0x01c13000 0x0 0x1000>, + <0x0 0x60005000 0x0 0x2000>; + reg-names = "parf", "dbi", "elbi", "atu", "addr_space", "mmio", "dma"; + interrupts = , + , + ; + interrupt-names = "global", "doorbell", "dma"; + reset-gpios = <&tlmm 4 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 5 GPIO_ACTIVE_LOW>; + dma-coherent; + iommus = <&pcie_smmu 0x80 0x7f>; + power-domains = <&scmi6_pd 1>; + num-lanes = <4>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9d..18363f86300f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20357,6 +20357,7 @@ L: linux-pci@vger.kernel.org L: linux-arm-msm@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml +F: Documentation/devicetree/bindings/pci/qcom,sa8255p-pcie-ep.yaml F: drivers/pci/controller/dwc/pcie-qcom-common.c F: drivers/pci/controller/dwc/pcie-qcom-ep.c From 5b026a9e714d33bb61f6041b9e1bffa2dcc66ff6 Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Tue, 6 Jan 2026 18:04:46 +0530 Subject: [PATCH 2/2] PCI: qcom-ep: Add support for firmware-managed PCIe Endpoint Some Qualcomm platforms use firmware to manage PCIe resources such as clocks, resets, and PHY through the SCMI interface. In these cases, the Linux driver should not perform resource enable or disable operations directly. So introduce a `firmware_managed` flag in 'struct qcom_pcie_ep_cfg', and set it to true for SA8255p SoC. When this flag is set, the driver will skip the resource handling and rely on runtime PM APIs to let the firmware handle the resources with the help of power domain. Signed-off-by: Mrinmay Sarkar [mani: reworded description and tiny code cleanup] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260106-firmware_managed_ep-v5-2-1933432127ec@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 67 +++++++++++++++++++---- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index f1bc0ac81a92..49cc4ffd7947 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -168,11 +168,13 @@ enum qcom_pcie_ep_link_status { * @hdma_support: HDMA support on this SoC * @override_no_snoop: Override NO_SNOOP attribute in TLP to enable cache snooping * @disable_mhi_ram_parity_check: Disable MHI RAM data parity error check + * @firmware_managed: Set if the controller is firmware managed */ struct qcom_pcie_ep_cfg { bool hdma_support; bool override_no_snoop; bool disable_mhi_ram_parity_check; + bool firmware_managed; }; /** @@ -377,6 +379,14 @@ static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep) static void qcom_pcie_disable_resources(struct qcom_pcie_ep *pcie_ep) { + struct device *dev = pcie_ep->pci.dev; + + pm_runtime_put(dev); + + /* Skip resource disablement if controller is firmware-managed */ + if (pcie_ep->cfg && pcie_ep->cfg->firmware_managed) + return; + icc_set_bw(pcie_ep->icc_mem, 0, 0); phy_power_off(pcie_ep->phy); phy_exit(pcie_ep->phy); @@ -390,12 +400,24 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) u32 val, offset; int ret; - ret = qcom_pcie_enable_resources(pcie_ep); - if (ret) { - dev_err(dev, "Failed to enable resources: %d\n", ret); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + dev_err(dev, "Failed to enable device: %d\n", ret); return ret; } + /* Skip resource enablement if controller is firmware-managed */ + if (pcie_ep->cfg && pcie_ep->cfg->firmware_managed) + goto skip_resources_enable; + + ret = qcom_pcie_enable_resources(pcie_ep); + if (ret) { + dev_err(dev, "Failed to enable resources: %d\n", ret); + pm_runtime_put(dev); + return ret; + } + +skip_resources_enable: /* Perform cleanup that requires refclk */ pci_epc_deinit_notify(pci->ep.epc); dw_pcie_ep_cleanup(&pci->ep); @@ -630,6 +652,17 @@ static int qcom_pcie_ep_get_resources(struct platform_device *pdev, return ret; } + pcie_ep->reset = devm_gpiod_get(dev, "reset", GPIOD_IN); + if (IS_ERR(pcie_ep->reset)) + return PTR_ERR(pcie_ep->reset); + + pcie_ep->wake = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_LOW); + if (IS_ERR(pcie_ep->wake)) + return PTR_ERR(pcie_ep->wake); + + if (pcie_ep->cfg && pcie_ep->cfg->firmware_managed) + return 0; + pcie_ep->num_clks = devm_clk_bulk_get_all(dev, &pcie_ep->clks); if (pcie_ep->num_clks < 0) { dev_err(dev, "Failed to get clocks\n"); @@ -640,14 +673,6 @@ static int qcom_pcie_ep_get_resources(struct platform_device *pdev, if (IS_ERR(pcie_ep->core_reset)) return PTR_ERR(pcie_ep->core_reset); - pcie_ep->reset = devm_gpiod_get(dev, "reset", GPIOD_IN); - if (IS_ERR(pcie_ep->reset)) - return PTR_ERR(pcie_ep->reset); - - pcie_ep->wake = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_LOW); - if (IS_ERR(pcie_ep->wake)) - return PTR_ERR(pcie_ep->wake); - pcie_ep->phy = devm_phy_optional_get(dev, "pciephy"); if (IS_ERR(pcie_ep->phy)) ret = PTR_ERR(pcie_ep->phy); @@ -874,6 +899,12 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcie_ep); + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + ret = qcom_pcie_ep_get_resources(pdev, pcie_ep); if (ret) return ret; @@ -894,6 +925,12 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) goto err_disable_irqs; } + ret = pm_runtime_put_sync(dev); + if (ret < 0) { + dev_err(dev, "Failed to suspend device: %d\n", ret); + goto err_disable_irqs; + } + pcie_ep->debugfs = debugfs_create_dir(name, NULL); qcom_pcie_ep_init_debugfs(pcie_ep); @@ -930,7 +967,15 @@ static const struct qcom_pcie_ep_cfg cfg_1_34_0 = { .disable_mhi_ram_parity_check = true, }; +static const struct qcom_pcie_ep_cfg cfg_1_34_0_fw_managed = { + .hdma_support = true, + .override_no_snoop = true, + .disable_mhi_ram_parity_check = true, + .firmware_managed = true, +}; + static const struct of_device_id qcom_pcie_ep_match[] = { + { .compatible = "qcom,sa8255p-pcie-ep", .data = &cfg_1_34_0_fw_managed}, { .compatible = "qcom,sa8775p-pcie-ep", .data = &cfg_1_34_0}, { .compatible = "qcom,sdx55-pcie-ep", }, { .compatible = "qcom,sm8450-pcie-ep", },