summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/dwc/pci-imx6.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/controller/dwc/pci-imx6.c')
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c206
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;