diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2026-02-06 17:09:35 -0600 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-02-06 17:09:35 -0600 |
| commit | 62dea8718b7a7f6fc9b1408dd1f863f95191fbb6 (patch) | |
| tree | a0e8a2edf8fd5851304a71abf8baf5db51702967 /drivers/pci/controller | |
| parent | 93c398be499a5fcc3367f793fe3709cd3d13b6f9 (diff) | |
| parent | a152a90f53909544fe996fb0fa072ae9e355c452 (diff) | |
| download | lwn-62dea8718b7a7f6fc9b1408dd1f863f95191fbb6.tar.gz lwn-62dea8718b7a7f6fc9b1408dd1f863f95191fbb6.zip | |
Merge branch 'pci/controller/dwc-imx6'
- Add DT binding and driver support for an optional external refclock in
addition to the refclock from the internal PLL (Richard Zhu)
- Apply i.MX95 ERR051586 erratum workaround (release CLKREQ# so endpoint
can assert it when required) during resume (Richard Zhu)
- Enable i.MX95 REFCLK by overriding CLKREQ# so it's driven by default
(Richard Zhu)
- Clear CLKREQ# override if link is up and DT says 'supports-clkreq' so
endpoints can use CLKREQ# to exit the L1.2 state (Richard Zhu)
* pci/controller/dwc-imx6:
PCI: imx6: Clear CLKREQ# override if 'supports-clkreq' DT property is available
PCI: imx6: Add CLKREQ# override to enable REFCLK for i.MX95 PCIe
PCI: dwc: Invoke post_init in dw_pcie_resume_noirq()
PCI: imx6: Add external reference clock input mode support
dt-bindings: PCI: pci-imx6: Add external reference clock input
dt-bindings: PCI: dwc: Add external reference clock input
Diffstat (limited to 'drivers/pci/controller')
| -rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 69 | ||||
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-host.c | 3 |
2 files changed, 64 insertions, 8 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 06f45e009d7d..a5b8d0b71677 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -52,6 +52,8 @@ #define IMX95_PCIE_REF_CLKEN BIT(23) #define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) #define IMX95_PCIE_SS_RW_REG_1 0xf4 +#define IMX95_PCIE_CLKREQ_OVERRIDE_EN BIT(8) +#define IMX95_PCIE_CLKREQ_OVERRIDE_VAL BIT(9) #define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31) #define IMX95_PE0_GEN_CTRL_1 0x1050 @@ -137,6 +139,7 @@ struct imx_pcie_drvdata { int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable); int (*core_reset)(struct imx_pcie *pcie, bool assert); int (*wait_pll_lock)(struct imx_pcie *pcie); + void (*clr_clkreq_override)(struct imx_pcie *pcie); const struct dw_pcie_host_ops *ops; }; @@ -150,6 +153,8 @@ struct imx_pcie { struct gpio_desc *reset_gpiod; struct clk_bulk_data *clks; int num_clks; + bool supports_clkreq; + bool enable_ext_refclk; struct regmap *iomuxc_gpr; u16 msi_ctrl; u32 controller_id; @@ -242,6 +247,8 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie) static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) { + bool ext = imx_pcie->enable_ext_refclk; + /* * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready * Through Beacon or PERST# De-assertion @@ -260,13 +267,12 @@ static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) IMX95_PCIE_PHY_CR_PARA_SEL, IMX95_PCIE_PHY_CR_PARA_SEL); - regmap_update_bits(imx_pcie->iomuxc_gpr, - IMX95_PCIE_PHY_GEN_CTRL, - IMX95_PCIE_REF_USE_PAD, 0); - regmap_update_bits(imx_pcie->iomuxc_gpr, - IMX95_PCIE_SS_RW_REG_0, + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL, + ext ? IMX95_PCIE_REF_USE_PAD : 0, + IMX95_PCIE_REF_USE_PAD); + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, IMX95_PCIE_REF_CLKEN, - IMX95_PCIE_REF_CLKEN); + ext ? 0 : IMX95_PCIE_REF_CLKEN); return 0; } @@ -686,7 +692,7 @@ static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) return 0; } -static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) +static void imx8mm_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable) { int offset = imx_pcie_grp_offset(imx_pcie); @@ -696,6 +702,11 @@ static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) regmap_update_bits(imx_pcie->iomuxc_gpr, offset, IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN, enable ? IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0); +} + +static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) +{ + imx8mm_pcie_clkreq_override(imx_pcie, enable); return 0; } @@ -707,6 +718,32 @@ static int imx7d_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) return 0; } +static void imx95_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable) +{ + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_CLKREQ_OVERRIDE_EN, + enable ? IMX95_PCIE_CLKREQ_OVERRIDE_EN : 0); + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_CLKREQ_OVERRIDE_VAL, + enable ? IMX95_PCIE_CLKREQ_OVERRIDE_VAL : 0); +} + +static int imx95_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable) +{ + imx95_pcie_clkreq_override(imx_pcie, enable); + return 0; +} + +static void imx8mm_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie) +{ + imx8mm_pcie_clkreq_override(imx_pcie, false); +} + +static void imx95_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie) +{ + imx95_pcie_clkreq_override(imx_pcie, false); +} + static int imx_pcie_clk_enable(struct imx_pcie *imx_pcie) { struct dw_pcie *pci = imx_pcie->pci; @@ -1323,6 +1360,12 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp) dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); dw_pcie_dbi_ro_wr_dis(pci); } + + /* Clear CLKREQ# override if supports_clkreq is true and link is up */ + if (dw_pcie_link_up(pci) && imx_pcie->supports_clkreq) { + if (imx_pcie->drvdata->clr_clkreq_override) + imx_pcie->drvdata->clr_clkreq_override(imx_pcie); + } } /* @@ -1606,7 +1649,7 @@ static int imx_pcie_probe(struct platform_device *pdev) struct imx_pcie *imx_pcie; struct device_node *np; struct device_node *node = dev->of_node; - int ret, domain; + int i, ret, domain; u16 val; imx_pcie = devm_kzalloc(dev, sizeof(*imx_pcie), GFP_KERNEL); @@ -1657,6 +1700,9 @@ static int imx_pcie_probe(struct platform_device *pdev) if (imx_pcie->num_clks < 0) return dev_err_probe(dev, imx_pcie->num_clks, "failed to get clocks\n"); + for (i = 0; i < imx_pcie->num_clks; i++) + if (strncmp(imx_pcie->clks[i].id, "extref", 6) == 0) + imx_pcie->enable_ext_refclk = true; if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_PHYDRV)) { imx_pcie->phy = devm_phy_get(dev, "pcie-phy"); @@ -1744,6 +1790,7 @@ static int imx_pcie_probe(struct platform_device *pdev) /* Limit link speed */ pci->max_link_speed = 1; of_property_read_u32(node, "fsl,max-link-speed", &pci->max_link_speed); + imx_pcie->supports_clkreq = of_property_read_bool(node, "supports-clkreq"); ret = devm_regulator_get_enable_optional(&pdev->dev, "vpcie3v3aux"); if (ret < 0 && ret != -ENODEV) @@ -1881,6 +1928,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, .init_phy = imx8mq_pcie_init_phy, .enable_ref_clk = imx8mm_pcie_enable_ref_clk, + .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override, }, [IMX8MM] = { .variant = IMX8MM, @@ -1891,6 +1939,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_off[0] = IOMUXC_GPR12, .mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, .enable_ref_clk = imx8mm_pcie_enable_ref_clk, + .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override, }, [IMX8MP] = { .variant = IMX8MP, @@ -1901,6 +1950,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_off[0] = IOMUXC_GPR12, .mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, .enable_ref_clk = imx8mm_pcie_enable_ref_clk, + .clr_clkreq_override = imx8mm_pcie_clr_clkreq_override, }, [IMX8Q] = { .variant = IMX8Q, @@ -1921,6 +1971,8 @@ static const struct imx_pcie_drvdata drvdata[] = { .core_reset = imx95_pcie_core_reset, .init_phy = imx95_pcie_init_phy, .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, + .enable_ref_clk = imx95_pcie_enable_ref_clk, + .clr_clkreq_override = imx95_pcie_clr_clkreq_override, }, [IMX8MQ_EP] = { .variant = IMX8MQ_EP, @@ -1977,6 +2029,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .core_reset = imx95_pcie_core_reset, .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, .epc_features = &imx95_pcie_epc_features, + .enable_ref_clk = imx95_pcie_enable_ref_clk, .mode = DW_PCIE_EP_TYPE, }, }; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 75b28f7d8302..fb045d45542e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -1317,6 +1317,9 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci) if (ret) return ret; + if (pci->pp.ops->post_init) + pci->pp.ops->post_init(&pci->pp); + return ret; } EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); |
