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>
This commit is contained in:
		
							parent
							
								
									e24b6b513e
								
							
						
					
					
						commit
						3f7cceeab8
					
				| @ -27,6 +27,8 @@ | ||||
| #include <linux/types.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/reset.h> | ||||
| #include <linux/pm_domain.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| 
 | ||||
| #include "pcie-designware.h" | ||||
| 
 | ||||
| @ -59,6 +61,11 @@ struct imx6_pcie { | ||||
| 	u32			tx_swing_low; | ||||
| 	int			link_gen; | ||||
| 	struct regulator	*vpcie; | ||||
| 
 | ||||
| 	/* power domain for pcie */ | ||||
| 	struct device		*pd_pcie; | ||||
| 	/* power domain for pcie phy */ | ||||
| 	struct device		*pd_pcie_phy; | ||||
| }; | ||||
| 
 | ||||
| /* 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, | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static int imx6_pcie_attach_pd(struct device *dev) | ||||
| { | ||||
| 	struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | ||||
| 	struct device_link *link; | ||||
| 
 | ||||
| 	/* Do nothing when in a single power domain */ | ||||
| 	if (dev->pm_domain) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	imx6_pcie->pd_pcie = dev_pm_domain_attach_by_name(dev, "pcie"); | ||||
| 	if (IS_ERR(imx6_pcie->pd_pcie)) | ||||
| 		return PTR_ERR(imx6_pcie->pd_pcie); | ||||
| 	link = device_link_add(dev, imx6_pcie->pd_pcie, | ||||
| 			DL_FLAG_STATELESS | | ||||
| 			DL_FLAG_PM_RUNTIME | | ||||
| 			DL_FLAG_RPM_ACTIVE); | ||||
| 	if (!link) { | ||||
| 		dev_err(dev, "Failed to add device_link to pcie pd.\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	imx6_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy"); | ||||
| 	if (IS_ERR(imx6_pcie->pd_pcie_phy)) | ||||
| 		return PTR_ERR(imx6_pcie->pd_pcie_phy); | ||||
| 
 | ||||
| 	device_link_add(dev, imx6_pcie->pd_pcie_phy, | ||||
| 			DL_FLAG_STATELESS | | ||||
| 			DL_FLAG_PM_RUNTIME | | ||||
| 			DL_FLAG_RPM_ACTIVE); | ||||
| 	if (IS_ERR(link)) { | ||||
| 		dev_err(dev, "Failed to add device_link to pcie_phy pd: %ld\n", PTR_ERR(link)); | ||||
| 		return PTR_ERR(link); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | ||||
| { | ||||
| 	struct device *dev = imx6_pcie->pci->dev; | ||||
| @ -985,6 +1029,10 @@ static int imx6_pcie_probe(struct platform_device *pdev) | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, imx6_pcie); | ||||
| 
 | ||||
| 	ret = imx6_pcie_attach_pd(dev); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ret = imx6_add_pcie_port(imx6_pcie, pdev); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user