]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
PCI: tegra: Add Tegra186 PCIe support
authorManikanta Maddireddy <mmaddireddy@nvidia.com>
Wed, 27 Sep 2017 11:58:35 +0000 (17:28 +0530)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 18 Oct 2017 16:27:17 +0000 (11:27 -0500)
Add Tegra186 PCIe support.  UPHY programming is performed by BPMP; PHY
enable calls are not required for Tegra186 PCIe.

Power partition ungate is done by BPMP powergate driver.  The Tegra186
DT description must include a "power-domains" property, which results in
dev->pm_domain being set.

Tested-by: Mikko Perttunen <mperttunen@nvidia.com>
Tested-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
[bhelgaas: add "power-domains" reference]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
drivers/pci/host/pci-tegra.c

index e8e1ddbaabc9aaffcd46970ee5842074049ea685..8dd3b3f7d1417f533b24801617cfb61551966638 100644 (file)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE    (0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420       (0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1     (0x0 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401       (0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL      (0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222       (0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1     (0x1 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211       (0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411       (0x2 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111       (0x2 << 20)
 
 #define AFI_FUSE                       0x104
 #define  AFI_FUSE_PCIE_T0_GEN2_DIS     (1 << 2)
@@ -252,6 +255,7 @@ struct tegra_pcie_soc {
        bool has_cml_clk;
        bool has_gen2;
        bool force_pca_enable;
+       bool program_uphy;
 };
 
 static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip)
@@ -1032,10 +1036,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
                afi_writel(pcie, value, AFI_FUSE);
        }
 
-       err = tegra_pcie_phy_power_on(pcie);
-       if (err < 0) {
-               dev_err(dev, "failed to power on PHY(s): %d\n", err);
-               return err;
+       if (soc->program_uphy) {
+               err = tegra_pcie_phy_power_on(pcie);
+               if (err < 0) {
+                       dev_err(dev, "failed to power on PHY(s): %d\n", err);
+                       return err;
+               }
        }
 
        /* take the PCIe interface module out of reset */
@@ -1068,19 +1074,23 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 {
        struct device *dev = pcie->dev;
+       const struct tegra_pcie_soc *soc = pcie->soc;
        int err;
 
        /* TODO: disable and unprepare clocks? */
 
-       err = tegra_pcie_phy_power_off(pcie);
-       if (err < 0)
-               dev_err(dev, "failed to power off PHY(s): %d\n", err);
+       if (soc->program_uphy) {
+               err = tegra_pcie_phy_power_off(pcie);
+               if (err < 0)
+                       dev_err(dev, "failed to power off PHY(s): %d\n", err);
+       }
 
        reset_control_assert(pcie->pcie_xrst);
        reset_control_assert(pcie->afi_rst);
        reset_control_assert(pcie->pex_rst);
 
-       tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+       if (!dev->pm_domain)
+               tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
 
        err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
        if (err < 0)
@@ -1097,19 +1107,29 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
        reset_control_assert(pcie->afi_rst);
        reset_control_assert(pcie->pex_rst);
 
-       tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+       if (!dev->pm_domain)
+               tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
 
        /* enable regulators */
        err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
        if (err < 0)
                dev_err(dev, "failed to enable regulators: %d\n", err);
 
-       err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
-                                               pcie->pex_clk,
-                                               pcie->pex_rst);
-       if (err) {
-               dev_err(dev, "powerup sequence failed: %d\n", err);
-               return err;
+       if (dev->pm_domain) {
+               err = clk_prepare_enable(pcie->pex_clk);
+               if (err) {
+                       dev_err(dev, "failed to enable PEX clock: %d\n", err);
+                       return err;
+               }
+               reset_control_deassert(pcie->pex_rst);
+       } else {
+               err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
+                                                       pcie->pex_clk,
+                                                       pcie->pex_rst);
+               if (err) {
+                       dev_err(dev, "powerup sequence failed: %d\n", err);
+                       return err;
+               }
        }
 
        reset_control_deassert(pcie->afi_rst);
@@ -1282,6 +1302,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
        struct device *dev = pcie->dev;
        struct platform_device *pdev = to_platform_device(dev);
        struct resource *pads, *afi, *res;
+       const struct tegra_pcie_soc *soc = pcie->soc;
        int err;
 
        err = tegra_pcie_clocks_get(pcie);
@@ -1296,10 +1317,12 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
                return err;
        }
 
-       err = tegra_pcie_phys_get(pcie);
-       if (err < 0) {
-               dev_err(dev, "failed to get PHYs: %d\n", err);
-               return err;
+       if (soc->program_uphy) {
+               err = tegra_pcie_phys_get(pcie);
+               if (err < 0) {
+                       dev_err(dev, "failed to get PHYs: %d\n", err);
+                       return err;
+               }
        }
 
        err = tegra_pcie_power_on(pcie);
@@ -1361,6 +1384,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
 static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
 {
        struct device *dev = pcie->dev;
+       const struct tegra_pcie_soc *soc = pcie->soc;
        int err;
 
        if (pcie->irq > 0)
@@ -1368,9 +1392,11 @@ static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
 
        tegra_pcie_power_off(pcie);
 
-       err = phy_exit(pcie->phy);
-       if (err < 0)
-               dev_err(dev, "failed to teardown PHY: %d\n", err);
+       if (soc->program_uphy) {
+               err = phy_exit(pcie->phy);
+               if (err < 0)
+                       dev_err(dev, "failed to teardown PHY: %d\n", err);
+       }
 
        return 0;
 }
@@ -1636,8 +1662,32 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
        struct device *dev = pcie->dev;
        struct device_node *np = dev->of_node;
 
-       if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
-           of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
+       if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
+               switch (lanes) {
+               case 0x010004:
+                       dev_info(dev, "4x1, 1x1 configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401;
+                       return 0;
+
+               case 0x010102:
+                       dev_info(dev, "2x1, 1X1, 1x1 configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
+                       return 0;
+
+               case 0x010101:
+                       dev_info(dev, "1x1, 1x1, 1x1 configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111;
+                       return 0;
+
+               default:
+                       dev_info(dev, "wrong configuration updated in DT, "
+                                "switching to default 2x1, 1x1, 1x1 "
+                                "configuration\n");
+                       *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
+                       return 0;
+               }
+       } else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
+                  of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
                switch (lanes) {
                case 0x0000104:
                        dev_info(dev, "4x1, 1x1 configuration\n");
@@ -1757,7 +1807,20 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
        struct device_node *np = dev->of_node;
        unsigned int i = 0;
 
-       if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
+       if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
+               pcie->num_supplies = 4;
+
+               pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
+                                             sizeof(*pcie->supplies),
+                                             GFP_KERNEL);
+               if (!pcie->supplies)
+                       return -ENOMEM;
+
+               pcie->supplies[i++].supply = "dvdd-pex";
+               pcie->supplies[i++].supply = "hvdd-pex-pll";
+               pcie->supplies[i++].supply = "hvdd-pex";
+               pcie->supplies[i++].supply = "vddio-pexctl-aud";
+       } else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
                pcie->num_supplies = 6;
 
                pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
@@ -2096,6 +2159,7 @@ static const struct tegra_pcie_soc tegra20_pcie = {
        .has_cml_clk = false,
        .has_gen2 = false,
        .force_pca_enable = false,
+       .program_uphy = true,
 };
 
 static const struct tegra_pcie_soc tegra30_pcie = {
@@ -2111,6 +2175,7 @@ static const struct tegra_pcie_soc tegra30_pcie = {
        .has_cml_clk = true,
        .has_gen2 = false,
        .force_pca_enable = false,
+       .program_uphy = true,
 };
 
 static const struct tegra_pcie_soc tegra124_pcie = {
@@ -2125,6 +2190,7 @@ static const struct tegra_pcie_soc tegra124_pcie = {
        .has_cml_clk = true,
        .has_gen2 = true,
        .force_pca_enable = false,
+       .program_uphy = true,
 };
 
 static const struct tegra_pcie_soc tegra210_pcie = {
@@ -2139,9 +2205,27 @@ static const struct tegra_pcie_soc tegra210_pcie = {
        .has_cml_clk = true,
        .has_gen2 = true,
        .force_pca_enable = true,
+       .program_uphy = true,
+};
+
+static const struct tegra_pcie_soc tegra186_pcie = {
+       .num_ports = 3,
+       .msi_base_shift = 8,
+       .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+       .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+       .pads_refclk_cfg0 = 0x80b880b8,
+       .pads_refclk_cfg1 = 0x000480b8,
+       .has_pex_clkreq_en = true,
+       .has_pex_bias_ctrl = true,
+       .has_intr_prsnt_sense = true,
+       .has_cml_clk = false,
+       .has_gen2 = true,
+       .force_pca_enable = false,
+       .program_uphy = false,
 };
 
 static const struct of_device_id tegra_pcie_of_match[] = {
+       { .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie },
        { .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie },
        { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie },
        { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie },