Skip to content

Commit 7d944c0

Browse files
Mayank Ranabjorn-helgaas
authored andcommitted
PCI: qcom: Add support for Qualcomm SA8255p based PCIe Root Complex
Add functionality to enable resource management (like clocks, regulators, PHY) through firmware and enumerate ECAM compliant Root Complex on SA8255p SoC, where the PCIe Root Complex is firmware managed and configured into ECAM compliant mode. Signed-off-by: Mayank Rana <[email protected]> [mani: minor code cleanups and commit message rewording] Signed-off-by: Manivannan Sadhasivam <[email protected]> [bhelgaas: add "ECAM" in comment] Signed-off-by: Bjorn Helgaas <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent d7c7c05 commit 7d944c0

File tree

2 files changed

+112
-12
lines changed

2 files changed

+112
-12
lines changed

drivers/pci/controller/dwc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ config PCIE_QCOM
296296
select PCIE_DW_HOST
297297
select CRC8
298298
select PCIE_QCOM_COMMON
299+
select PCI_HOST_COMMON
299300
help
300301
Say Y here to enable PCIe controller support on Qualcomm SoCs. The
301302
PCIe controller uses the DesignWare core plus Qualcomm-specific

drivers/pci/controller/dwc/pcie-qcom.c

Lines changed: 111 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
#include <linux/limits.h>
2222
#include <linux/init.h>
2323
#include <linux/of.h>
24+
#include <linux/of_pci.h>
2425
#include <linux/pci.h>
26+
#include <linux/pci-ecam.h>
2527
#include <linux/pm_opp.h>
2628
#include <linux/pm_runtime.h>
2729
#include <linux/platform_device.h>
@@ -34,6 +36,7 @@
3436
#include <linux/units.h>
3537

3638
#include "../../pci.h"
39+
#include "../pci-host-common.h"
3740
#include "pcie-designware.h"
3841
#include "pcie-qcom-common.h"
3942

