]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
MLK-10203-1 pci: imx: enable imx6qdl pcie support
authorRichard Zhu <Richard.Zhu@freescale.com>
Thu, 5 Feb 2015 08:13:07 +0000 (16:13 +0800)
committerRichard Zhu <Richard.Zhu@freescale.com>
Wed, 11 Feb 2015 07:19:48 +0000 (15:19 +0800)
enable imx6qdl pcie on imx_3.14 kernel
and add the pcie pm workaround for imx6qdl.
------
L2 can exit by 'reset' or Inband beacon (from remote EP)
toggling phy_powerdown has same effect as 'inband beacon'
So, toggle bit18 of GPR1, used as a workaround of errata
"PCIe PCIe does not support L2 Power Down"
WARNING: This is not official workaround for ERR005723.
Fortunately, we don't encounter issue with this workaround.
User should take own risk to use it.

Signed-off-by: Richard Zhu <Richard.Zhu@freescale.com>
(cherry picked from commit 4cdd4fb7fb3b3e746b66838f4cdd24fccd67c78d)

drivers/pci/host/pci-imx6.c

index c120ee1052b29af1fc89913b7925e9cc37c7a4bc..1b53010ea49c3baca3dd1cabce62645bc139d2bf 100644 (file)
@@ -45,9 +45,11 @@ static u32 ddr_test_region = 0, test_region_size = SZ_2M;
 
 struct imx6_pcie {
        int                     reset_gpio;
+       int                     power_on_gpio;
        struct clk              *pcie_bus;
        struct clk              *pcie_phy;
        struct clk              *pcie_inbound_axi;
+       struct clk              *ref_100m;
        struct clk              *pcie;
        struct pcie_port        pp;
        struct regmap           *iomuxc_gpr;
@@ -292,6 +294,9 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
        struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
        int ret;
 
+       if (gpio_is_valid(imx6_pcie->power_on_gpio))
+               gpio_set_value(imx6_pcie->power_on_gpio, 1);
+
        request_bus_freq(BUS_FREQ_HIGH);
        ret = clk_prepare_enable(imx6_pcie->pcie_phy);
        if (ret) {
@@ -327,6 +332,13 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
                /* power up core phy and enable ref clock */
                regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
                                IMX6Q_GPR1_PCIE_TEST_PD, 0);
+
+               /* sata_ref is not used by pcie on imx6sx */
+               ret = clk_prepare_enable(imx6_pcie->ref_100m);
+               if (ret) {
+                       dev_err(pp->dev, "unable to enable ref_100m\n");
+                       goto err_inbound_axi;
+               }
                /*
                 * the async reset input need ref clock to sync internally,
                 * when the ref clock comes after reset, internal synced
@@ -525,6 +537,9 @@ out:
                         * Power down PCIe PHY.
                         */
                        regulator_disable(imx6_pcie->pcie_phy_regulator);
+               } else {
+                       clk_disable_unprepare(imx6_pcie->ref_100m);
+                       release_bus_freq(BUS_FREQ_HIGH);
                }
        } else {
                tmp = readl(pp->dbi_base + 0x80);
@@ -901,6 +916,16 @@ static int pci_imx_suspend_noirq(struct device *dev)
                        clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
                        release_bus_freq(BUS_FREQ_HIGH);
                }
+       } else {
+               /*
+                * L2 can exit by 'reset' or Inband beacon (from remote EP)
+                * toggling phy_powerdown has same effect as 'inband beacon'
+                * So, toggle bit18 of GPR1, used as a workaround of errata
+                * "PCIe PCIe does not support L2 Power Down"
+                */
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                               IMX6Q_GPR1_PCIE_TEST_PD,
+                               IMX6Q_GPR1_PCIE_TEST_PD);
        }
 
        return 0;
@@ -956,6 +981,15 @@ static int pci_imx_resume_noirq(struct device *dev)
                        if (IS_ENABLED(CONFIG_PCI_MSI))
                                dw_pcie_msi_cfg_restore(pp);
                }
+       } else {
+               /*
+                * L2 can exit by 'reset' or Inband beacon (from remote EP)
+                * toggling phy_powerdown has same effect as 'inband beacon'
+                * So, toggle bit18 of GPR1, used as a workaround of errata
+                * "PCIe PCIe does not support L2 Power Down"
+                */
+               regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+                               IMX6Q_GPR1_PCIE_TEST_PD, 0);
        }
 
        return 0;
@@ -1013,6 +1047,18 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
                }
        }
 
+       imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
+       if (gpio_is_valid(imx6_pcie->power_on_gpio)) {
+               ret = devm_gpio_request_one(&pdev->dev,
+                                       imx6_pcie->power_on_gpio,
+                                       GPIOF_OUT_INIT_LOW,
+                                       "PCIe power enable");
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to get power-on gpio\n");
+                       return ret;
+               }
+       }
+
        /* Fetch clocks */
        imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");
        if (IS_ERR(imx6_pcie->pcie_phy)) {
@@ -1051,6 +1097,14 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
                         syscon_regmap_lookup_by_compatible
                         ("fsl,imx6sx-iomuxc-gpr");
        } else {
+               /* sata_ref is not used by pcie on imx6sx */
+               imx6_pcie->ref_100m = devm_clk_get(&pdev->dev, "ref_100m");
+               if (IS_ERR(imx6_pcie->ref_100m)) {
+                       dev_err(&pdev->dev,
+                               "ref_100m clock source missing or invalid\n");
+                       return PTR_ERR(imx6_pcie->ref_100m);
+               }
+
                imx6_pcie->iomuxc_gpr =
                        syscon_regmap_lookup_by_compatible
                        ("fsl,imx6q-iomuxc-gpr");