diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pci-imx6.c')
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 206 |
1 files changed, 135 insertions, 71 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index c655d9de144e..f37b805fd730 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -100,9 +100,10 @@ struct imx6_pcie_drvdata { struct imx6_pcie { struct dw_pcie *pci; - int clkreq_gpio; - int dis_gpio; - int reset_gpio; + struct gpio_desc *clkreq_gpiod; + struct gpio_desc *dis_gpiod; + struct gpio_desc *power_on_gpiod; + struct gpio_desc *reset_gpiod; bool gpio_active_high; struct clk *pcie_bus; struct clk *pcie_phy; @@ -111,6 +112,7 @@ struct imx6_pcie { struct clk *pciex2_per; struct clk *pcie_inbound_axi; struct clk *pcie; + struct clk *pcie_ext; struct clk *pcie_aux; struct clk *phy_per; struct clk *misc_per; @@ -878,7 +880,7 @@ static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) PHY_PLL_LOCK_WAIT_TIMEOUT)) dev_err(dev, "PCIe PLL lock timeout\n"); } -static void imx8_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) +static int imx8_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) { u32 val, retries = 0, tmp = 0, orig = 0; struct dw_pcie *pci = imx6_pcie->pci; @@ -946,10 +948,13 @@ static void imx8_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) break; } - if (retries >= PHY_PLL_LOCK_WAIT_MAX_RETRIES) + if (retries >= PHY_PLL_LOCK_WAIT_MAX_RETRIES) { dev_err(dev, "PCIe PLL lock timeout\n"); - else - dev_info(dev, "PCIe PLL locked after %d us.\n", retries * 10); + return -ENODEV; + } + + dev_info(dev, "PCIe PLL locked after %d us.\n", retries * 10); + return 0; } static void imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie) @@ -1133,6 +1138,9 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) break; } + if (imx6_pcie->dis_gpiod) + gpiod_set_value_cansleep(imx6_pcie->dis_gpiod, 1); + if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) { int ret = regulator_disable(imx6_pcie->vpcie); @@ -1142,7 +1150,7 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) } } -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; @@ -1154,10 +1162,26 @@ 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; } } + if (imx6_pcie->power_on_gpiod) + gpiod_set_value_cansleep(imx6_pcie->power_on_gpiod, 1); + + if (imx6_pcie->clkreq_gpiod) + gpiod_set_value_cansleep(imx6_pcie->clkreq_gpiod, 1); + + mdelay(2); + if (imx6_pcie->dis_gpiod) + gpiod_set_value_cansleep(imx6_pcie->dis_gpiod, 0); + + ret = clk_prepare_enable(imx6_pcie->pcie_ext); + if (ret) { + dev_err(dev, "unable to enable pcie_ext clock\n"); + return ret; + } + switch (imx6_pcie->drvdata->variant) { case IMX8QXP: case IMX8QM: @@ -1170,12 +1194,13 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) } /* 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); - msleep(100); - gpio_set_value_cansleep(imx6_pcie->reset_gpio, + if (imx6_pcie->reset_gpiod) { + gpiod_set_value_cansleep(imx6_pcie->reset_gpiod, !imx6_pcie->gpio_active_high); + msleep(100); + gpiod_set_value_cansleep(imx6_pcie->reset_gpiod, + imx6_pcie->gpio_active_high); + msleep(20); } switch (imx6_pcie->drvdata->variant) { @@ -1206,13 +1231,15 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) dev_err(dev, "ERROR PM_REQ_CORE_RST is still set.\n"); /* wait for phy pll lock firstly. */ - imx8_pcie_wait_for_phy_pll_lock(imx6_pcie); + if(imx8_pcie_wait_for_phy_pll_lock(imx6_pcie) != 0) + goto err_pll; break; case IMX8MQ: case IMX8MM: reset_control_deassert(imx6_pcie->pciephy_reset); - imx8_pcie_wait_for_phy_pll_lock(imx6_pcie); + if(imx8_pcie_wait_for_phy_pll_lock(imx6_pcie) != 0) + goto err_pll; /* * Set the over ride low and enabled * make sure that REF_CLK is turned on. @@ -1289,7 +1316,8 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) reset_control_deassert(imx6_pcie->pciephy_reset); udelay(10); - imx8_pcie_wait_for_phy_pll_lock(imx6_pcie); + if(imx8_pcie_wait_for_phy_pll_lock(imx6_pcie) != 0) + goto err_pll; break; case IMX7D: reset_control_deassert(imx6_pcie->pciephy_reset); @@ -1329,7 +1357,25 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) break; } - return; + return 0; + +err_pll: + if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie)) + ret = regulator_disable(imx6_pcie->vpcie); + + clk_disable_unprepare(imx6_pcie->pcie_ext); + + switch (imx6_pcie->drvdata->variant) { + case IMX8QXP: + case IMX8QM: + case IMX8MP: + break; + default: + imx6_pcie_clk_disable(imx6_pcie); + break; + } + + return -ENODEV; } static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie) @@ -1837,8 +1883,6 @@ err_reset_phy: imx6_pcie_clk_disable(imx6_pcie); if (imx6_pcie->vpcie != NULL) regulator_disable(imx6_pcie->vpcie); - if (imx6_pcie->epdev_on != NULL) - regulator_disable(imx6_pcie->epdev_on); } return ret; @@ -1865,12 +1909,16 @@ static int imx6_pcie_host_init(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); - if (gpio_is_valid(imx6_pcie->dis_gpio)) - gpio_set_value_cansleep(imx6_pcie->dis_gpio, 1); + if (imx6_pcie->power_on_gpiod) + gpiod_set_value_cansleep(imx6_pcie->power_on_gpiod, 1); imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); - imx6_pcie_deassert_core_reset(imx6_pcie); + if(imx6_pcie_deassert_core_reset(imx6_pcie) == -ENODEV) { + if (imx6_pcie->power_on_gpiod) + gpiod_set_value_cansleep(imx6_pcie->power_on_gpiod, 0); + return -ENODEV; + } imx6_setup_phy_mpll(imx6_pcie); if (!(IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS) && (imx6_pcie->hard_wired == 0))) { @@ -2351,7 +2399,8 @@ static int imx6_pcie_resume_noirq(struct device *dev) } else { imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); - imx6_pcie_deassert_core_reset(imx6_pcie); + if(imx6_pcie_deassert_core_reset(imx6_pcie) == -ENODEV) + return -ENODEV; dw_pcie_setup_rc(pp); pci_imx_set_msi_en(pp); @@ -2413,28 +2462,31 @@ static int imx6_pcie_probe(struct platform_device *pdev) } } - imx6_pcie->phy = devm_phy_get(dev, "pcie-phy"); - if (IS_ERR(imx6_pcie->phy)) { - if (PTR_ERR(imx6_pcie->phy) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_info(dev, "couldn't get pcie-phy\n"); - imx6_pcie->phy = NULL; - } + /* pcie-phy uses in iMX8MP variant only */ + if (imx6_pcie->drvdata->variant == IMX8MP) { + imx6_pcie->phy = devm_phy_get(dev, "pcie-phy"); + if (IS_ERR(imx6_pcie->phy)) { + if (PTR_ERR(imx6_pcie->phy) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_info(dev, "couldn't get pcie-phy\n"); + imx6_pcie->phy = NULL; + } - /* Find the HSIO MIX if one is defined, only imx8mp uses it */ - np = of_parse_phandle(node, "fsl,imx8mp-hsio-mix", 0); - if (np) { - struct resource res; + /* Find the HSIO MIX if one is defined, only imx8mp uses it */ + np = of_parse_phandle(node, "fsl,imx8mp-hsio-mix", 0); + if (np) { + struct resource res; - ret = of_address_to_resource(np, 0, &res); - if (ret) { - dev_err(dev, "Unable to find HSIO MIX res\n"); - return ret; - } - imx6_pcie->hsmix_base = devm_ioremap_resource(dev, &res); - if (IS_ERR(imx6_pcie->hsmix_base)) { - dev_err(dev, "Unable to map HSIO MIX res\n"); - return PTR_ERR(imx6_pcie->hsmix_base); + ret = of_address_to_resource(np, 0, &res); + if (ret) { + dev_err(dev, "Unable to find HSIO MIX res\n"); + return ret; + } + imx6_pcie->hsmix_base = devm_ioremap_resource(dev, &res); + if (IS_ERR(imx6_pcie->hsmix_base)) { + dev_err(dev, "Unable to map HSIO MIX res\n"); + return PTR_ERR(imx6_pcie->hsmix_base); + } } } @@ -2467,46 +2519,49 @@ static int imx6_pcie_probe(struct platform_device *pdev) } /* Fetch GPIOs */ - imx6_pcie->clkreq_gpio = of_get_named_gpio(node, "clkreq-gpio", 0); - if (gpio_is_valid(imx6_pcie->clkreq_gpio)) { - devm_gpio_request_one(&pdev->dev, imx6_pcie->clkreq_gpio, - GPIOF_OUT_INIT_LOW, "PCIe CLKREQ"); - } else if (imx6_pcie->clkreq_gpio == -EPROBE_DEFER) { - return imx6_pcie->clkreq_gpio; + imx6_pcie->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq", + GPIOD_OUT_LOW); + if (IS_ERR(imx6_pcie->clkreq_gpiod)) { + ret = PTR_ERR(imx6_pcie->clkreq_gpiod); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "unable to get clkreq gpio\n"); + return ret; } - imx6_pcie->dis_gpio = of_get_named_gpio(node, "disable-gpio", 0); - if (gpio_is_valid(imx6_pcie->dis_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->dis_gpio, - GPIOF_OUT_INIT_LOW, "PCIe DIS"); - if (ret) { + imx6_pcie->dis_gpiod = devm_gpiod_get_optional(dev, "disable", + GPIOD_OUT_LOW); + if (IS_ERR(imx6_pcie->dis_gpiod)) { + ret = PTR_ERR(imx6_pcie->dis_gpiod); + if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "unable to get disable gpio\n"); + return ret; + } + + imx6_pcie->power_on_gpiod = devm_gpiod_get_optional(dev, "power-on", + GPIOD_OUT_LOW); + if (IS_ERR(imx6_pcie->power_on_gpiod)) { + ret = PTR_ERR(imx6_pcie->power_on_gpiod); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "unable to get power-on gpio\n"); return ret; } - } else if (imx6_pcie->dis_gpio == -EPROBE_DEFER) { - return imx6_pcie->dis_gpio; - } imx6_pcie->epdev_on = devm_regulator_get(&pdev->dev, "epdev_on"); if (IS_ERR(imx6_pcie->epdev_on)) return -EPROBE_DEFER; - imx6_pcie->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0); imx6_pcie->gpio_active_high = of_property_read_bool(node, "reset-gpio-active-high"); - if (gpio_is_valid(imx6_pcie->reset_gpio)) { - ret = devm_gpio_request_one(dev, imx6_pcie->reset_gpio, - imx6_pcie->gpio_active_high ? - GPIOF_OUT_INIT_HIGH : - GPIOF_OUT_INIT_LOW, - "PCIe reset"); - if (ret) { + imx6_pcie->reset_gpiod = devm_gpiod_get_optional(dev, "reset", + imx6_pcie->gpio_active_high ? + GPIOD_OUT_LOW : + GPIOD_OUT_HIGH); + if (IS_ERR(imx6_pcie->reset_gpiod)) { + ret = PTR_ERR(imx6_pcie->reset_gpiod); + if (ret != -EPROBE_DEFER) dev_err(dev, "unable to get reset gpio\n"); - return ret; - } - } else if (imx6_pcie->reset_gpio == -EPROBE_DEFER) { - return imx6_pcie->reset_gpio; + return ret; } /* Fetch clocks */ @@ -2528,6 +2583,13 @@ static int imx6_pcie_probe(struct platform_device *pdev) return PTR_ERR(imx6_pcie->pcie); } + imx6_pcie->pcie_ext = devm_clk_get_optional(&pdev->dev, "pcie_ext"); + if (IS_ERR(imx6_pcie->pcie_ext)) { + dev_err(&pdev->dev, + "pcie_ext clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie_ext); + } + switch (imx6_pcie->drvdata->variant) { case IMX6SX: imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, @@ -2941,7 +3003,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) } else { dev_err(dev, "unable to add pcie port.\n"); } - goto err_ret; + goto err_reg; } pci_imx_set_msi_en(&imx6_pcie->pci->pp); @@ -2987,6 +3049,8 @@ static int imx6_pcie_probe(struct platform_device *pdev) return 0; +err_reg: + regulator_disable(imx6_pcie->epdev_on); err_ret: imx6_pcie_detach_pd(dev); return ret; |