diff options
author | Richard Zhu <Richard.Zhu@freescale.com> | 2015-04-10 14:50:50 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2015-05-08 17:25:03 +0800 |
commit | 43ee8a8429aaa4da2335101c4c12e3bacdf3f00b (patch) | |
tree | 2b21b9855fde9ce895c01699f487eeda2665b0a1 | |
parent | 1d36ac2afe42441825129f6494d0a691ad8ce2bd (diff) |
MLK-10610-3 pci: imx: refine pcie pm operations
- add the perst for imx pcie because that this signal
is mandatory required to be asserted/de-asserted
during suspend/resume.
Otherwise, pcie ep maybe failed to resume back.
- for imx7 pcie
- use the external osc, otherwise the internal pll
- adjust the ltssm de-assert
- change the init of pcie to late_initcall, because
the expansion spi gpio is used as pcie_rst_b and
pcie_dis_b on imx7d/imx6qp boards, and pcie driver has
to be loaded after spi/i2c driver is probed.
- cansleep set value function should be used to
manipulate the expansion gpios.
Signed-off-by: Richard Zhu <Richard.Zhu@freescale.com>
-rw-r--r-- | drivers/pci/host/pci-imx6.c | 242 |
1 files changed, 130 insertions, 112 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 54097abfa3dd..62d20f85fe8e 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -317,10 +317,25 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp) return 0; } -static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) +static void pci_imx_phy_pll_locked(struct imx6_pcie *imx6_pcie) { - int ret, count; + u32 val; + int count = 20000; + + while (count--) { + regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &val); + if (val & BIT(31)) + break; + udelay(10); + if (count == 0) + pr_info("pcie phy pll can't be locked.\n"); + } +} + +static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) +{ + int ret; struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); if (gpio_is_valid(imx6_pcie->power_on_gpio)) @@ -416,15 +431,7 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(2), 0); /* wait for phy pll lock firstly. */ - count = 20000; - while (count--) { - regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &val); - if (val & BIT(31)) - break; - udelay(100); - if (count == 0) - pr_info("pcie phy pll can't be locked.\n"); - } + pci_imx_phy_pll_locked(imx6_pcie); } else if (is_imx6sx_pcie(imx6_pcie)) { regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, IMX6SX_GPR5_PCIE_BTNRST, 0); @@ -476,7 +483,7 @@ static int imx6_pcie_init_phy(struct pcie_port *pp) /* pcie phy ref clock select; 1? internal pll : external osc */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - BIT(5), BIT(5)); + BIT(5), 0); } else if (is_imx6sx_pcie(imx6_pcie)) { /* Force PCIe PHY reset */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, @@ -570,16 +577,6 @@ static int imx6_pcie_start_link(struct pcie_port *pp) /* Start LTSSM. */ if (is_imx7d_pcie(imx6_pcie)) { - /* wait for phy pll lock firstly. */ - count = 20000; - while (count--) { - regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &tmp); - if (tmp & BIT(31)) - break; - udelay(10); - if (count == 0) - pr_info("pcie phy pll can't be locked.\n"); - } regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(6), BIT(6)); } else { regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, @@ -988,6 +985,38 @@ static void imx6_pcie_setup_ep(struct pcie_port *pp) } #ifdef CONFIG_PM_SLEEP +/* PM_TURN_OFF */ +static void pci_imx_pm_turn_off(struct imx6_pcie *imx6_pcie) +{ + /* PM_TURN_OFF */ + if (is_imx6sx_pcie(imx6_pcie)) { + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6SX_GPR12_PCIE_PM_TURN_OFF, + IMX6SX_GPR12_PCIE_PM_TURN_OFF); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0); + } else if (is_imx6qp_pcie(imx6_pcie)) { + /* PM_TURN_OFF */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_PM_TURN_OFF, + IMX6Q_GPR12_PCIE_PM_TURN_OFF); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_PM_TURN_OFF, 0); + } else if (is_imx7d_pcie(imx6_pcie)) { + regmap_update_bits(imx6_pcie->reg_src, 0x2c, + BIT(11), BIT(11)); + regmap_update_bits(imx6_pcie->reg_src, 0x2c, + BIT(11), 0); + } else { + pr_info("Info: don't support pm_turn_off yet.\n"); + return; + } + + udelay(1000); + if (gpio_is_valid(imx6_pcie->reset_gpio)) + gpio_set_value_cansleep(imx6_pcie->reset_gpio, 0); +} + static int pci_imx_suspend_noirq(struct device *dev) { struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); @@ -996,47 +1025,28 @@ static int pci_imx_suspend_noirq(struct device *dev) if (IS_ENABLED(CONFIG_PCI_MSI)) dw_pcie_msi_cfg_store(pp); - if (is_imx6sx_pcie(imx6_pcie) || is_imx7d_pcie(imx6_pcie)) { - /* PM_TURN_OFF */ - if (is_imx6sx_pcie(imx6_pcie)) { - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6SX_GPR12_PCIE_PM_TURN_OFF, - IMX6SX_GPR12_PCIE_PM_TURN_OFF); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0); - } else { - regmap_update_bits(imx6_pcie->reg_src, 0x2c, - BIT(11), BIT(11)); - udelay(10); - regmap_update_bits(imx6_pcie->reg_src, 0x2c, - BIT(11), 0); - } + pci_imx_pm_turn_off(imx6_pcie); + if (is_imx6sx_pcie(imx6_pcie) || is_imx7d_pcie(imx6_pcie)) { /* Disable clks */ clk_disable_unprepare(imx6_pcie->pcie); clk_disable_unprepare(imx6_pcie->pcie_phy); if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS) && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS)) clk_disable_unprepare(imx6_pcie->pcie_bus); - if (is_imx6sx_pcie(imx6_pcie)) + if (is_imx6sx_pcie(imx6_pcie)) { clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); + } else { + /* turn off external osc input */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + BIT(5), BIT(5)); + } release_bus_freq(BUS_FREQ_HIGH); /* Power down PCIe PHY. */ if (IS_ENABLED(CONFIG_PCI_IMX6SX_EXTREMELY_PWR_SAVE)) regulator_disable(imx6_pcie->pcie_phy_regulator); } else if (is_imx6qp_pcie(imx6_pcie)) { - /* PM_TURN_OFF */ - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_PM_TURN_OFF, - IMX6Q_GPR12_PCIE_PM_TURN_OFF); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_PM_TURN_OFF, 0); - - udelay(1000); - if (gpio_is_valid(imx6_pcie->reset_gpio)) - gpio_set_value_cansleep(imx6_pcie->reset_gpio, 0); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 0); clk_disable_unprepare(imx6_pcie->pcie_bus); @@ -1065,81 +1075,89 @@ static int pci_imx_resume_noirq(struct device *dev) struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); struct pcie_port *pp = &imx6_pcie->pp; - if (is_imx6sx_pcie(imx6_pcie) || is_imx7d_pcie(imx6_pcie)) { - if (IS_ENABLED(CONFIG_PCI_IMX6SX_EXTREMELY_PWR_SAVE)) { - imx6_pcie_assert_core_reset(pp); + if (IS_ENABLED(CONFIG_PCI_IMX6SX_EXTREMELY_PWR_SAVE)) { + imx6_pcie_assert_core_reset(pp); - ret = imx6_pcie_init_phy(pp); - if (ret < 0) - return ret; + ret = imx6_pcie_init_phy(pp); + if (ret < 0) + return ret; - ret = imx6_pcie_deassert_core_reset(pp); - if (ret < 0) - return ret; + ret = imx6_pcie_deassert_core_reset(pp); + if (ret < 0) + return ret; - if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) - imx6_pcie_setup_ep(pp); - else - dw_pcie_setup_rc(pp); + if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) + imx6_pcie_setup_ep(pp); + else + dw_pcie_setup_rc(pp); - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_cfg_restore(pp); + if (IS_ENABLED(CONFIG_PCI_MSI)) + dw_pcie_msi_cfg_restore(pp); - /* Start LTSSM. */ + /* Start LTSSM. */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, + IMX6Q_GPR12_PCIE_CTL_2); + } else if (is_imx6sx_pcie(imx6_pcie) || is_imx7d_pcie(imx6_pcie)) { + if (is_imx7d_pcie(imx6_pcie)) { + regmap_update_bits(imx6_pcie->reg_src, + 0x2c, BIT(1), BIT(1)); + regmap_update_bits(imx6_pcie->reg_src, + 0x2c, BIT(2), BIT(2)); + /* set external osc in */ regmap_update_bits(imx6_pcie->iomuxc_gpr, - IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, - IMX6Q_GPR12_PCIE_CTL_2); + IOMUXC_GPR12, BIT(5), 0); } else { - if (is_imx7d_pcie(imx6_pcie)) { - regmap_update_bits(imx6_pcie->reg_src, - 0x2c, BIT(6), 0); - regmap_update_bits(imx6_pcie->reg_src, - 0x2c, BIT(1), BIT(1)); - regmap_update_bits(imx6_pcie->reg_src, - 0x2c, BIT(2), BIT(2)); - } + regmap_update_bits(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR5, + IMX6SX_GPR5_PCIE_BTNRST, + IMX6SX_GPR5_PCIE_BTNRST); + } - request_bus_freq(BUS_FREQ_HIGH); - if (is_imx6sx_pcie(imx6_pcie)) - clk_prepare_enable(imx6_pcie->pcie_inbound_axi); - if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS) - && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS)) - clk_prepare_enable(imx6_pcie->pcie_bus); - clk_prepare_enable(imx6_pcie->pcie_phy); - clk_prepare_enable(imx6_pcie->pcie); - - if (is_imx7d_pcie(imx6_pcie)) { - regmap_update_bits(imx6_pcie->reg_src, - 0x2c, BIT(1), 0); - regmap_update_bits(imx6_pcie->reg_src, - 0x2c, BIT(2), 0); - } + request_bus_freq(BUS_FREQ_HIGH); + if (is_imx6sx_pcie(imx6_pcie)) + clk_prepare_enable(imx6_pcie->pcie_inbound_axi); + if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS) + && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS)) + clk_prepare_enable(imx6_pcie->pcie_bus); + clk_prepare_enable(imx6_pcie->pcie_phy); + clk_prepare_enable(imx6_pcie->pcie); - /* Reset iMX6SX PCIe */ - if (is_imx6sx_pcie(imx6_pcie)) { - regmap_update_bits(imx6_pcie->iomuxc_gpr, - IOMUXC_GPR5, - IMX6SX_GPR5_PCIE_PERST, - IMX6SX_GPR5_PCIE_PERST); - regmap_update_bits(imx6_pcie->iomuxc_gpr, - IOMUXC_GPR5, - IMX6SX_GPR5_PCIE_PERST, 0); - } + if (gpio_is_valid(imx6_pcie->reset_gpio)) + gpio_set_value_cansleep(imx6_pcie->reset_gpio, 1); + mdelay(20); - /* - * controller maybe turn off, re-configure again - */ - dw_pcie_setup_rc(pp); + if (is_imx7d_pcie(imx6_pcie)) { + regmap_update_bits(imx6_pcie->reg_src, + 0x2c, BIT(6), 0); + regmap_update_bits(imx6_pcie->reg_src, + 0x2c, BIT(1), 0); + regmap_update_bits(imx6_pcie->reg_src, + 0x2c, BIT(2), 0); + } else { + regmap_update_bits(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR5, + IMX6SX_GPR5_PCIE_BTNRST, 0); + } - if (IS_ENABLED(CONFIG_PCI_MSI)) - dw_pcie_msi_cfg_restore(pp); + /* + * controller maybe turn off, re-configure again + */ + dw_pcie_setup_rc(pp); - if (is_imx7d_pcie(imx6_pcie)) { - regmap_update_bits(imx6_pcie->reg_src, 0x2c, - BIT(6), BIT(6)); - } + if (IS_ENABLED(CONFIG_PCI_MSI)) + dw_pcie_msi_cfg_restore(pp); + + if (is_imx7d_pcie(imx6_pcie)) { + /* wait for phy pll lock firstly. */ + pci_imx_phy_pll_locked(imx6_pcie); + regmap_update_bits(imx6_pcie->reg_src, 0x2c, + BIT(6), BIT(6)); } + ret = imx6_pcie_wait_for_link(pp); + if (ret < 0) + pr_info("pcie link is down after resume.\n"); } else if (is_imx6qp_pcie(imx6_pcie)) { regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6Q_GPR12_PCIE_CTL_2, 0); @@ -1518,7 +1536,7 @@ static int __init imx6_pcie_init(void) { return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe); } -module_init(imx6_pcie_init); +late_initcall(imx6_pcie_init); MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver"); |