@@ -255,10 +258,12 @@ struct qcom_pcie_ops {
255258
* @ops: qcom PCIe ops structure
256259
* @override_no_snoop: Override NO_SNOOP attribute in TLP to enable cache
257260
* snooping
261+
* @firmware_managed: Set if the Root Complex is firmware managed
258262
*/
259263
struct qcom_pcie_cfg {
260264
const struct qcom_pcie_ops *ops;
261265
bool override_no_snoop;
266+
bool firmware_managed;
262267
bool no_l0s;
263268
};
264269

@@ -1426,6 +1431,10 @@ static const struct qcom_pcie_cfg cfg_sc8280xp = {
14261431
.no_l0s = true,
14271432
};
14281433

1434+
static const struct qcom_pcie_cfg cfg_fw_managed = {
1435+
.firmware_managed = true,
1436+
};
1437+
14291438
static const struct dw_pcie_ops dw_pcie_ops = {
14301439
.link_up = qcom_pcie_link_up,
14311440
.start_link = qcom_pcie_start_link,
@@ -1579,6 +1588,49 @@ static irqreturn_t qcom_pcie_global_irq_thread(int irq, void *data)
15791588
return IRQ_HANDLED;
15801589
}
15811590

1591+
static void qcom_pci_free_msi(void *ptr)
1592+
{
1593+
struct dw_pcie_rp *pp = (struct dw_pcie_rp *)ptr;
1594+
1595+
if (pp && pp->has_msi_ctrl)
1596+
dw_pcie_free_msi(pp);
1597+
}
1598+
1599+
static int qcom_pcie_ecam_host_init(struct pci_config_window *cfg)
1600+
{
1601+
struct device *dev = cfg->parent;
1602+
struct dw_pcie_rp *pp;
1603+
struct dw_pcie *pci;
1604+
int ret;
1605+
1606+
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
1607+
if (!pci)
1608+
return -ENOMEM;
1609+
1610+
pci->dev = dev;
1611+
pp = &pci->pp;
1612+
pci->dbi_base = cfg->win;
1613+
pp->num_vectors = MSI_DEF_NUM_VECTORS;
1614+
1615+
ret = dw_pcie_msi_host_init(pp);
1616+
if (ret)
1617+
return ret;
1618+
1619+
pp->has_msi_ctrl = true;
1620+
dw_pcie_msi_init(pp);
1621+
1622+
return devm_add_action_or_reset(dev, qcom_pci_free_msi, pp);
1623+
}
1624+
1625+
static const struct pci_ecam_ops pci_qcom_ecam_ops = {
1626+
.init = qcom_pcie_ecam_host_init,
1627+
.pci_ops = {
1628+
.map_bus = pci_ecam_map_bus,
1629+
.read = pci_generic_config_read,
1630+
.write = pci_generic_config_write,
1631+
}
1632+
};
1633+
15821634
static int qcom_pcie_probe(struct platform_device *pdev)
15831635
{
15841636
const struct qcom_pcie_cfg *pcie_cfg;
@@ -1593,24 +1645,62 @@ static int qcom_pcie_probe(struct platform_device *pdev)
15931645
char *name;
15941646

15951647
pcie_cfg = of_device_get_match_data(dev);
1596-
if (!pcie_cfg || !pcie_cfg->ops) {
1597-
dev_err(dev, "Invalid platform data\n");
1598-
return -EINVAL;
1648+
if (!pcie_cfg) {
1649+
dev_err(dev, "No platform data\n");
1650+
return -ENODATA;
15991651
}
16001652

1601-
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
1602-
if (!pcie)
1603-
return -ENOMEM;
1604-
1605-
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
1606-
if (!pci)
1607-
return -ENOMEM;
1653+
if (!pcie_cfg->firmware_managed && !pcie_cfg->ops) {
1654+
dev_err(dev, "No platform ops\n");
1655+
return -ENODATA;
1656+
}
16081657

16091658
pm_runtime_enable(dev);
16101659
ret = pm_runtime_get_sync(dev);
16111660
if (ret < 0)
16121661
goto err_pm_runtime_put;
16131662

1663+
if (pcie_cfg->firmware_managed) {
1664+
struct pci_host_bridge *bridge;
1665+
struct pci_config_window *cfg;
1666+
1667+
bridge = devm_pci_alloc_host_bridge(dev, 0);
1668+
if (!bridge) {
1669+
ret = -ENOMEM;
1670+
goto err_pm_runtime_put;
1671+
}
1672+
1673+
/* Parse and map our ECAM configuration space area */
1674+
cfg = pci_host_common_ecam_create(dev, bridge,
1675+
&pci_qcom_ecam_ops);
1676+
if (IS_ERR(cfg)) {
1677+
ret = PTR_ERR(cfg);
1678+
goto err_pm_runtime_put;
1679+
}
1680+
1681+
bridge->sysdata = cfg;
1682+
bridge->ops = (struct pci_ops *)&pci_qcom_ecam_ops.pci_ops;
1683+
bridge->msi_domain = true;
1684+
1685+
ret = pci_host_probe(bridge);
1686+
if (ret)
1687+
goto err_pm_runtime_put;
1688+
1689+
return 0;
1690+
}
1691+
1692+
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
1693+
if (!pcie) {
1694+
ret = -ENOMEM;
1695+
goto err_pm_runtime_put;
1696+
}
1697+
1698+
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
1699+
if (!pci) {
1700+
ret = -ENOMEM;
1701+
goto err_pm_runtime_put;
1702+
}
1703+
16141704
pci->dev = dev;
16151705
pci->ops = &dw_pcie_ops;
16161706
pp = &pci->pp;
@@ -1756,9 +1846,13 @@ static int qcom_pcie_probe(struct platform_device *pdev)
17561846

17571847
static int qcom_pcie_suspend_noirq(struct device *dev)
17581848
{
1759-
struct qcom_pcie *pcie = dev_get_drvdata(dev);
1849+
struct qcom_pcie *pcie;
17601850
int ret = 0;
17611851

1852+
pcie = dev_get_drvdata(dev);
1853+
if (!pcie)
1854+
return 0;
1855+
17621856
/*
17631857
* Set minimum bandwidth required to keep data path functional during
17641858
* suspend.
@@ -1812,9 +1906,13 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
18121906

18131907
static int qcom_pcie_resume_noirq(struct device *dev)
18141908
{
1815-
struct qcom_pcie *pcie = dev_get_drvdata(dev);
1909+
struct qcom_pcie *pcie;
18161910
int ret;
18171911

1912+
pcie = dev_get_drvdata(dev);
1913+
if (!pcie)
1914+
return 0;
1915+
18181916
if (pm_suspend_target_state != PM_SUSPEND_MEM) {
18191917
ret = icc_enable(pcie->icc_cpu);
18201918
if (ret) {
@@ -1849,6 +1947,7 @@ static const struct of_device_id qcom_pcie_match[] = {
18491947
{ .compatible = "qcom,pcie-ipq9574", .data = &cfg_2_9_0 },
18501948
{ .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 },
18511949
{ .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 },
1950+
{ .compatible = "qcom,pcie-sa8255p", .data = &cfg_fw_managed },
18521951
{ .compatible = "qcom,pcie-sa8540p", .data = &cfg_sc8280xp },
18531952
{ .compatible = "qcom,pcie-sa8775p", .data = &cfg_1_34_0},
18541953
{ .compatible = "qcom,pcie-sc7280", .data = &cfg_1_9_0 },

0 commit comments

Comments
 (0)