# --- T2-COPYRIGHT-BEGIN --- # t2/package/*/linux/up-next-qcom.x1e80100.patch.arm64 # Copyright (C) 2025 The T2 SDE Project # SPDX-License-Identifier: GPL-2.0 or patched project license # --- T2-COPYRIGHT-END --- https://github.com/jhovold/linux diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index d9f0386396ed..153fcc71000c 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -290,7 +290,7 @@ config PCIE_QCOM_COMMON bool config PCIE_QCOM - bool "Qualcomm PCIe controller (host mode)" + tristate "Qualcomm PCIe controller (host mode)" depends on OF && (ARCH_QCOM || COMPILE_TEST) depends on PCI_MSI select PCIE_DW_HOST diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index c789e3f85655..33a5167090b5 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -247,7 +249,6 @@ int (*get_resources)(struct qcom_pcie *pcie); int (*init)(struct qcom_pcie *pcie); int (*post_init)(struct qcom_pcie *pcie); - void (*host_post_init)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie); int (*config_sid)(struct qcom_pcie *pcie); @@ -282,6 +283,7 @@ struct icc_path *icc_cpu; const struct qcom_pcie_cfg *cfg; struct dentry *debugfs; + struct notifier_block nb; struct list_head ports; bool suspended; bool use_pm_opp; @@ -1039,25 +1041,6 @@ return 0; } -static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata) -{ - /* - * Downstream devices need to be in D0 state before enabling PCI PM - * substates. - */ - pci_set_power_state_locked(pdev, PCI_D0); - pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL); - - return 0; -} - -static void qcom_pcie_host_post_init_2_7_0(struct qcom_pcie *pcie) -{ - struct dw_pcie_rp *pp = &pcie->pci->pp; - - pci_walk_bus(pp->bridge->bus, qcom_pcie_enable_aspm, NULL); -} - static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0; @@ -1332,19 +1315,9 @@ pcie->cfg->ops->deinit(pcie); } -static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct qcom_pcie *pcie = to_qcom_pcie(pci); - - if (pcie->cfg->ops->host_post_init) - pcie->cfg->ops->host_post_init(pcie); -} - static const struct dw_pcie_host_ops qcom_pcie_dw_ops = { .init = qcom_pcie_host_init, .deinit = qcom_pcie_host_deinit, - .post_init = qcom_pcie_host_post_init, }; /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */ @@ -1406,7 +1379,6 @@ .get_resources = qcom_pcie_get_resources_2_7_0, .init = qcom_pcie_init_2_7_0, .post_init = qcom_pcie_post_init_2_7_0, - .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, .config_sid = qcom_pcie_config_sid_1_9_0, @@ -1417,7 +1389,6 @@ .get_resources = qcom_pcie_get_resources_2_7_0, .init = qcom_pcie_init_2_7_0, .post_init = qcom_pcie_post_init_2_7_0, - .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, }; @@ -1764,6 +1735,38 @@ return 0; } +static int qcom_pcie_enable_aspm(struct pci_dev *pdev) +{ + /* + * Downstream devices need to be in D0 state before enabling PCI PM + * substates. + */ + pci_set_power_state(pdev, PCI_D0); + pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL); + + return 0; +} + +static int pcie_qcom_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct device *dev = data; + struct pci_dev *pdev = to_pci_dev(dev); + + switch (action) { + case BUS_NOTIFY_BIND_DRIVER: + qcom_pcie_enable_aspm(pdev); + break; + } + + return NOTIFY_DONE; +} + +static void qcom_pcie_deinit_debugfs(struct qcom_pcie *pcie) +{ + debugfs_remove(pcie->debugfs); +} + static int qcom_pcie_probe(struct platform_device *pdev) { const struct qcom_pcie_cfg *pcie_cfg; @@ -1931,10 +1934,15 @@ if (irq > 0) pp->use_linkup_irq = true; + pcie->nb.notifier_call = pcie_qcom_notify; + ret = bus_register_notifier(&pci_bus_type, &pcie->nb); + if (ret) + goto err_phy_exit; + ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "cannot initialize host\n"); - goto err_phy_exit; + goto err_unregister_notifier; } name = devm_kasprintf(dev, GFP_KERNEL, "qcom_pcie_global_irq%d", @@ -1967,6 +1975,8 @@ err_host_deinit: dw_pcie_host_deinit(pp); +err_unregister_notifier: + bus_unregister_notifier(&pci_bus_type, &pcie->nb); err_phy_exit: list_for_each_entry_safe(port, tmp, &pcie->ports, list) { phy_exit(port->phy); @@ -1979,6 +1989,27 @@ return ret; } +static void qcom_pcie_remove(struct platform_device *pdev) +{ + struct qcom_pcie *pcie = platform_get_drvdata(pdev); + struct qcom_pcie_port *port, *tmp; + struct device *dev = &pdev->dev; + + qcom_pcie_deinit_debugfs(pcie); + + dw_pcie_host_deinit(&pcie->pci->pp); + + bus_unregister_notifier(&pci_bus_type, &pcie->nb); + + list_for_each_entry_safe(port, tmp, &pcie->ports, list) { + phy_exit(port->phy); + list_del(&port->list); + } + + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); +} + static int qcom_pcie_suspend_noirq(struct device *dev) { struct qcom_pcie *pcie; @@ -2099,6 +2130,7 @@ { .compatible = "qcom,pcie-x1e80100", .data = &cfg_sc8280xp }, { } }; +MODULE_DEVICE_TABLE(of, qcom_pcie_match); static void qcom_fixup_class(struct pci_dev *dev) { @@ -2118,12 +2150,16 @@ static struct platform_driver qcom_pcie_driver = { .probe = qcom_pcie_probe, + .remove = qcom_pcie_remove, .driver = { .name = "qcom-pcie", - .suppress_bind_attrs = true, .of_match_table = qcom_pcie_match, .pm = &qcom_pcie_pm_ops, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; -builtin_platform_driver(qcom_pcie_driver); +module_platform_driver(qcom_pcie_driver); + +MODULE_AUTHOR("Stanimir Varbanov "); +MODULE_DESCRIPTION("Qualcomm PCIe root complex driver"); +MODULE_LICENSE("GPL");