diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pci-imx6.c')
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 102 |
1 files changed, 97 insertions, 5 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 88af6bff945f..52e47dac028f 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 */ |
@@ -67,6 +74,7 @@ struct imx6_pcie { | |||
67 | #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 | 74 | #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 |
68 | 75 | ||
69 | /* PCIe Root Complex registers (memory-mapped) */ | 76 | /* PCIe Root Complex registers (memory-mapped) */ |
77 | #define PCIE_RC_IMX6_MSI_CAP 0x50 | ||
70 | #define PCIE_RC_LCR 0x7c | 78 | #define PCIE_RC_LCR 0x7c |
71 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 | 79 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 |
72 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 | 80 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 |
@@ -290,6 +298,43 @@ static int imx6q_pcie_abort_handler(unsigned long addr, | |||
290 | return 1; | 298 | return 1; |
291 | } | 299 | } |
292 | 300 | ||
301 | static int imx6_pcie_attach_pd(struct device *dev) | ||
302 | { | ||
303 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | ||
304 | struct device_link *link; | ||
305 | |||
306 | /* Do nothing when in a single power domain */ | ||
307 | if (dev->pm_domain) | ||
308 | return 0; | ||
309 | |||
310 | imx6_pcie->pd_pcie = dev_pm_domain_attach_by_name(dev, "pcie"); | ||
311 | if (IS_ERR(imx6_pcie->pd_pcie)) | ||
312 | return PTR_ERR(imx6_pcie->pd_pcie); | ||
313 | link = device_link_add(dev, imx6_pcie->pd_pcie, | ||
314 | DL_FLAG_STATELESS | | ||
315 | DL_FLAG_PM_RUNTIME | | ||
316 | DL_FLAG_RPM_ACTIVE); | ||
317 | if (!link) { | ||
318 | dev_err(dev, "Failed to add device_link to pcie pd.\n"); | ||
319 | return -EINVAL; | ||
320 | } | ||
321 | |||
322 | imx6_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy"); | ||
323 | if (IS_ERR(imx6_pcie->pd_pcie_phy)) | ||
324 | return PTR_ERR(imx6_pcie->pd_pcie_phy); | ||
325 | |||
326 | device_link_add(dev, imx6_pcie->pd_pcie_phy, | ||
327 | DL_FLAG_STATELESS | | ||
328 | DL_FLAG_PM_RUNTIME | | ||
329 | DL_FLAG_RPM_ACTIVE); | ||
330 | if (IS_ERR(link)) { | ||
331 | dev_err(dev, "Failed to add device_link to pcie_phy pd: %ld\n", PTR_ERR(link)); | ||
332 | return PTR_ERR(link); | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
293 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | 338 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) |
294 | { | 339 | { |
295 | struct device *dev = imx6_pcie->pci->dev; | 340 | struct device *dev = imx6_pcie->pci->dev; |
@@ -765,8 +810,28 @@ static void imx6_pcie_ltssm_disable(struct device *dev) | |||
765 | 810 | ||
766 | static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) | 811 | static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) |
767 | { | 812 | { |
768 | reset_control_assert(imx6_pcie->turnoff_reset); | 813 | struct device *dev = imx6_pcie->pci->dev; |
769 | reset_control_deassert(imx6_pcie->turnoff_reset); | 814 | |
815 | /* Some variants have a turnoff reset in DT */ | ||
816 | if (imx6_pcie->turnoff_reset) { | ||
817 | reset_control_assert(imx6_pcie->turnoff_reset); | ||
818 | reset_control_deassert(imx6_pcie->turnoff_reset); | ||
819 | goto pm_turnoff_sleep; | ||
820 | } | ||
821 | |||
822 | /* Others poke directly at IOMUXC registers */ | ||
823 | switch (imx6_pcie->variant) { | ||
824 | case IMX6SX: | ||
825 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
826 | IMX6SX_GPR12_PCIE_PM_TURN_OFF, | ||
827 | IMX6SX_GPR12_PCIE_PM_TURN_OFF); | ||
828 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
829 | IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0); | ||
830 | break; | ||
831 | default: | ||
832 | dev_err(dev, "PME_Turn_Off not implemented\n"); | ||
833 | return; | ||
834 | } | ||
770 | 835 | ||
771 | /* | 836 | /* |
772 | * Components with an upstream port must respond to | 837 | * Components with an upstream port must respond to |
@@ -775,6 +840,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) | |||
775 | * The standard recommends a 1-10ms timeout after which to | 840 | * The standard recommends a 1-10ms timeout after which to |
776 | * proceed anyway as if acks were received. | 841 | * proceed anyway as if acks were received. |
777 | */ | 842 | */ |
843 | pm_turnoff_sleep: | ||
778 | usleep_range(1000, 10000); | 844 | usleep_range(1000, 10000); |
779 | } | 845 | } |
780 | 846 | ||
@@ -784,18 +850,31 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) | |||
784 | clk_disable_unprepare(imx6_pcie->pcie_phy); | 850 | clk_disable_unprepare(imx6_pcie->pcie_phy); |
785 | clk_disable_unprepare(imx6_pcie->pcie_bus); | 851 | clk_disable_unprepare(imx6_pcie->pcie_bus); |
786 | 852 | ||
787 | if (imx6_pcie->variant == IMX7D) { | 853 | switch (imx6_pcie->variant) { |
854 | case IMX6SX: | ||
855 | clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); | ||
856 | break; | ||
857 | case IMX7D: | ||
788 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 858 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, |
789 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, | 859 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, |
790 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); | 860 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); |
861 | break; | ||
862 | default: | ||
863 | break; | ||
791 | } | 864 | } |
792 | } | 865 | } |
793 | 866 | ||
867 | static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie) | ||
868 | { | ||
869 | return (imx6_pcie->variant == IMX7D || | ||
870 | imx6_pcie->variant == IMX6SX); | ||
871 | } | ||
872 | |||
794 | static int imx6_pcie_suspend_noirq(struct device *dev) | 873 | static int imx6_pcie_suspend_noirq(struct device *dev) |
795 | { | 874 | { |
796 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | 875 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); |
797 | 876 | ||
798 | if (imx6_pcie->variant != IMX7D) | 877 | if (!imx6_pcie_supports_suspend(imx6_pcie)) |
799 | return 0; | 878 | return 0; |
800 | 879 | ||
801 | imx6_pcie_pm_turnoff(imx6_pcie); | 880 | imx6_pcie_pm_turnoff(imx6_pcie); |
@@ -811,7 +890,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) | |||
811 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); | 890 | struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); |
812 | struct pcie_port *pp = &imx6_pcie->pci->pp; | 891 | struct pcie_port *pp = &imx6_pcie->pci->pp; |
813 | 892 | ||
814 | if (imx6_pcie->variant != IMX7D) | 893 | if (!imx6_pcie_supports_suspend(imx6_pcie)) |
815 | return 0; | 894 | return 0; |
816 | 895 | ||
817 | imx6_pcie_assert_core_reset(imx6_pcie); | 896 | imx6_pcie_assert_core_reset(imx6_pcie); |
@@ -840,6 +919,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
840 | struct resource *dbi_base; | 919 | struct resource *dbi_base; |
841 | struct device_node *node = dev->of_node; | 920 | struct device_node *node = dev->of_node; |
842 | int ret; | 921 | int ret; |
922 | u16 val; | ||
843 | 923 | ||
844 | imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL); | 924 | imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL); |
845 | if (!imx6_pcie) | 925 | if (!imx6_pcie) |
@@ -977,10 +1057,22 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
977 | 1057 | ||
978 | platform_set_drvdata(pdev, imx6_pcie); | 1058 | platform_set_drvdata(pdev, imx6_pcie); |
979 | 1059 | ||
1060 | ret = imx6_pcie_attach_pd(dev); | ||
1061 | if (ret) | ||
1062 | return ret; | ||
1063 | |||
980 | ret = imx6_add_pcie_port(imx6_pcie, pdev); | 1064 | ret = imx6_add_pcie_port(imx6_pcie, pdev); |
981 | if (ret < 0) | 1065 | if (ret < 0) |
982 | return ret; | 1066 | return ret; |
983 | 1067 | ||
1068 | if (pci_msi_enabled()) { | ||
1069 | val = dw_pcie_readw_dbi(pci, PCIE_RC_IMX6_MSI_CAP + | ||
1070 | PCI_MSI_FLAGS); | ||
1071 | val |= PCI_MSI_FLAGS_ENABLE; | ||
1072 | dw_pcie_writew_dbi(pci, PCIE_RC_IMX6_MSI_CAP + PCI_MSI_FLAGS, | ||
1073 | val); | ||
1074 | } | ||
1075 | |||
984 | return 0; | 1076 | return 0; |
985 | } | 1077 | } |
986 | 1078 | ||