Skip to content

Commit

Permalink
Merge branch 'remotes/lorenzo/pci/qcom'
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
bjorn-helgaas committed Dec 10, 2022
2 parents 8ecdba3 + 74eac50 commit 008ee71
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
22 changes: 22 additions & 0 deletions Documentation/devicetree/bindings/pci/qcom,pcie.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
76 changes: 76 additions & 0 deletions drivers/pci/controller/dwc/pcie-qcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand Down

0 comments on commit 008ee71

Please sign in to comment.