Commit a1dd5e7a authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/controller/dwc-qcom-ep'

- Add DT binding and driver support for SA8255p Endpoint being managed by
  firmware (Mrinmay Sarkar)

* pci/controller/dwc-qcom-ep:
  PCI: qcom-ep: Add support for firmware-managed PCIe Endpoint
  dt-bindings: PCI: qcom,sa8255p-pcie-ep: Document firmware managed PCIe endpoint
parents 9b2e9baa 5b026a9e
Loading
Loading
Loading
Loading
+110 −0
Original line number Diff line number Diff line
# 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 <mani@kernel.org>

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 <dt-bindings/gpio/gpio.h>
    #include <dt-bindings/interrupt-controller/arm-gic.h>
    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 = <GIC_SPI 518 IRQ_TYPE_LEVEL_HIGH>,
                         <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
                         <GIC_SPI 474 IRQ_TYPE_LEVEL_HIGH>;
            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>;
        };
    };
+1 −0
Original line number Diff line number Diff line
@@ -20365,6 +20365,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
+53 −8
Original line number Diff line number Diff line
@@ -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 = 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);
@@ -875,6 +900,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;
@@ -895,6 +926,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);

@@ -931,7 +968,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", },