diff options
author | Leonard Crestez <leonard.crestez@nxp.com> | 2018-10-08 14:06:21 -0400 |
---|---|---|
committer | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2018-12-18 07:01:08 -0500 |
commit | 3f7cceeab895fcc17ac8db0d9a5e8ca2954b4661 (patch) | |
tree | 9db4a171779ee9f9c15633ca221a943d64154293 /drivers/pci/controller/dwc | |
parent | e24b6b513e747727ee56b77ad46f04dff36cee53 (diff) |
PCI: imx: Add multi-pd support
On some chips the PCIe and PCIE_PHY blocks are in separate power domains
which can be power-gated independently. The PCI driver needs to handle
this by keeping both domain active.
This is intended for imx6sx where PCIe is in DISPLAY and PCIE_PHY in
its own domain. Defining the DISPLAY domain requires a way for PCIe to
keep it active or it will break when displays are off.
The power-domains on imx6sx are meant to look like this:
power-domains = <&pd_disp>, <&pd_pci>;
power-domain-names = "pcie", "pcie_phy";
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
[lorenzo.pieralisi@arm.com: updated commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 2cbef2d7c207..4a307cdf20c8 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/reset.h> | 29 | #include <linux/reset.h> |
30 | #include <linux/pm_domain.h> | ||
31 | #include <linux/pm_runtime.h> | ||
30 | 32 | ||
31 | #include "pcie-designware.h" | 33 | #include "pcie-designware.h" |
32 | 34 | ||
@@ -59,6 +61,11 @@ struct imx6_pcie { | |||
59 | u32 tx_swing_low; | 61 | u32 tx_swing_low; |
60 | int link_gen; | 62 | int link_gen; |
61 | struct regulator *vpcie; | 63 | struct regulator *vpcie; |
64 | |||
65 | /* power domain for pcie */ | ||
66 | struct device *pd_pcie; | ||
67 | /* power domain for pcie phy */ | ||
68 | struct device *pd_pcie_phy; | ||
62 | }; | 69 | }; |
63 | 70 | ||
64 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ | 71 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ |
@@ -292,6 +299,43 @@ static int imx6q_pcie_abort_handler(unsigned long addr, | |||
292 | return 1; | 299 | return 1; |
293 | } | 300 | } |
294 | 301 | ||
302 | static int imx6_pcie_attach_pd(struct device *dev) | ||
303 | { | ||
304 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | ||
305 | struct device_link *link; | ||
306 | |||
307 | /* Do nothing when in a single power domain */ | ||
308 | if (dev->pm_domain) | ||
309 | return 0; | ||
310 | |||
311 | imx6_pcie->pd_pcie = dev_pm_domain_attach_by_name(dev, "pcie"); | ||
312 | if (IS_ERR(imx6_pcie->pd_pcie)) | ||
313 | return PTR_ERR(imx6_pcie->pd_pcie); | ||
314 | link = device_link_add(dev, imx6_pcie->pd_pcie, | ||
315 | DL_FLAG_STATELESS | | ||
316 | DL_FLAG_PM_RUNTIME | | ||
317 | DL_FLAG_RPM_ACTIVE); | ||
318 | if (!link) { | ||
319 | dev_err(dev, "Failed to add device_link to pcie pd.\n"); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | imx6_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy"); | ||
324 | if (IS_ERR(imx6_pcie->pd_pcie_phy)) | ||
325 | return PTR_ERR(imx6_pcie->pd_pcie_phy); | ||
326 | |||
327 | device_link_add(dev, imx6_pcie->pd_pcie_phy, | ||
328 | DL_FLAG_STATELESS | | ||
329 | DL_FLAG_PM_RUNTIME | | ||
330 | DL_FLAG_RPM_ACTIVE); | ||
331 | if (IS_ERR(link)) { | ||
332 | dev_err(dev, "Failed to add device_link to pcie_phy pd: %ld\n", PTR_ERR(link)); | ||
333 | return PTR_ERR(link); | ||
334 | } | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
295 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | 339 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) |
296 | { | 340 | { |
297 | struct device *dev = imx6_pcie->pci->dev; | 341 | struct device *dev = imx6_pcie->pci->dev; |
@@ -985,6 +1029,10 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
985 | 1029 | ||
986 | platform_set_drvdata(pdev, imx6_pcie); | 1030 | platform_set_drvdata(pdev, imx6_pcie); |
987 | 1031 | ||
1032 | ret = imx6_pcie_attach_pd(dev); | ||
1033 | if (ret) | ||
1034 | return ret; | ||
1035 | |||
988 | ret = imx6_add_pcie_port(imx6_pcie, pdev); | 1036 | ret = imx6_add_pcie_port(imx6_pcie, pdev); |
989 | if (ret < 0) | 1037 | if (ret < 0) |
990 | return ret; | 1038 | return ret; |