Commit 008ee711 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'remotes/lorenzo/pci/qcom'

- Add DT and driver support for SC8280XP/SA8540P basic interconnects where
  interconnect bandwidth must be requested before enabling interconnect
  clocks (Johan Hovold)

- Add 'dma-coherent' property (Johan Hovold)

* remotes/lorenzo/pci/qcom:
  dt-bindings: PCI: qcom: Allow 'dma-coherent' property
  PCI: qcom: Add basic interconnect support
  dt-bindings: PCI: qcom: Add SC8280XP/SA8540P interconnects
parents 8ecdba32 74eac503
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -62,6 +62,16 @@ properties:
    minItems: 3
    maxItems: 13

  dma-coherent: true

  interconnects:
    maxItems: 2

  interconnect-names:
    items:
      - const: pcie-mem
      - const: cpu-pcie

  resets:
    minItems: 1
    maxItems: 12
@@ -631,6 +641,18 @@ allOf:
          items:
            - const: pci # PCIe core reset

  - if:
      properties:
        compatible:
          contains:
            enum:
              - qcom,pcie-sa8540p
              - qcom,pcie-sc8280xp
    then:
      required:
        - interconnects
        - interconnect-names

  - if:
      not:
        properties:
+76 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/crc8.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -223,6 +224,7 @@ struct qcom_pcie {
	union qcom_pcie_resources res;
	struct phy *phy;
	struct gpio_desc *reset;
	struct icc_path *icc_mem;
	const struct qcom_pcie_cfg *cfg;
};

@@ -1639,6 +1641,74 @@ static const struct dw_pcie_ops dw_pcie_ops = {
	.start_link = qcom_pcie_start_link,
};

static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
{
	struct dw_pcie *pci = pcie->pci;
	int ret;

	pcie->icc_mem = devm_of_icc_get(pci->dev, "pcie-mem");
	if (IS_ERR(pcie->icc_mem))
		return PTR_ERR(pcie->icc_mem);

	/*
	 * Some Qualcomm platforms require interconnect bandwidth constraints
	 * to be set before enabling interconnect clocks.
	 *
	 * Set an initial peak bandwidth corresponding to single-lane Gen 1
	 * for the pcie-mem path.
	 */
	ret = icc_set_bw(pcie->icc_mem, 0, MBps_to_icc(250));
	if (ret) {
		dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
			ret);
		return ret;
	}

	return 0;
}

static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
{
	struct dw_pcie *pci = pcie->pci;
	u32 offset, status, bw;
	int speed, width;
	int ret;

	if (!pcie->icc_mem)
		return;

	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
	status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);

	/* Only update constraints if link is up. */
	if (!(status & PCI_EXP_LNKSTA_DLLLA))
		return;

	speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
	width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);

	switch (speed) {
	case 1:
		bw = MBps_to_icc(250);
		break;
	case 2:
		bw = MBps_to_icc(500);
		break;
	default:
		WARN_ON_ONCE(1);
		fallthrough;
	case 3:
		bw = MBps_to_icc(985);
		break;
	}

	ret = icc_set_bw(pcie->icc_mem, 0, width * bw);
	if (ret) {
		dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
			ret);
	}
}

static int qcom_pcie_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
@@ -1699,6 +1769,10 @@ static int qcom_pcie_probe(struct platform_device *pdev)
		goto err_pm_runtime_put;
	}

	ret = qcom_pcie_icc_init(pcie);
	if (ret)
		goto err_pm_runtime_put;

	ret = pcie->cfg->ops->get_resources(pcie);
	if (ret)
		goto err_pm_runtime_put;
@@ -1717,6 +1791,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
		goto err_phy_exit;
	}

	qcom_pcie_icc_update(pcie);

	return 0;

err_phy_exit: