pci: tegra: port to standard clock/reset/pwr domain APIs

Tegra186 supports the new standard clock, reset, and power domain APIs.
Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so
that it can operate with either set of APIs.

On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming.
Consequently, this logic is disabled too.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Tom Warren <twarren@nvidia.com>
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index 352cdef..ea8adb98 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -13,22 +13,35 @@
 #define pr_fmt(fmt) "tegra-pcie: " fmt
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
 #include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
 #include <pci.h>
+#include <power-domain.h>
+#include <reset.h>
 
 #include <asm/io.h>
 #include <asm/gpio.h>
 
+#include <linux/list.h>
+
+#ifndef CONFIG_TEGRA186
 #include <asm/arch/clock.h>
 #include <asm/arch/powergate.h>
 #include <asm/arch-tegra/xusb-padctl.h>
-
-#include <linux/list.h>
-
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+#endif
+
+/*
+ * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
+ * should not be present. These are needed because newer Tegra SoCs support
+ * only the standard clock/reset APIs, whereas older Tegra SoCs support only
+ * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
+ * fixed to implement the standard APIs, and all drivers converted to solely
+ * use the new standard APIs, with no ifdefs.
+ */
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -103,6 +116,9 @@
 #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_411	(0x2 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401	(0x0 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211	(0x1 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111	(0x2 << 20)
 
 #define AFI_FUSE			0x104
 #define  AFI_FUSE_PCIE_T0_GEN2_DIS	(1 << 2)
@@ -110,6 +126,7 @@
 #define AFI_PEX0_CTRL			0x110
 #define AFI_PEX1_CTRL			0x118
 #define AFI_PEX2_CTRL			0x128
+#define AFI_PEX2_CTRL_T186		0x19c
 #define  AFI_PEX_CTRL_RST		(1 << 0)
 #define  AFI_PEX_CTRL_CLKREQ_EN		(1 << 1)
 #define  AFI_PEX_CTRL_REFCLK_EN		(1 << 3)
@@ -173,6 +190,7 @@
 	TEGRA30_PCIE,
 	TEGRA124_PCIE,
 	TEGRA210_PCIE,
+	TEGRA186_PCIE,
 };
 
 struct tegra_pcie_port {
@@ -189,6 +207,7 @@
 	unsigned int num_ports;
 	unsigned long pads_pll_ctl;
 	unsigned long tx_ref_sel;
+	unsigned long afi_pex2_ctrl;
 	u32 pads_refclk_cfg0;
 	u32 pads_refclk_cfg1;
 	bool has_pex_clkreq_en;
@@ -209,7 +228,17 @@
 	unsigned long xbar;
 
 	const struct tegra_pcie_soc *soc;
+
+#ifdef CONFIG_TEGRA186
+	struct clk clk_afi;
+	struct clk clk_pex;
+	struct reset_ctl reset_afi;
+	struct reset_ctl reset_pex;
+	struct reset_ctl reset_pcie_x;
+	struct power_domain pwrdom;
+#else
 	struct tegra_xusb_phy *phy;
+#endif
 };
 
 static void afi_writel(struct tegra_pcie *pcie, unsigned long value,
@@ -229,10 +258,12 @@
 	writel(value, pcie->pads.start + offset);
 }
 
+#ifndef CONFIG_TEGRA186
 static unsigned long pads_readl(struct tegra_pcie *pcie, unsigned long offset)
 {
 	return readl(pcie->pads.start + offset);
 }
+#endif
 
 static unsigned long rp_readl(struct tegra_pcie_port *port,
 			      unsigned long offset)
@@ -400,6 +431,24 @@
 			return 0;
 		}
 		break;
+	case TEGRA186_PCIE:
+		switch (lanes) {
+		case 0x0010004:
+			debug("x4 x1 configuration\n");
+			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401;
+			return 0;
+
+		case 0x0010102:
+			debug("x2 x1 x1 configuration\n");
+			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211;
+			return 0;
+
+		case 0x0010101:
+			debug("x1 x1 x1 configuration\n");
+			*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111;
+			return 0;
+		}
+		break;
 	default:
 		break;
 	}
@@ -471,6 +520,7 @@
 		return err;
 	}
 
+#ifndef CONFIG_TEGRA186
 	pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
 	if (pcie->phy) {
 		err = tegra_xusb_phy_prepare(pcie->phy);
@@ -479,6 +529,7 @@
 			return err;
 		}
 	}
+#endif
 
 	fdt_for_each_subnode(fdt, subnode, node) {
 		unsigned int index = 0, num_lanes = 0;
@@ -523,6 +574,44 @@
 	return 0;
 }
 
+#ifdef CONFIG_TEGRA186
+static int tegra_pcie_power_on(struct tegra_pcie *pcie)
+{
+	int ret;
+
+	ret = power_domain_on(&pcie->pwrdom);
+	if (ret) {
+		error("power_domain_on() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_enable(&pcie->clk_afi);
+	if (ret) {
+		error("clk_enable(afi) failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_enable(&pcie->clk_pex);
+	if (ret) {
+		error("clk_enable(pex) failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = reset_deassert(&pcie->reset_afi);
+	if (ret) {
+		error("reset_deassert(afi) failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = reset_deassert(&pcie->reset_pex);
+	if (ret) {
+		error("reset_deassert(pex) failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+#else
 static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 {
 	const struct tegra_pcie_soc *soc = pcie->soc;
@@ -639,6 +728,7 @@
 
 	return 0;
 }
+#endif
 
 static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 {
@@ -647,7 +737,11 @@
 	u32 value;
 	int err;
 
+#ifdef CONFIG_TEGRA186
+	{
+#else
 	if (pcie->phy) {
+#endif
 		value = afi_readl(pcie, AFI_PLLE_CONTROL);
 		value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
 		value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
@@ -675,6 +769,7 @@
 
 	afi_writel(pcie, value, AFI_FUSE);
 
+#ifndef CONFIG_TEGRA186
 	if (pcie->phy)
 		err = tegra_xusb_phy_enable(pcie->phy);
 	else
@@ -684,9 +779,18 @@
 		error("failed to power on PHY: %d\n", err);
 		return err;
 	}
+#endif
 
 	/* take the PCIEXCLK logic out of reset */
+#ifdef CONFIG_TEGRA186
+	err = reset_deassert(&pcie->reset_pcie_x);
+	if (err) {
+		error("reset_deassert(pcie_x) failed: %d\n", err);
+		return err;
+	}
+#else
 	reset_set_enable(PERIPH_ID_PCIEXCLK, 0);
+#endif
 
 	/* finally enable PCIe */
 	value = afi_readl(pcie, AFI_CONFIGURATION);
@@ -787,7 +891,7 @@
 		break;
 
 	case 2:
-		ret = AFI_PEX2_CTRL;
+		ret = port->pcie->soc->afi_pex2_ctrl;
 		break;
 	}
 
@@ -945,6 +1049,7 @@
 		.num_ports = 3,
 		.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
 		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+		.afi_pex2_ctrl = AFI_PEX2_CTRL,
 		.pads_refclk_cfg0 = 0xfa5cfa5c,
 		.pads_refclk_cfg1 = 0xfa5cfa5c,
 		.has_pex_clkreq_en = true,
@@ -972,7 +1077,16 @@
 		.has_cml_clk = true,
 		.has_gen2 = true,
 		.force_pca_enable = true,
-	}
+	},
+	[TEGRA186_PCIE] = {
+		.num_ports = 3,
+		.afi_pex2_ctrl = AFI_PEX2_CTRL_T186,
+		.pads_refclk_cfg0 = 0x80b880b8,
+		.pads_refclk_cfg1 = 0x000480b8,
+		.has_pex_clkreq_en = true,
+		.has_pex_bias_ctrl = true,
+		.has_gen2 = true,
+	},
 };
 
 static int pci_tegra_ofdata_to_platdata(struct udevice *dev)
@@ -996,6 +1110,44 @@
 	struct tegra_pcie *pcie = dev_get_priv(dev);
 	int err;
 
+#ifdef CONFIG_TEGRA186
+	err = clk_get_by_name(dev, "afi", &pcie->clk_afi);
+	if (err) {
+		debug("clk_get_by_name(afi) failed: %d\n", err);
+		return err;
+	}
+
+	err = clk_get_by_name(dev, "pex", &pcie->clk_pex);
+	if (err) {
+		debug("clk_get_by_name(pex) failed: %d\n", err);
+		return err;
+	}
+
+	err = reset_get_by_name(dev, "afi", &pcie->reset_afi);
+	if (err) {
+		debug("reset_get_by_name(afi) failed: %d\n", err);
+		return err;
+	}
+
+	err = reset_get_by_name(dev, "pex", &pcie->reset_pex);
+	if (err) {
+		debug("reset_get_by_name(pex) failed: %d\n", err);
+		return err;
+	}
+
+	err = reset_get_by_name(dev, "pcie_x", &pcie->reset_pcie_x);
+	if (err) {
+		debug("reset_get_by_name(pcie_x) failed: %d\n", err);
+		return err;
+	}
+
+	err = power_domain_get(dev, &pcie->pwrdom);
+	if (err) {
+		debug("power_domain_get() failed: %d\n", err);
+		return err;
+	}
+#endif
+
 	err = tegra_pcie_power_on(pcie);
 	if (err < 0) {
 		error("failed to power on");
@@ -1033,6 +1185,7 @@
 	{ .compatible = "nvidia,tegra30-pcie", .data = TEGRA30_PCIE },
 	{ .compatible = "nvidia,tegra124-pcie", .data = TEGRA124_PCIE },
 	{ .compatible = "nvidia,tegra210-pcie", .data = TEGRA210_PCIE },
+	{ .compatible = "nvidia,tegra186-pcie", .data = TEGRA186_PCIE },
 	{ }
 };