diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2026-09-30 17:17:12 -0500 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-09-30 17:17:12 -0500 |
| commit | 47a32c7dd8621226a8dde72a13eb834a7d750245 (patch) | |
| tree | 1d55726b17717712027327520739256cb18a7881 /drivers/pci/controller | |
| parent | 22d8929a51e83c212c7d3f91acb00d2b252fc0a6 (diff) | |
| parent | 5a642c81b31bbd426edceb071ba50839c225220a (diff) | |
| download | linux-next-47a32c7dd8621226a8dde72a13eb834a7d750245.tar.gz linux-next-47a32c7dd8621226a8dde72a13eb834a7d750245.zip | |
Merge branch 'pci/controller/dwc-imx6'
- Fix pwrctrl device leak when .probe() PM runtime setup fail (Zhijian Han)
- Fix resource leaks in .probe() error paths (Zhijian Han)
- Improve i.MX95 Gen3 link stability by changing MPLLB_BANDWIDTH from
default 120 to 140 (Richard Zhu)
* pci/controller/dwc-imx6:
PCI: imx6: Update MPLLB bandwidth to improve i.MX95 Gen3 PCIe stability
PCI: imx6: Fix resource leaks in probe error paths
PCI: imx6: Fix pwrctrl device leak on PM runtime setup failure
Diffstat (limited to 'drivers/pci/controller')
| -rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 94 |
1 files changed, 82 insertions, 12 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 8383a71534c0..0c98107ca0db 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -80,6 +80,18 @@ #define IMX95_SID_MASK GENMASK(5, 0) #define IMX95_MAX_LUT 32 +#define IMX95_PCIE_PHY_REG_ADDR 0x3008 +#define IMX95_PCIE_PHY_REG_EN BIT(31) +#define IMX95_PCIE_PHY_REG_ADDR_MASK GENMASK(15, 0) + +#define IMX95_PCIE_PHY_REG_DATA 0x300c + +#define IMX95_PCIE_PHY_MPLLB_OVRD_IN 0x2004 +#define IMX95_PCIE_PHY_MPLLB_OVRD_BW_EN BIT(10) + +#define IMX95_PCIE_PHY_MPLLB_BW_IN 0x2005 +#define IMX95_PCIE_PHY_MPLLB_BW_VAL 0x8c + #define IMX95_PCIE_RST_CTRL 0x3010 #define IMX95_PCIE_COLD_RST BIT(0) @@ -180,8 +192,12 @@ struct imx_pcie { struct imx_lut_data luts[IMX95_MAX_LUT]; /* power domain for pcie */ struct device *pd_pcie; + /* device link for pcie power domain */ + struct device_link *pd_link; /* power domain for pcie phy */ struct device *pd_pcie_phy; + /* device link for pcie phy power domain */ + struct device_link *pd_phy_link; struct phy *phy; const struct imx_pcie_drvdata *drvdata; @@ -270,8 +286,19 @@ static int imx95_pcie_select_ref_clk_src(struct imx_pcie *imx_pcie) return 0; } +static void imx95_pcie_phy_write(struct imx_pcie *imx_pcie, int addr, u16 data) +{ + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_REG_ADDR, + IMX95_PCIE_PHY_REG_EN, IMX95_PCIE_PHY_REG_EN); + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_REG_ADDR, + IMX95_PCIE_PHY_REG_ADDR_MASK, addr); + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_REG_DATA, data); +} + static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) { + u32 val; + /* * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready * Through Beacon or PERST# De-assertion @@ -290,6 +317,21 @@ static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) IMX95_PCIE_PHY_CR_PARA_SEL, IMX95_PCIE_PHY_CR_PARA_SEL); + /* Flush the IMX95_PCIE_PHY_CR_PARA_SEL update */ + regmap_read(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, &val); + + /* + * A delay is required between the assertion of + * IMX95_PCIE_PHY_CR_PARA_SEL and subsequent PHY register write + * operation to ensure values are successfully written. + */ + udelay(200); + + imx95_pcie_phy_write(imx_pcie, IMX95_PCIE_PHY_MPLLB_BW_IN, + IMX95_PCIE_PHY_MPLLB_BW_VAL); + imx95_pcie_phy_write(imx_pcie, IMX95_PCIE_PHY_MPLLB_OVRD_IN, + IMX95_PCIE_PHY_MPLLB_OVRD_BW_EN); + return 0; } @@ -639,10 +681,34 @@ static int imx6q_pcie_abort_handler(unsigned long addr, } #endif +static void imx_pcie_detach_pd_action(void *data) +{ + struct imx_pcie *imx_pcie = data; + + if (!IS_ERR_OR_NULL(imx_pcie->pd_phy_link)) { + device_link_del(imx_pcie->pd_phy_link); + imx_pcie->pd_phy_link = NULL; + } + + if (!IS_ERR_OR_NULL(imx_pcie->pd_link)) { + device_link_del(imx_pcie->pd_link); + imx_pcie->pd_link = NULL; + } + + if (!IS_ERR_OR_NULL(imx_pcie->pd_pcie_phy)) { + dev_pm_domain_detach(imx_pcie->pd_pcie_phy, true); + imx_pcie->pd_pcie_phy = NULL; + } + + if (!IS_ERR_OR_NULL(imx_pcie->pd_pcie)) { + dev_pm_domain_detach(imx_pcie->pd_pcie, true); + imx_pcie->pd_pcie = NULL; + } +} + static int imx_pcie_attach_pd(struct device *dev) { struct imx_pcie *imx_pcie = dev_get_drvdata(dev); - struct device_link *link; /* Do nothing when in a single power domain */ if (dev->pm_domain) @@ -654,11 +720,11 @@ static int imx_pcie_attach_pd(struct device *dev) /* Do nothing when power domain missing */ if (!imx_pcie->pd_pcie) return 0; - link = device_link_add(dev, imx_pcie->pd_pcie, - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!link) { + imx_pcie->pd_link = device_link_add(dev, imx_pcie->pd_pcie, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!imx_pcie->pd_link) { dev_err(dev, "Failed to add device_link to pcie pd\n"); return -EINVAL; } @@ -667,11 +733,11 @@ static int imx_pcie_attach_pd(struct device *dev) if (IS_ERR(imx_pcie->pd_pcie_phy)) return PTR_ERR(imx_pcie->pd_pcie_phy); - link = device_link_add(dev, imx_pcie->pd_pcie_phy, - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!link) { + imx_pcie->pd_phy_link = device_link_add(dev, imx_pcie->pd_pcie_phy, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!imx_pcie->pd_phy_link) { dev_err(dev, "Failed to add device_link to pcie_phy pd\n"); return -EINVAL; } @@ -1951,6 +2017,10 @@ static int imx_pcie_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imx_pcie); + ret = devm_add_action_or_reset(dev, imx_pcie_detach_pd_action, imx_pcie); + if (ret) + return ret; + ret = imx_pcie_attach_pd(dev); if (ret) return ret; @@ -1975,7 +2045,7 @@ static int imx_pcie_probe(struct platform_device *pdev) pm_runtime_no_callbacks(dev); ret = devm_pm_runtime_set_active_enabled(dev); if (ret < 0) - return ret; + goto err_pwrctrl_destroy; } if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SKIP_L23_READY)) |
