From 60b3c27fb9b92b8b55cd8bdcc444c3f7cb556652 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Fri, 24 Jun 2022 17:34:25 +0300 Subject: PCI: dwc: Rename struct pcie_port to dw_pcie_rp All of the DW PCIe core driver entities except the pcie_port struct have names with the "dw_" prefix to distinguish local and common PCIe name spaces, and endpoint-related entities have an "_ep" suffix. Rename struct pcie_port to dw_pcie_rp to make it more consistent with other names. [bhelgaas: commit log] Link: https://lore.kernel.org/r/20220624143428.8334-16-Sergey.Semin@baikalelectronics.ru Signed-off-by: Serge Semin Signed-off-by: Bjorn Helgaas Reviewed-by: Rob Herring Reviewed-by: Neil Armstrong Reviewed-by: Manivannan Sadhasivam Acked-by: Jesper Nilsson --- drivers/pci/controller/dwc/pci-imx6.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7a285fb0f619..5ea01ed4674d 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -863,7 +863,7 @@ err_reset_phy: return ret; } -static int imx6_pcie_host_init(struct pcie_port *pp) +static int imx6_pcie_host_init(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); @@ -992,7 +992,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) { int ret; struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); - struct pcie_port *pp = &imx6_pcie->pci->pp; + struct dw_pcie_rp *pp = &imx6_pcie->pci->pp; if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; @@ -1291,7 +1291,7 @@ static struct platform_driver imx6_pcie_driver = { static void imx6_pcie_quirk(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; - struct pcie_port *pp = bus->sysdata; + struct dw_pcie_rp *pp = bus->sysdata; /* Bus parent is the PCI bridge, its parent is this platform driver */ if (!bus->dev.parent || !bus->dev.parent->parent) -- cgit v1.2.3 From 9d14ad61551d72fdd78ee87bdf741e00f0d31ca7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 19 Jul 2022 15:50:18 -0500 Subject: PCI: imx6: Convert to NOIRQ_SYSTEM_SLEEP_PM_OPS() Replace SET_NOIRQ_SYSTEM_SLEEP_PM_OPS() with NOIRQ_SYSTEM_SLEEP_PM_OPS(), which has the advantage that the compiler always sees the PM callbacks as referenced, so they don't need to be wrapped with "#ifdef CONFIG_PM_SLEEP" or tagged with "__maybe_unused" to avoid "defined but not used" warnings. See 1a3c7bb08826 ("PM: core: Add new *_PM_OPS macros, deprecate old ones"). Signed-off-by: Bjorn Helgaas Reviewed-by: Arnd Bergmann --- drivers/pci/controller/dwc/pci-imx6.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5ea01ed4674d..6f1dfbfc4304 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -884,7 +884,6 @@ static const struct dw_pcie_ops dw_pcie_ops = { .start_link = imx6_pcie_start_link, }; -#ifdef CONFIG_PM_SLEEP static void imx6_pcie_ltssm_disable(struct device *dev) { struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); @@ -1008,11 +1007,10 @@ static int imx6_pcie_resume_noirq(struct device *dev) return 0; } -#endif static const struct dev_pm_ops imx6_pcie_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq, - imx6_pcie_resume_noirq) + NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq, + imx6_pcie_resume_noirq) }; static int imx6_pcie_probe(struct platform_device *pdev) -- cgit v1.2.3 From 79f14b6f1c60ea79e2209e301e31c12eb2a71e26 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 14 Jul 2022 15:30:53 +0800 Subject: PCI: imx6: Move imx6_pcie_grp_offset(), imx6_pcie_configure_type() earlier Move imx6_pcie_grp_offset() and imx6_pcie_configure_type() earlier in the file since they depend on nothing and are used by several other functions that will be moved earlier. No functional change intended. Link: https://lore.kernel.org/r/1657783869-19194-2-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach Acked-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 6f1dfbfc4304..0f779f02334e 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -146,6 +146,31 @@ struct imx6_pcie { #define PHY_RX_OVRD_IN_LO_RX_DATA_EN BIT(5) #define PHY_RX_OVRD_IN_LO_RX_PLL_EN BIT(3) +static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie) +{ + WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ && + imx6_pcie->drvdata->variant != IMX8MM); + return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14; +} + +static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie) +{ + unsigned int mask, val; + + if (imx6_pcie->drvdata->variant == IMX8MQ && + imx6_pcie->controller_id == 1) { + mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE; + val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, + PCI_EXP_TYPE_ROOT_PORT); + } else { + mask = IMX6Q_GPR12_DEVICE_TYPE; + val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, + PCI_EXP_TYPE_ROOT_PORT); + } + + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val); +} + static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, bool exp_val) { struct dw_pcie *pci = imx6_pcie->pci; @@ -415,13 +440,6 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) imx6_pcie->gpio_active_high); } -static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie) -{ - WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ && - imx6_pcie->drvdata->variant != IMX8MM); - return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14; -} - static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -617,24 +635,6 @@ err_pcie_phy: } } -static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie) -{ - unsigned int mask, val; - - if (imx6_pcie->drvdata->variant == IMX8MQ && - imx6_pcie->controller_id == 1) { - mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE; - val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, - PCI_EXP_TYPE_ROOT_PORT); - } else { - mask = IMX6Q_GPR12_DEVICE_TYPE; - val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, - PCI_EXP_TYPE_ROOT_PORT); - } - - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val); -} - static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) { switch (imx6_pcie->drvdata->variant) { -- cgit v1.2.3 From 6b1e989e491088b79f2582c9c0c7925ce1d67e06 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 14 Jul 2022 15:30:54 +0800 Subject: PCI: imx6: Move PHY management functions together Collect imx6_pcie_init_phy(), imx7d_pcie_wait_for_phy_pll_lock(), and imx6_setup_phy_mpll() earlier with other PHY-related code. No functional change intended. Link: https://lore.kernel.org/r/1657783869-19194-3-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach Acked-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 256 +++++++++++++++++----------------- 1 file changed, 128 insertions(+), 128 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 0f779f02334e..a4951c44a7f1 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -296,6 +296,134 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, u16 data) return 0; } +static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) +{ + switch (imx6_pcie->drvdata->variant) { + case IMX8MM: + /* + * The PHY initialization had been done in the PHY + * driver, break here directly. + */ + break; + case IMX8MQ: + /* + * TODO: Currently this code assumes external + * oscillator is being used + */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, + imx6_pcie_grp_offset(imx6_pcie), + IMX8MQ_GPR_PCIE_REF_USE_PAD, + IMX8MQ_GPR_PCIE_REF_USE_PAD); + /* + * Regarding the datasheet, the PCIE_VPH is suggested + * to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the + * VREG_BYPASS should be cleared to zero. + */ + if (imx6_pcie->vph && + regulator_get_voltage(imx6_pcie->vph) > 3000000) + regmap_update_bits(imx6_pcie->iomuxc_gpr, + imx6_pcie_grp_offset(imx6_pcie), + IMX8MQ_GPR_PCIE_VREG_BYPASS, + 0); + break; + case IMX7D: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0); + break; + case IMX6SX: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6SX_GPR12_PCIE_RX_EQ_MASK, + IMX6SX_GPR12_PCIE_RX_EQ_2); + fallthrough; + default: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); + + /* configure constant input signal to the pcie ctrl and phy */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_LOS_LEVEL, 9 << 4); + + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, + IMX6Q_GPR8_TX_DEEMPH_GEN1, + imx6_pcie->tx_deemph_gen1 << 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, + IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, + imx6_pcie->tx_deemph_gen2_3p5db << 6); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, + IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, + imx6_pcie->tx_deemph_gen2_6db << 12); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, + IMX6Q_GPR8_TX_SWING_FULL, + imx6_pcie->tx_swing_full << 18); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, + IMX6Q_GPR8_TX_SWING_LOW, + imx6_pcie->tx_swing_low << 25); + break; + } + + imx6_pcie_configure_type(imx6_pcie); +} + +static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) +{ + u32 val; + struct device *dev = imx6_pcie->pci->dev; + + if (regmap_read_poll_timeout(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR22, val, + val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED, + PHY_PLL_LOCK_WAIT_USLEEP_MAX, + PHY_PLL_LOCK_WAIT_TIMEOUT)) + dev_err(dev, "PCIe PLL lock timeout\n"); +} + +static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) +{ + unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy); + int mult, div; + u16 val; + + if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY)) + return 0; + + switch (phy_rate) { + case 125000000: + /* + * The default settings of the MPLL are for a 125MHz input + * clock, so no need to reconfigure anything in that case. + */ + return 0; + case 100000000: + mult = 25; + div = 0; + break; + case 200000000: + mult = 25; + div = 1; + break; + default: + dev_err(imx6_pcie->pci->dev, + "Unsupported PHY reference clock rate %lu\n", phy_rate); + return -EINVAL; + } + + pcie_phy_read(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, &val); + val &= ~(PCIE_PHY_MPLL_MULTIPLIER_MASK << + PCIE_PHY_MPLL_MULTIPLIER_SHIFT); + val |= mult << PCIE_PHY_MPLL_MULTIPLIER_SHIFT; + val |= PCIE_PHY_MPLL_MULTIPLIER_OVRD; + pcie_phy_write(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, val); + + pcie_phy_read(imx6_pcie, PCIE_PHY_ATEOVRD, &val); + val &= ~(PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK << + PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT); + val |= div << PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT; + val |= PCIE_PHY_ATEOVRD_EN; + pcie_phy_write(imx6_pcie, PCIE_PHY_ATEOVRD, val); + + return 0; +} + static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie) { u16 tmp; @@ -500,19 +628,6 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) return ret; } -static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) -{ - u32 val; - struct device *dev = imx6_pcie->pci->dev; - - if (regmap_read_poll_timeout(imx6_pcie->iomuxc_gpr, - IOMUXC_GPR22, val, - val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED, - PHY_PLL_LOCK_WAIT_USLEEP_MAX, - PHY_PLL_LOCK_WAIT_TIMEOUT)) - dev_err(dev, "PCIe PLL lock timeout\n"); -} - static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -635,121 +750,6 @@ err_pcie_phy: } } -static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) -{ - switch (imx6_pcie->drvdata->variant) { - case IMX8MM: - /* - * The PHY initialization had been done in the PHY - * driver, break here directly. - */ - break; - case IMX8MQ: - /* - * TODO: Currently this code assumes external - * oscillator is being used - */ - regmap_update_bits(imx6_pcie->iomuxc_gpr, - imx6_pcie_grp_offset(imx6_pcie), - IMX8MQ_GPR_PCIE_REF_USE_PAD, - IMX8MQ_GPR_PCIE_REF_USE_PAD); - /* - * Regarding the datasheet, the PCIE_VPH is suggested - * to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the - * VREG_BYPASS should be cleared to zero. - */ - if (imx6_pcie->vph && - regulator_get_voltage(imx6_pcie->vph) > 3000000) - regmap_update_bits(imx6_pcie->iomuxc_gpr, - imx6_pcie_grp_offset(imx6_pcie), - IMX8MQ_GPR_PCIE_VREG_BYPASS, - 0); - break; - case IMX7D: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0); - break; - case IMX6SX: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6SX_GPR12_PCIE_RX_EQ_MASK, - IMX6SX_GPR12_PCIE_RX_EQ_2); - fallthrough; - default: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); - - /* configure constant input signal to the pcie ctrl and phy */ - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_LOS_LEVEL, 9 << 4); - - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, - IMX6Q_GPR8_TX_DEEMPH_GEN1, - imx6_pcie->tx_deemph_gen1 << 0); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, - IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, - imx6_pcie->tx_deemph_gen2_3p5db << 6); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, - IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, - imx6_pcie->tx_deemph_gen2_6db << 12); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, - IMX6Q_GPR8_TX_SWING_FULL, - imx6_pcie->tx_swing_full << 18); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, - IMX6Q_GPR8_TX_SWING_LOW, - imx6_pcie->tx_swing_low << 25); - break; - } - - imx6_pcie_configure_type(imx6_pcie); -} - -static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) -{ - unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy); - int mult, div; - u16 val; - - if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY)) - return 0; - - switch (phy_rate) { - case 125000000: - /* - * The default settings of the MPLL are for a 125MHz input - * clock, so no need to reconfigure anything in that case. - */ - return 0; - case 100000000: - mult = 25; - div = 0; - break; - case 200000000: - mult = 25; - div = 1; - break; - default: - dev_err(imx6_pcie->pci->dev, - "Unsupported PHY reference clock rate %lu\n", phy_rate); - return -EINVAL; - } - - pcie_phy_read(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, &val); - val &= ~(PCIE_PHY_MPLL_MULTIPLIER_MASK << - PCIE_PHY_MPLL_MULTIPLIER_SHIFT); - val |= mult << PCIE_PHY_MPLL_MULTIPLIER_SHIFT; - val |= PCIE_PHY_MPLL_MULTIPLIER_OVRD; - pcie_phy_write(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, val); - - pcie_phy_read(imx6_pcie, PCIE_PHY_ATEOVRD, &val); - val &= ~(PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK << - PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT); - val |= div << PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT; - val |= PCIE_PHY_ATEOVRD_EN; - pcie_phy_write(imx6_pcie, PCIE_PHY_ATEOVRD, val); - - return 0; -} - static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; -- cgit v1.2.3 From 276509690c2e4993016d1c2e220ca1929791b812 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 14 Jul 2022 15:30:55 +0800 Subject: PCI: imx6: Move imx6_pcie_enable_ref_clk() earlier Move imx6_pcie_enable_ref_clk() earlier so it's not in the middle between imx6_pcie_assert_core_reset() and imx6_pcie_deassert_core_reset(). No functional change intended. Link: https://lore.kernel.org/r/1657783869-19194-4-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach Acked-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 96 +++++++++++++++++------------------ 1 file changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index a4951c44a7f1..c0616979c5c1 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -520,54 +520,6 @@ static int imx6_pcie_attach_pd(struct device *dev) return 0; } -static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) -{ - struct device *dev = imx6_pcie->pci->dev; - - switch (imx6_pcie->drvdata->variant) { - case IMX7D: - case IMX8MQ: - reset_control_assert(imx6_pcie->pciephy_reset); - fallthrough; - case IMX8MM: - reset_control_assert(imx6_pcie->apps_reset); - break; - case IMX6SX: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6SX_GPR12_PCIE_TEST_POWERDOWN, - IMX6SX_GPR12_PCIE_TEST_POWERDOWN); - /* Force PCIe PHY reset */ - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, - IMX6SX_GPR5_PCIE_BTNRST_RESET, - IMX6SX_GPR5_PCIE_BTNRST_RESET); - break; - case IMX6QP: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, - IMX6Q_GPR1_PCIE_SW_RST, - IMX6Q_GPR1_PCIE_SW_RST); - break; - case IMX6Q: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, - IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, - IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); - break; - } - - if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { - int ret = regulator_disable(imx6_pcie->vpcie); - - if (ret) - dev_err(dev, "failed to disable vpcie regulator: %d\n", - ret); - } - - /* Some boards don't have PCIe reset GPIO. */ - if (gpio_is_valid(imx6_pcie->reset_gpio)) - gpio_set_value_cansleep(imx6_pcie->reset_gpio, - imx6_pcie->gpio_active_high); -} - static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -628,6 +580,54 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) return ret; } +static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) +{ + struct device *dev = imx6_pcie->pci->dev; + + switch (imx6_pcie->drvdata->variant) { + case IMX7D: + case IMX8MQ: + reset_control_assert(imx6_pcie->pciephy_reset); + fallthrough; + case IMX8MM: + reset_control_assert(imx6_pcie->apps_reset); + break; + case IMX6SX: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6SX_GPR12_PCIE_TEST_POWERDOWN, + IMX6SX_GPR12_PCIE_TEST_POWERDOWN); + /* Force PCIe PHY reset */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, + IMX6SX_GPR5_PCIE_BTNRST_RESET, + IMX6SX_GPR5_PCIE_BTNRST_RESET); + break; + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, + IMX6Q_GPR1_PCIE_SW_RST, + IMX6Q_GPR1_PCIE_SW_RST); + break; + case IMX6Q: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, + IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, + IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); + break; + } + + if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { + int ret = regulator_disable(imx6_pcie->vpcie); + + if (ret) + dev_err(dev, "failed to disable vpcie regulator: %d\n", + ret); + } + + /* Some boards don't have PCIe reset GPIO. */ + if (gpio_is_valid(imx6_pcie->reset_gpio)) + gpio_set_value_cansleep(imx6_pcie->reset_gpio, + imx6_pcie->gpio_active_high); +} + static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; -- cgit v1.2.3 From 34b1b9022586bf909ad0c7213d8669902150fc2a Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:30:56 +0800 Subject: PCI: imx6: Move imx6_pcie_clk_disable() earlier Move imx6_pcie_clk_disable() earlier to be near other clock-related functions. No functional change intended. [bhelgaas: reorder patch so pure moves are earlier] Link: https://lore.kernel.org/r/1657783869-19194-5-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 48 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index c0616979c5c1..09cf496b9a2a 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -580,6 +580,30 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) return ret; } +static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) +{ + clk_disable_unprepare(imx6_pcie->pcie); + clk_disable_unprepare(imx6_pcie->pcie_phy); + clk_disable_unprepare(imx6_pcie->pcie_bus); + + switch (imx6_pcie->drvdata->variant) { + case IMX6SX: + clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); + break; + case IMX7D: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); + break; + case IMX8MQ: + case IMX8MM: + clk_disable_unprepare(imx6_pcie->pcie_aux); + break; + default: + break; + } +} + static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) { struct device *dev = imx6_pcie->pci->dev; @@ -940,30 +964,6 @@ pm_turnoff_sleep: usleep_range(1000, 10000); } -static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) -{ - clk_disable_unprepare(imx6_pcie->pcie); - clk_disable_unprepare(imx6_pcie->pcie_phy); - clk_disable_unprepare(imx6_pcie->pcie_bus); - - switch (imx6_pcie->drvdata->variant) { - case IMX6SX: - clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); - break; - case IMX7D: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, - IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); - break; - case IMX8MQ: - case IMX8MM: - clk_disable_unprepare(imx6_pcie->pcie_aux); - break; - default: - break; - } -} - static int imx6_pcie_suspend_noirq(struct device *dev) { struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); -- cgit v1.2.3 From d0a75c791f981546618c917293bc20094a923410 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 14 Jul 2022 15:30:57 +0800 Subject: PCI: imx6: Factor out ref clock disable to match enable The PCIe ref clocks are specific to different variants. The enables are already split out into imx6_pcie_enable_ref_clk(), but the disables were combined with the more generic bus/phy/pcie clock disables in imx6_pcie_clk_disable(). Split out the variant-specific disables into imx6_pcie_disable_ref_clk() to match imx6_pcie_enable_ref_clk(). No functional change intended. Link: https://lore.kernel.org/r/1657783869-19194-6-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach Acked-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 09cf496b9a2a..848c8eef949a 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -580,12 +580,8 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) return ret; } -static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) +static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie) { - clk_disable_unprepare(imx6_pcie->pcie); - clk_disable_unprepare(imx6_pcie->pcie_phy); - clk_disable_unprepare(imx6_pcie->pcie_bus); - switch (imx6_pcie->drvdata->variant) { case IMX6SX: clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); @@ -595,8 +591,8 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); break; - case IMX8MQ: case IMX8MM: + case IMX8MQ: clk_disable_unprepare(imx6_pcie->pcie_aux); break; default: @@ -604,6 +600,14 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) } } +static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) +{ + clk_disable_unprepare(imx6_pcie->pcie); + clk_disable_unprepare(imx6_pcie->pcie_phy); + clk_disable_unprepare(imx6_pcie->pcie_bus); + imx6_pcie_disable_ref_clk(imx6_pcie); +} + static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) { struct device *dev = imx6_pcie->pci->dev; -- cgit v1.2.3 From 835fe229d7099dc07f34f16780cbad9081da7bf1 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:30:58 +0800 Subject: PCI: imx6: Collect clock enables in imx6_pcie_clk_enable() Encapsulate the i.MX PCIe clock enable operations into one standalone function, imx6_pcie_clk_enable(). No functional change intended. [bhelgaas: split pure code moves into separate patches] Link: https://lore.kernel.org/r/1657783869-19194-7-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 95 +++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 39 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 848c8eef949a..f7c01c01f031 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -600,6 +600,58 @@ static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie) } } +static int imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie) +{ + struct dw_pcie *pci = imx6_pcie->pci; + struct device *dev = pci->dev; + int ret; + + ret = clk_prepare_enable(imx6_pcie->pcie_phy); + if (ret) { + dev_err(dev, "unable to enable pcie_phy clock\n"); + return ret; + } + + ret = clk_prepare_enable(imx6_pcie->pcie_bus); + if (ret) { + dev_err(dev, "unable to enable pcie_bus clock\n"); + goto err_pcie_bus; + } + + ret = clk_prepare_enable(imx6_pcie->pcie); + if (ret) { + dev_err(dev, "unable to enable pcie clock\n"); + goto err_pcie; + } + + ret = imx6_pcie_enable_ref_clk(imx6_pcie); + if (ret) { + dev_err(dev, "unable to enable pcie ref clock\n"); + goto err_ref_clk; + } + + switch (imx6_pcie->drvdata->variant) { + case IMX8MM: + if (phy_power_on(imx6_pcie->phy)) + dev_err(dev, "unable to power on PHY\n"); + break; + default: + break; + } + /* allow the clocks to stabilize */ + usleep_range(200, 500); + return 0; + +err_ref_clk: + clk_disable_unprepare(imx6_pcie->pcie); +err_pcie: + clk_disable_unprepare(imx6_pcie->pcie_bus); +err_pcie_bus: + clk_disable_unprepare(imx6_pcie->pcie_phy); + + return ret; +} + static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) { clk_disable_unprepare(imx6_pcie->pcie); @@ -671,40 +723,11 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) } } - ret = clk_prepare_enable(imx6_pcie->pcie_phy); - if (ret) { - dev_err(dev, "unable to enable pcie_phy clock\n"); - goto err_pcie_phy; - } - - ret = clk_prepare_enable(imx6_pcie->pcie_bus); - if (ret) { - dev_err(dev, "unable to enable pcie_bus clock\n"); - goto err_pcie_bus; - } - - ret = clk_prepare_enable(imx6_pcie->pcie); - if (ret) { - dev_err(dev, "unable to enable pcie clock\n"); - goto err_pcie; - } - - ret = imx6_pcie_enable_ref_clk(imx6_pcie); + ret = imx6_pcie_clk_enable(imx6_pcie); if (ret) { - dev_err(dev, "unable to enable pcie ref clock\n"); - goto err_ref_clk; - } - - switch (imx6_pcie->drvdata->variant) { - case IMX8MM: - if (phy_power_on(imx6_pcie->phy)) - dev_err(dev, "unable to power on PHY\n"); - break; - default: - break; + dev_err(dev, "unable to enable pcie clocks: %d\n", ret); + goto err_clks; } - /* allow the clocks to stabilize */ - usleep_range(200, 500); switch (imx6_pcie->drvdata->variant) { case IMX8MQ: @@ -763,13 +786,7 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) return; -err_ref_clk: - clk_disable_unprepare(imx6_pcie->pcie); -err_pcie: - clk_disable_unprepare(imx6_pcie->pcie_bus); -err_pcie_bus: - clk_disable_unprepare(imx6_pcie->pcie_phy); -err_pcie_phy: +err_clks: if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { ret = regulator_disable(imx6_pcie->vpcie); if (ret) -- cgit v1.2.3 From 9751f65db025a19a8f73e0531240b1d21a12139c Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:30:59 +0800 Subject: PCI: imx6: Propagate .host_init() errors to caller Since dw_pcie_host_init() checks for errors from ops->host_init(), check for errors when enabling power regulators and clocks and return them. [bhelgaas: commit log] Link: https://lore.kernel.org/r/1657783869-19194-8-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index f7c01c01f031..515515145306 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -708,7 +708,7 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) imx6_pcie->gpio_active_high); } -static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) +static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; struct device *dev = pci->dev; @@ -719,7 +719,7 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) if (ret) { dev_err(dev, "failed to enable vpcie regulator: %d\n", ret); - return; + return ret; } } @@ -784,7 +784,7 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) msleep(100); } - return; + return 0; err_clks: if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { @@ -793,6 +793,7 @@ err_clks: dev_err(dev, "failed to disable vpcie regulator: %d\n", ret); } + return ret; } static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) @@ -911,11 +912,18 @@ err_reset_phy: static int imx6_pcie_host_init(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct device *dev = pci->dev; struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); + int ret; imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); - imx6_pcie_deassert_core_reset(imx6_pcie); + ret = imx6_pcie_deassert_core_reset(imx6_pcie); + if (ret < 0) { + dev_err(dev, "pcie deassert core reset failed: %d\n", ret); + return ret; + } + imx6_setup_phy_mpll(imx6_pcie); return 0; -- cgit v1.2.3 From fea446eb9c77209dcd056fbd86c269a390075a29 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:00 +0800 Subject: PCI: imx6: Disable i.MX6QDL clock when disabling ref clocks When disabling PCIe clocks, disable i.MX6QDL ref clock too. Link: https://lore.kernel.org/r/1657783869-19194-9-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 515515145306..f2157533442f 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -586,6 +586,14 @@ static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie) case IMX6SX: clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); break; + case IMX6QP: + case IMX6Q: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, + IMX6Q_GPR1_PCIE_REF_CLK_EN, 0); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, + IMX6Q_GPR1_PCIE_TEST_PD, + IMX6Q_GPR1_PCIE_TEST_PD); + break; case IMX7D: regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, -- cgit v1.2.3 From cfacf22e0df2e3db3e90306f830a4f6c08829b05 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:01 +0800 Subject: PCI: imx6: Call host init function directly in resume Call imx6_pcie_host_init() instead of duplicating codes in resume. Note that this also means we do MPLL setup again during resume, which we didn't do before. [bhelgaas: add MPLL setup note, pointed out by Lucas] Link: https://lore.kernel.org/r/1657783869-19194-10-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index f2157533442f..20bee1a9e651 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1033,9 +1033,9 @@ static int imx6_pcie_resume_noirq(struct device *dev) if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; - imx6_pcie_assert_core_reset(imx6_pcie); - imx6_pcie_init_phy(imx6_pcie); - imx6_pcie_deassert_core_reset(imx6_pcie); + ret = imx6_pcie_host_init(pp); + if (ret) + return ret; dw_pcie_setup_rc(pp); ret = imx6_pcie_start_link(imx6_pcie->pci); -- cgit v1.2.3 From a4bb720eeb1e2f2b895734ccce0dceec0a64eebd Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:02 +0800 Subject: PCI: imx6: Turn off regulator when system is in suspend mode The driver should undo any enables it did itself. The regulator disable shouldn't be basing decisions on regulator_is_enabled(). Move the regulator_disable to the suspend function, turn off regulator when the system is in suspend mode. Link: https://lore.kernel.org/r/1657783869-19194-11-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-imx6.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 20bee1a9e651..4ff6cb9ef97f 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -670,8 +670,6 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) { - struct device *dev = imx6_pcie->pci->dev; - switch (imx6_pcie->drvdata->variant) { case IMX7D: case IMX8MQ: @@ -702,14 +700,6 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) break; } - if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { - int ret = regulator_disable(imx6_pcie->vpcie); - - if (ret) - dev_err(dev, "failed to disable vpcie regulator: %d\n", - ret); - } - /* Some boards don't have PCIe reset GPIO. */ if (gpio_is_valid(imx6_pcie->reset_gpio)) gpio_set_value_cansleep(imx6_pcie->reset_gpio, @@ -722,7 +712,7 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) struct device *dev = pci->dev; int ret; - if (imx6_pcie->vpcie && !regulator_is_enabled(imx6_pcie->vpcie)) { + if (imx6_pcie->vpcie) { ret = regulator_enable(imx6_pcie->vpcie); if (ret) { dev_err(dev, "failed to enable vpcie regulator: %d\n", @@ -795,7 +785,7 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) return 0; err_clks: - if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { + if (imx6_pcie->vpcie) { ret = regulator_disable(imx6_pcie->vpcie); if (ret) dev_err(dev, "failed to disable vpcie regulator: %d\n", @@ -1021,6 +1011,9 @@ static int imx6_pcie_suspend_noirq(struct device *dev) break; } + if (imx6_pcie->vpcie) + regulator_disable(imx6_pcie->vpcie); + return 0; } -- cgit v1.2.3 From f0691e326b270d86fff408f347bd6498949f3076 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:03 +0800 Subject: PCI: imx6: Move regulator enable out of imx6_pcie_deassert_core_reset() Move regulator enable out of imx6_pcie_deassert_core_reset(), since the regulator_enable() has nothing to do with imx6_pcie_deassert_core_reset(). Link: https://lore.kernel.org/r/1657783869-19194-12-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-imx6.c | 36 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 4ff6cb9ef97f..cfb67f422e46 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -712,19 +712,10 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) struct device *dev = pci->dev; int ret; - if (imx6_pcie->vpcie) { - ret = regulator_enable(imx6_pcie->vpcie); - if (ret) { - dev_err(dev, "failed to enable vpcie regulator: %d\n", - ret); - return ret; - } - } - ret = imx6_pcie_clk_enable(imx6_pcie); if (ret) { dev_err(dev, "unable to enable pcie clocks: %d\n", ret); - goto err_clks; + return ret; } switch (imx6_pcie->drvdata->variant) { @@ -783,15 +774,6 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) } return 0; - -err_clks: - if (imx6_pcie->vpcie) { - ret = regulator_disable(imx6_pcie->vpcie); - if (ret) - dev_err(dev, "failed to disable vpcie regulator: %d\n", - ret); - } - return ret; } static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) @@ -914,17 +896,31 @@ static int imx6_pcie_host_init(struct dw_pcie_rp *pp) struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); int ret; + if (imx6_pcie->vpcie) { + ret = regulator_enable(imx6_pcie->vpcie); + if (ret) { + dev_err(dev, "failed to enable vpcie regulator: %d\n", + ret); + return ret; + } + } + imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); ret = imx6_pcie_deassert_core_reset(imx6_pcie); if (ret < 0) { dev_err(dev, "pcie deassert core reset failed: %d\n", ret); - return ret; + goto err_reg_disable; } imx6_setup_phy_mpll(imx6_pcie); return 0; + +err_reg_disable: + if (imx6_pcie->vpcie) + regulator_disable(imx6_pcie->vpcie); + return ret; } static const struct dw_pcie_host_ops imx6_pcie_host_ops = { -- cgit v1.2.3 From 508919d0a95c04ef04469e60776146a9795c07cf Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:04 +0800 Subject: PCI: imx6: Mark the link down as non-fatal error If the PCIe link is down, return zero from imx6_pcie_start_link() so the driver will probe successfully. Link: https://lore.kernel.org/r/1657783869-19194-13-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index cfb67f422e46..a693286c9843 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -836,7 +836,9 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); - dw_pcie_wait_for_link(pci); + ret = dw_pcie_wait_for_link(pci); + if (ret) + goto err_reset_phy; if (pci->link_gen == 2) { /* Allow Gen2 mode after the link is up. */ @@ -872,7 +874,9 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) } /* Make sure link training is finished as well! */ - dw_pcie_wait_for_link(pci); + ret = dw_pcie_wait_for_link(pci); + if (ret) + goto err_reset_phy; } else { dev_info(dev, "Link: Gen2 disabled\n"); } @@ -886,7 +890,7 @@ err_reset_phy: dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0), dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1)); imx6_pcie_reset_phy(imx6_pcie); - return ret; + return 0; } static int imx6_pcie_host_init(struct dw_pcie_rp *pp) @@ -1027,10 +1031,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) return ret; dw_pcie_setup_rc(pp); - ret = imx6_pcie_start_link(imx6_pcie->pci); - if (ret < 0) - dev_info(dev, "pcie link is down after resume.\n"); - + imx6_pcie_start_link(imx6_pcie->pci); return 0; } -- cgit v1.2.3 From af48f8226e94555bd3c5f93a437acf714024c2c3 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:05 +0800 Subject: PCI: imx6: Reduce resume time by only starting link if it was up before suspend i.MX PCIe doesn't support hotplug. During resume, only start PCIe link training when the link was up before system suspend to avoid the long latency in the link training period. Link: https://lore.kernel.org/r/1657783869-19194-14-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-imx6.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index a693286c9843..33c5089eb46e 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -67,6 +67,7 @@ struct imx6_pcie { struct dw_pcie *pci; int reset_gpio; bool gpio_active_high; + bool link_is_up; struct clk *pcie_bus; struct clk *pcie_phy; struct clk *pcie_inbound_axi; @@ -881,11 +882,13 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) dev_info(dev, "Link: Gen2 disabled\n"); } + imx6_pcie->link_is_up = true; tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA); dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS); return 0; err_reset_phy: + imx6_pcie->link_is_up = false; dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n", dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0), dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1)); @@ -1031,7 +1034,9 @@ static int imx6_pcie_resume_noirq(struct device *dev) return ret; dw_pcie_setup_rc(pp); - imx6_pcie_start_link(imx6_pcie->pci); + if (imx6_pcie->link_is_up) + imx6_pcie_start_link(imx6_pcie->pci); + return 0; } -- cgit v1.2.3 From cf236e0c0d59b36e500c7a37e310e0cd6eefa5a0 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:06 +0800 Subject: PCI: imx6: Do not hide PHY driver callbacks and refine the error handling Move the phy_power_on() to host_init from imx6_pcie_clk_enable(). Move the phy_init() to host_init from imx6_pcie_deassert_core_reset(). Refine the error handling in imx6_pcie_host_init() accordingly. Link: https://lore.kernel.org/r/1657783869-19194-15-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-imx6.c | 36 ++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 33c5089eb46e..7a9047f0a27a 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -639,14 +639,6 @@ static int imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie) goto err_ref_clk; } - switch (imx6_pcie->drvdata->variant) { - case IMX8MM: - if (phy_power_on(imx6_pcie->phy)) - dev_err(dev, "unable to power on PHY\n"); - break; - default: - break; - } /* allow the clocks to stabilize */ usleep_range(200, 500); return 0; @@ -723,10 +715,6 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) case IMX8MQ: reset_control_deassert(imx6_pcie->pciephy_reset); break; - case IMX8MM: - if (phy_init(imx6_pcie->phy)) - dev_err(dev, "waiting for phy ready timeout!\n"); - break; case IMX7D: reset_control_deassert(imx6_pcie->pciephy_reset); @@ -762,6 +750,7 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) usleep_range(200, 500); break; case IMX6Q: /* Nothing to do */ + case IMX8MM: break; } @@ -914,16 +903,37 @@ static int imx6_pcie_host_init(struct dw_pcie_rp *pp) imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); + + if (imx6_pcie->phy) { + ret = phy_power_on(imx6_pcie->phy); + if (ret) { + dev_err(dev, "pcie PHY power up failed\n"); + goto err_reg_disable; + } + } + ret = imx6_pcie_deassert_core_reset(imx6_pcie); if (ret < 0) { dev_err(dev, "pcie deassert core reset failed: %d\n", ret); - goto err_reg_disable; + goto err_phy_off; } + if (imx6_pcie->phy) { + ret = phy_init(imx6_pcie->phy); + if (ret) { + dev_err(dev, "waiting for PHY ready timeout!\n"); + goto err_clk_disable; + } + } imx6_setup_phy_mpll(imx6_pcie); return 0; +err_clk_disable: + imx6_pcie_clk_disable(imx6_pcie); +err_phy_off: + if (imx6_pcie->phy) + phy_power_off(imx6_pcie->phy); err_reg_disable: if (imx6_pcie->vpcie) regulator_disable(imx6_pcie->vpcie); -- cgit v1.2.3 From 34eb543f4ffa6d9bcadfee29adb05d7c5937bc34 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 14 Jul 2022 15:31:07 +0800 Subject: PCI: imx6: Disable clocks in reverse order of enable imx6_pcie_clk_enable() enables clocks in the order: pcie_phy pcie_bus pcie imx6_pcie_enable_ref_clk Change imx6_pcie_clk_disable() to disable them in the reverse order. Link: https://lore.kernel.org/r/1657783869-19194-16-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach Acked-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7a9047f0a27a..cd151222d000 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -655,10 +655,10 @@ err_pcie_bus: static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) { + imx6_pcie_disable_ref_clk(imx6_pcie); clk_disable_unprepare(imx6_pcie->pcie); - clk_disable_unprepare(imx6_pcie->pcie_phy); clk_disable_unprepare(imx6_pcie->pcie_bus); - imx6_pcie_disable_ref_clk(imx6_pcie); + clk_disable_unprepare(imx6_pcie->pcie_phy); } static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) -- cgit v1.2.3 From 1c5e761565c10945049e5d52fb17540cda23690e Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:08 +0800 Subject: PCI: imx6: Move the imx6_pcie_ltssm_disable() earlier Move the imx6_pcie_ltssm_disable() earlier and place it just behind the imx6_pcie_ltssm_enable(), since it might not be only used by suspend callback directly. To be symmetric with imx6_pcie_ltssm_enable(), add the IMX6Q and IMX8MQ switch cases in imx6_pcie_ltssm_disable(). Link: https://lore.kernel.org/r/1657783869-19194-17-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-imx6.c | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index cd151222d000..1f5347bd694b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -805,6 +805,25 @@ static void imx6_pcie_ltssm_enable(struct device *dev) } } +static void imx6_pcie_ltssm_disable(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + switch (imx6_pcie->drvdata->variant) { + case IMX6Q: + case IMX6SX: + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, 0); + break; + case IMX7D: + case IMX8MQ: + case IMX8MM: + reset_control_assert(imx6_pcie->apps_reset); + break; + } +} + static int imx6_pcie_start_link(struct dw_pcie *pci) { struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); @@ -948,25 +967,6 @@ static const struct dw_pcie_ops dw_pcie_ops = { .start_link = imx6_pcie_start_link, }; -static void imx6_pcie_ltssm_disable(struct device *dev) -{ - struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); - - switch (imx6_pcie->drvdata->variant) { - case IMX6SX: - case IMX6QP: - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 0); - break; - case IMX7D: - case IMX8MM: - reset_control_assert(imx6_pcie->apps_reset); - break; - default: - dev_err(dev, "ltssm_disable not supported\n"); - } -} - static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) { struct device *dev = imx6_pcie->pci->dev; -- cgit v1.2.3 From 835a345b18b013cc03b0fc392394fbccd61d4efb Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 14 Jul 2022 15:31:09 +0800 Subject: PCI: imx6: Reformat suspend callback to keep symmetric with resume Create imx6_pcie_stop_link() and imx6_pcie_host_exit() functions. Encapsulate clocks, regulators disables and PHY uninitialization into imx6_pcie_host_exit(). To keep suspend/resume symmetric as much as possible, invoke these two new created functions in suspend callback. To be symmetric with imx6_pcie_host_exit(), move imx6_pcie_clk_enable() to imx6_pcie_host_init() from imx6_pcie_deassert_core_reset(). Link: https://lore.kernel.org/r/1657783869-19194-18-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 62 +++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 25 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 1f5347bd694b..81ab6ddb0d59 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -703,13 +703,6 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; struct device *dev = pci->dev; - int ret; - - ret = imx6_pcie_clk_enable(imx6_pcie); - if (ret) { - dev_err(dev, "unable to enable pcie clocks: %d\n", ret); - return ret; - } switch (imx6_pcie->drvdata->variant) { case IMX8MQ: @@ -904,6 +897,14 @@ err_reset_phy: return 0; } +static void imx6_pcie_stop_link(struct dw_pcie *pci) +{ + struct device *dev = pci->dev; + + /* Turn off PCIe LTSSM */ + imx6_pcie_ltssm_disable(dev); +} + static int imx6_pcie_host_init(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -923,11 +924,17 @@ static int imx6_pcie_host_init(struct dw_pcie_rp *pp) imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); + ret = imx6_pcie_clk_enable(imx6_pcie); + if (ret) { + dev_err(dev, "unable to enable pcie clocks: %d\n", ret); + goto err_reg_disable; + } + if (imx6_pcie->phy) { ret = phy_power_on(imx6_pcie->phy); if (ret) { dev_err(dev, "pcie PHY power up failed\n"); - goto err_reg_disable; + goto err_clk_disable; } } @@ -941,24 +948,40 @@ static int imx6_pcie_host_init(struct dw_pcie_rp *pp) ret = phy_init(imx6_pcie->phy); if (ret) { dev_err(dev, "waiting for PHY ready timeout!\n"); - goto err_clk_disable; + goto err_phy_off; } } imx6_setup_phy_mpll(imx6_pcie); return 0; -err_clk_disable: - imx6_pcie_clk_disable(imx6_pcie); err_phy_off: if (imx6_pcie->phy) phy_power_off(imx6_pcie->phy); +err_clk_disable: + imx6_pcie_clk_disable(imx6_pcie); err_reg_disable: if (imx6_pcie->vpcie) regulator_disable(imx6_pcie->vpcie); return ret; } +static void imx6_pcie_host_exit(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); + + if (imx6_pcie->phy) { + if (phy_power_off(imx6_pcie->phy)) + dev_err(pci->dev, "unable to power off PHY\n"); + phy_exit(imx6_pcie->phy); + } + imx6_pcie_clk_disable(imx6_pcie); + + if (imx6_pcie->vpcie) + regulator_disable(imx6_pcie->vpcie); +} + static const struct dw_pcie_host_ops imx6_pcie_host_ops = { .host_init = imx6_pcie_host_init, }; @@ -1007,25 +1030,14 @@ pm_turnoff_sleep: static int imx6_pcie_suspend_noirq(struct device *dev) { struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + struct dw_pcie_rp *pp = &imx6_pcie->pci->pp; if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; imx6_pcie_pm_turnoff(imx6_pcie); - imx6_pcie_ltssm_disable(dev); - imx6_pcie_clk_disable(imx6_pcie); - switch (imx6_pcie->drvdata->variant) { - case IMX8MM: - if (phy_power_off(imx6_pcie->phy)) - dev_err(dev, "unable to power off PHY\n"); - phy_exit(imx6_pcie->phy); - break; - default: - break; - } - - if (imx6_pcie->vpcie) - regulator_disable(imx6_pcie->vpcie); + imx6_pcie_stop_link(imx6_pcie->pci); + imx6_pcie_host_exit(pp); return 0; } -- cgit v1.2.3 From 13f8f3d1e369f56dfaeea10a2238d56bc36c876c Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 18 May 2022 17:35:27 +0800 Subject: PCI: imx6: Set PCIE_DBI_RO_WR_EN before writing DBI registers The PCIE_DBI_RO_WR_EN bit should be set when write some DBI registers. To make sure that the DBI registers are writable, set the PCIE_DBI_RO_WR_EN properly when writing the DBI registers. Link: https://lore.kernel.org/r/1652866528-13220-1-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-imx6.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 81ab6ddb0d59..d11032388d23 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -830,10 +830,12 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) * started in Gen2 mode, there is a possibility the devices on the * bus will not be detected at all. This happens with PCIe switches. */ + dw_pcie_dbi_ro_wr_en(pci); tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); tmp &= ~PCI_EXP_LNKCAP_SLS; tmp |= PCI_EXP_LNKCAP_SLS_2_5GB; dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp); + dw_pcie_dbi_ro_wr_dis(pci); /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); @@ -844,6 +846,7 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) if (pci->link_gen == 2) { /* Allow Gen2 mode after the link is up. */ + dw_pcie_dbi_ro_wr_en(pci); tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); tmp &= ~PCI_EXP_LNKCAP_SLS; tmp |= PCI_EXP_LNKCAP_SLS_5_0GB; @@ -856,6 +859,7 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); tmp |= PORT_LOGIC_SPEED_CHANGE; dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); + dw_pcie_dbi_ro_wr_dis(pci); if (imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE) { -- cgit v1.2.3 From 6213c6c545cb273510047df881230d855e474d3b Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 20 Jul 2022 11:26:16 +0800 Subject: PCI: imx6: Support more than Gen2 speed link mode Support more than Gen2 speed link mode, since i.MX8MP PCIe supports up to Gen3 link speed. Link: https://lore.kernel.org/r/1658287576-26908-1-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-imx6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller/dwc/pci-imx6.c') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index d11032388d23..6e5debdbc55b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -844,12 +844,12 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) if (ret) goto err_reset_phy; - if (pci->link_gen == 2) { - /* Allow Gen2 mode after the link is up. */ + if (pci->link_gen > 1) { + /* Allow faster modes after the link is up */ dw_pcie_dbi_ro_wr_en(pci); tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); tmp &= ~PCI_EXP_LNKCAP_SLS; - tmp |= PCI_EXP_LNKCAP_SLS_5_0GB; + tmp |= pci->link_gen; dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp); /* @@ -884,7 +884,7 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) if (ret) goto err_reset_phy; } else { - dev_info(dev, "Link: Gen2 disabled\n"); + dev_info(dev, "Link: Only Gen1 is enabled\n"); } imx6_pcie->link_is_up = true; -- cgit v1.2.3