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
This commit is contained in:
Bjorn Helgaas 2022-12-10 10:36:38 -06:00
commit 008ee711f9
2 changed files with 98 additions and 0 deletions

View File

@ -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:

View File

@ -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: