diff options
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index c1d434ba3642..64c74334f7d0 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/of_gpio.h> | 20 | #include <linux/of_gpio.h> |
21 | #include <linux/of_device.h> | 21 | #include <linux/of_device.h> |
22 | #include <linux/of_address.h> | ||
22 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
23 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
24 | #include <linux/regmap.h> | 25 | #include <linux/regmap.h> |
@@ -77,6 +78,7 @@ struct imx6_pcie { | |||
77 | u32 tx_swing_low; | 78 | u32 tx_swing_low; |
78 | int link_gen; | 79 | int link_gen; |
79 | struct regulator *vpcie; | 80 | struct regulator *vpcie; |
81 | void __iomem *phy_base; | ||
80 | 82 | ||
81 | /* power domain for pcie */ | 83 | /* power domain for pcie */ |
82 | struct device *pd_pcie; | 84 | struct device *pd_pcie; |
@@ -134,6 +136,23 @@ struct imx6_pcie { | |||
134 | #define PCIE_PHY_RX_ASIC_OUT 0x100D | 136 | #define PCIE_PHY_RX_ASIC_OUT 0x100D |
135 | #define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0) | 137 | #define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0) |
136 | 138 | ||
139 | /* iMX7 PCIe PHY registers */ | ||
140 | #define PCIE_PHY_CMN_REG4 0x14 | ||
141 | /* These are probably the bits that *aren't* DCC_FB_EN */ | ||
142 | #define PCIE_PHY_CMN_REG4_DCC_FB_EN 0x29 | ||
143 | |||
144 | #define PCIE_PHY_CMN_REG15 0x54 | ||
145 | #define PCIE_PHY_CMN_REG15_DLY_4 BIT(2) | ||
146 | #define PCIE_PHY_CMN_REG15_PLL_PD BIT(5) | ||
147 | #define PCIE_PHY_CMN_REG15_OVRD_PLL_PD BIT(7) | ||
148 | |||
149 | #define PCIE_PHY_CMN_REG24 0x90 | ||
150 | #define PCIE_PHY_CMN_REG24_RX_EQ BIT(6) | ||
151 | #define PCIE_PHY_CMN_REG24_RX_EQ_SEL BIT(3) | ||
152 | |||
153 | #define PCIE_PHY_CMN_REG26 0x98 | ||
154 | #define PCIE_PHY_CMN_REG26_ATT_MODE 0xBC | ||
155 | |||
137 | #define PHY_RX_OVRD_IN_LO 0x1005 | 156 | #define PHY_RX_OVRD_IN_LO 0x1005 |
138 | #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) | 157 | #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) |
139 | #define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) | 158 | #define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) |
@@ -533,6 +552,26 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) | |||
533 | break; | 552 | break; |
534 | case IMX7D: | 553 | case IMX7D: |
535 | reset_control_deassert(imx6_pcie->pciephy_reset); | 554 | reset_control_deassert(imx6_pcie->pciephy_reset); |
555 | |||
556 | /* Workaround for ERR010728, failure of PCI-e PLL VCO to | ||
557 | * oscillate, especially when cold. This turns off "Duty-cycle | ||
558 | * Corrector" and other mysterious undocumented things. | ||
559 | */ | ||
560 | if (likely(imx6_pcie->phy_base)) { | ||
561 | /* De-assert DCC_FB_EN */ | ||
562 | writel(PCIE_PHY_CMN_REG4_DCC_FB_EN, | ||
563 | imx6_pcie->phy_base + PCIE_PHY_CMN_REG4); | ||
564 | /* Assert RX_EQS and RX_EQS_SEL */ | ||
565 | writel(PCIE_PHY_CMN_REG24_RX_EQ_SEL | ||
566 | | PCIE_PHY_CMN_REG24_RX_EQ, | ||
567 | imx6_pcie->phy_base + PCIE_PHY_CMN_REG24); | ||
568 | /* Assert ATT_MODE */ | ||
569 | writel(PCIE_PHY_CMN_REG26_ATT_MODE, | ||
570 | imx6_pcie->phy_base + PCIE_PHY_CMN_REG26); | ||
571 | } else { | ||
572 | dev_warn(dev, "Unable to apply ERR010728 workaround. DT missing fsl,imx7d-pcie-phy phandle ?\n"); | ||
573 | } | ||
574 | |||
536 | imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie); | 575 | imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie); |
537 | break; | 576 | break; |
538 | case IMX6SX: | 577 | case IMX6SX: |
@@ -994,6 +1033,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
994 | struct device *dev = &pdev->dev; | 1033 | struct device *dev = &pdev->dev; |
995 | struct dw_pcie *pci; | 1034 | struct dw_pcie *pci; |
996 | struct imx6_pcie *imx6_pcie; | 1035 | struct imx6_pcie *imx6_pcie; |
1036 | struct device_node *np; | ||
997 | struct resource *dbi_base; | 1037 | struct resource *dbi_base; |
998 | struct device_node *node = dev->of_node; | 1038 | struct device_node *node = dev->of_node; |
999 | int ret; | 1039 | int ret; |
@@ -1013,6 +1053,23 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
1013 | imx6_pcie->pci = pci; | 1053 | imx6_pcie->pci = pci; |
1014 | imx6_pcie->drvdata = of_device_get_match_data(dev); | 1054 | imx6_pcie->drvdata = of_device_get_match_data(dev); |
1015 | 1055 | ||
1056 | /* Find the PHY if one is defined, only imx7d uses it */ | ||
1057 | np = of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0); | ||
1058 | if (np) { | ||
1059 | struct resource res; | ||
1060 | |||
1061 | ret = of_address_to_resource(np, 0, &res); | ||
1062 | if (ret) { | ||
1063 | dev_err(dev, "Unable to map PCIe PHY\n"); | ||
1064 | return ret; | ||
1065 | } | ||
1066 | imx6_pcie->phy_base = devm_ioremap_resource(dev, &res); | ||
1067 | if (IS_ERR(imx6_pcie->phy_base)) { | ||
1068 | dev_err(dev, "Unable to map PCIe PHY\n"); | ||
1069 | return PTR_ERR(imx6_pcie->phy_base); | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1016 | dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1073 | dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1017 | pci->dbi_base = devm_ioremap_resource(dev, dbi_base); | 1074 | pci->dbi_base = devm_ioremap_resource(dev, dbi_base); |
1018 | if (IS_ERR(pci->dbi_base)) | 1075 | if (IS_ERR(pci->dbi_base)) |