summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/dwc
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
commit8f9aa2c90530ab92301a82231ae44f3722becd93 (patch)
treefb282e955b0a880b07131a135257fe3ec764e928 /drivers/pci/controller/dwc
parent93467b31bec6da512b51544e5e4584f2745e995e (diff)
parent155b42bec9cbb6b8cdc47dd9bd09503a81fbe493 (diff)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r--drivers/pci/controller/dwc/pci-meson.c13
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-debugfs.c10
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c16
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h1
-rw-r--r--drivers/pci/controller/dwc/pcie-intel-gw.c46
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c43
6 files changed, 80 insertions, 49 deletions
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index 0694084f612b..225d887cd0a3 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -204,7 +204,9 @@ static inline struct clk *meson_pcie_probe_clock(struct device *dev,
return ERR_PTR(ret);
}
- devm_add_action_or_reset(dev, meson_pcie_disable_clock, clk);
+ ret = devm_add_action_or_reset(dev, meson_pcie_disable_clock, clk);
+ if (ret)
+ return ERR_PTR(ret);
return clk;
}
@@ -451,6 +453,14 @@ err_phy:
return ret;
}
+static void meson_pcie_remove(struct platform_device *pdev)
+{
+ struct meson_pcie *mp = platform_get_drvdata(pdev);
+
+ dw_pcie_host_deinit(&mp->pci.pp);
+ meson_pcie_power_off(mp);
+}
+
static const struct of_device_id meson_pcie_of_match[] = {
{
.compatible = "amlogic,axg-pcie",
@@ -464,6 +474,7 @@ MODULE_DEVICE_TABLE(of, meson_pcie_of_match);
static struct platform_driver meson_pcie_driver = {
.probe = meson_pcie_probe,
+ .remove = meson_pcie_remove,
.driver = {
.name = "meson-pcie",
.of_match_table = meson_pcie_of_match,
diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
index d0884253be97..449c67e7930d 100644
--- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c
+++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c
@@ -306,6 +306,7 @@ static ssize_t err_inj_write(struct file *file, const char __user *buf,
u32 val, counter, vc_num, err_group, type_mask;
int val_diff = 0;
char *kern_buf;
+ int ret;
err_group = err_inj_list[pdata->idx].err_inj_group;
type_mask = err_inj_type_mask[err_group];
@@ -327,10 +328,10 @@ static ssize_t err_inj_write(struct file *file, const char __user *buf,
return -EINVAL;
}
} else {
- val = kstrtou32(kern_buf, 0, &counter);
- if (val) {
+ ret = kstrtou32(kern_buf, 0, &counter);
+ if (ret) {
kfree(kern_buf);
- return val;
+ return ret;
}
}
@@ -557,6 +558,9 @@ static void dwc_pcie_rasdes_debugfs_deinit(struct dw_pcie *pci)
{
struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info;
+ if (!rinfo)
+ return;
+
mutex_destroy(&rinfo->reg_event_lock);
}
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c11cf61b8319..76c9a0a10367 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -487,13 +487,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg
static inline u32 dw_pcie_enable_ecrc(u32 val)
{
/*
- * DWC versions 0x3530302a and 0x3536322a have a design issue where
- * the 'TD' bit in the Control register-1 of the ATU outbound
- * region acts like an override for the ECRC setting, i.e., the
- * presence of TLP Digest (ECRC) in the outgoing TLPs is solely
- * determined by this bit. This is contrary to the PCIe spec which
- * says that the enablement of the ECRC is solely determined by the
- * AER registers.
+ * DesignWare core versions prior to 5.10A have a design issue where the
+ * 'TD' bit in the Control register-1 of the ATU outbound region acts
+ * like an override for the ECRC setting, i.e., the presence of TLP
+ * Digest (ECRC) in the outgoing TLPs is solely determined by this
+ * bit. This is contrary to the PCIe spec which says that the
+ * enablement of the ECRC is solely determined by the AER
+ * registers.
*
* Because of this, even when the ECRC is enabled through AER
* registers, the transactions going through ATU won't have TLP
@@ -563,7 +563,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
if (upper_32_bits(limit_addr) > upper_32_bits(parent_bus_addr) &&
dw_pcie_ver_is_ge(pci, 460A))
val |= PCIE_ATU_INCREASE_REGION_SIZE;
- if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A))
+ if (!dw_pcie_ver_is_ge(pci, 510A))
val = dw_pcie_enable_ecrc(val);
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 3e69ef60165b..a07b7abda41f 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -35,6 +35,7 @@
#define DW_PCIE_VER_480A 0x3438302a
#define DW_PCIE_VER_490A 0x3439302a
#define DW_PCIE_VER_500A 0x3530302a
+#define DW_PCIE_VER_510A 0x3531302a
#define DW_PCIE_VER_520A 0x3532302a
#define DW_PCIE_VER_540A 0x3534302a
#define DW_PCIE_VER_562A 0x3536322a
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index c21906eced61..f157c716953c 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -196,6 +196,13 @@ static void intel_pcie_device_rst_deassert(struct intel_pcie *pcie)
gpiod_set_value_cansleep(pcie->reset_gpio, 0);
}
+static void intel_pcie_core_irq_enable(struct intel_pcie *pcie)
+{
+ pcie_app_wr(pcie, PCIE_APP_IRNEN, 0);
+ pcie_app_wr(pcie, PCIE_APP_IRNCR, PCIE_APP_IRN_INT);
+ pcie_app_wr(pcie, PCIE_APP_IRNEN, PCIE_APP_IRN_INT);
+}
+
static void intel_pcie_core_irq_disable(struct intel_pcie *pcie)
{
pcie_app_wr(pcie, PCIE_APP_IRNEN, 0);
@@ -278,6 +285,16 @@ static void intel_pcie_turn_off(struct intel_pcie *pcie)
pcie_rc_cfg_wr_mask(pcie, PCI_COMMAND, PCI_COMMAND_MEMORY, 0);
}
+static int intel_pcie_start_link(struct dw_pcie *pci)
+{
+ struct intel_pcie *pcie = dev_get_drvdata(pci->dev);
+
+ intel_pcie_device_rst_deassert(pcie);
+ intel_pcie_ltssm_enable(pcie);
+
+ return 0;
+}
+
static int intel_pcie_host_setup(struct intel_pcie *pcie)
{
int ret;
@@ -285,13 +302,9 @@ static int intel_pcie_host_setup(struct intel_pcie *pcie)
intel_pcie_core_rst_assert(pcie);
intel_pcie_device_rst_assert(pcie);
-
- ret = phy_init(pcie->phy);
- if (ret)
- return ret;
-
intel_pcie_core_rst_deassert(pcie);
+ /* Controller clock must be provided earlier than PHY */
ret = clk_prepare_enable(pcie->core_clk);
if (ret) {
dev_err(pcie->pci.dev, "Core clock enable failed: %d\n", ret);
@@ -300,34 +313,24 @@ static int intel_pcie_host_setup(struct intel_pcie *pcie)
pci->atu_base = pci->dbi_base + 0xC0000;
+ ret = phy_init(pcie->phy);
+ if (ret)
+ goto phy_err;
+
intel_pcie_ltssm_disable(pcie);
intel_pcie_link_setup(pcie);
intel_pcie_init_n_fts(pci);
- ret = dw_pcie_setup_rc(&pci->pp);
- if (ret)
- goto app_init_err;
-
dw_pcie_upconfig_setup(pci);
- intel_pcie_device_rst_deassert(pcie);
- intel_pcie_ltssm_enable(pcie);
-
- ret = dw_pcie_wait_for_link(pci);
- if (ret)
- goto app_init_err;
-
- /* Enable integrated interrupts */
- pcie_app_wr_mask(pcie, PCIE_APP_IRNEN, PCIE_APP_IRN_INT,
- PCIE_APP_IRN_INT);
+ intel_pcie_core_irq_enable(pcie);
return 0;
-app_init_err:
+phy_err:
clk_disable_unprepare(pcie->core_clk);
clk_err:
intel_pcie_core_rst_assert(pcie);
- phy_exit(pcie->phy);
return ret;
}
@@ -381,6 +384,7 @@ static int intel_pcie_rc_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_ops intel_pcie_ops = {
+ .start_link = intel_pcie_start_link,
};
static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 7d8eaef436ef..2af757397975 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -1473,6 +1473,7 @@ static const struct qcom_pcie_cfg cfg_1_9_0 = {
static const struct qcom_pcie_cfg cfg_1_34_0 = {
.ops = &ops_1_9_0,
.override_no_snoop = true,
+ .no_l0s = true,
};
static const struct qcom_pcie_cfg cfg_2_1_0 = {
@@ -1613,6 +1614,22 @@ static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie)
}
}
+static int qcom_pcie_set_max_opp(struct device *dev)
+{
+ unsigned long max_freq = ULONG_MAX;
+ struct dev_pm_opp *opp;
+ int ret;
+
+ opp = dev_pm_opp_find_freq_floor(dev, &max_freq);
+ if (IS_ERR(opp))
+ return PTR_ERR(opp);
+
+ ret = dev_pm_opp_set_opp(dev, opp);
+ dev_pm_opp_put(opp);
+
+ return ret;
+}
+
static int qcom_pcie_link_transition_count(struct seq_file *s, void *data)
{
struct qcom_pcie *pcie = (struct qcom_pcie *)dev_get_drvdata(s->private);
@@ -1851,9 +1868,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
struct qcom_pcie_perst *perst, *tmp_perst;
struct qcom_pcie_port *port, *tmp_port;
const struct qcom_pcie_cfg *pcie_cfg;
- unsigned long max_freq = ULONG_MAX;
struct device *dev = &pdev->dev;
- struct dev_pm_opp *opp;
struct qcom_pcie *pcie;
struct dw_pcie_rp *pp;
struct resource *res;
@@ -1957,21 +1972,9 @@ static int qcom_pcie_probe(struct platform_device *pdev)
* probe(), OPP will be updated using qcom_pcie_icc_opp_update().
*/
if (!ret) {
- opp = dev_pm_opp_find_freq_floor(dev, &max_freq);
- if (IS_ERR(opp)) {
- ret = PTR_ERR(opp);
- dev_err_probe(pci->dev, ret,
- "Unable to find max freq OPP\n");
- goto err_pm_runtime_put;
- } else {
- ret = dev_pm_opp_set_opp(dev, opp);
- }
-
- dev_pm_opp_put(opp);
+ ret = qcom_pcie_set_max_opp(dev);
if (ret) {
- dev_err_probe(pci->dev, ret,
- "Failed to set OPP for freq %lu\n",
- max_freq);
+ dev_err_probe(dev, ret, "Failed to set max OPP\n");
goto err_pm_runtime_put;
}
@@ -2106,6 +2109,14 @@ static int qcom_pcie_resume_noirq(struct device *dev)
return 0;
if (pm_suspend_target_state != PM_SUSPEND_MEM) {
+ if (pcie->use_pm_opp) {
+ ret = qcom_pcie_set_max_opp(dev);
+ if (ret) {
+ dev_err(dev, "Failed to set max OPP: %d\n", ret);
+ return ret;
+ }
+ }
+
ret = icc_enable(pcie->icc_cpu);
if (ret) {
dev_err(dev, "Failed to enable CPU-PCIe interconnect path: %d\n", ret);