summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaribabu Narayanan <hnarayanan@nvidia.com>2014-06-16 17:57:46 -0700
committerMatthew Pedro <mapedro@nvidia.com>2014-09-16 21:35:55 -0700
commit4d7daf785c70f7250fb854a4d8458771c2130890 (patch)
treeb0379745970b12f0aa2481cc660ab2cf1f7acd04
parent807725d6864bacd838489bb52ee790f7ce6dbf4c (diff)
arm: tegra: power: add pcie dependency to xusb ops
Due to a HW bug 1320346 in t12x/t13x, PCIE needs to be unpowergated when XUSB is to be accessed. Currently PCIE powergating ops need to be invoked from XUSB driver since powergating module doesn't internally handle this dependency. This patch implements this dependency within the powergating module so that xhci-tegra driver can stay chip-agnostic. Bug 1451279 Bug 1524744 Bug 200027067 Change-Id: I57da2645c9bde1c98b73a906f2ff5e407a3a8380 Reviewed-on: http://git-master/r/424035 (cherry picked from commit ff373b04f297ee653c58a86c6642325037f5d10e) Signed-off-by: Vidya Sagar <vidyas@nvidia.com> Reviewed-on: http://git-master/r/498661 Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/powergate-t12x.c55
-rw-r--r--include/linux/tegra-powergate.h1
2 files changed, 53 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/powergate-t12x.c b/arch/arm/mach-tegra/powergate-t12x.c
index b54989269468..36deee3172c6 100644
--- a/arch/arm/mach-tegra/powergate-t12x.c
+++ b/arch/arm/mach-tegra/powergate-t12x.c
@@ -695,6 +695,39 @@ static int tegra12x_pcie_unpowergate(int id)
return ret;
}
+/*
+ * Due to a HW bug 1320346 in t12x/t13x, PCIE needs to be unpowergated when
+ * XUSB is to be accessed. Since PCIE uses reference counter, we can attempt
+ * to powergated/unpowergate PCIE when XUSB is powergated/unpowergated. This
+ * will ensure that PCIE is unpowergated when (either XUSB or PCIE) needs it
+ * and will be powergated when (neither XUSB nor PCIE) needs it.
+ */
+static int tegra12x_xusbc_powergate(int id)
+{
+ int ret = 0;
+
+ if (!TEGRA_IS_XUSBC_POWERGATE_ID(id))
+ return -EINVAL;
+
+ CHECK_RET(tegra12x_powergate(id));
+ CHECK_RET(tegra12x_pcie_powergate(TEGRA_POWERGATE_PCIE));
+
+ return ret;
+}
+
+static int tegra12x_xusbc_unpowergate(int id)
+{
+ int ret = 0;
+
+ if (!TEGRA_IS_XUSBC_POWERGATE_ID(id))
+ return -EINVAL;
+
+ CHECK_RET(tegra12x_unpowergate(id));
+ CHECK_RET(tegra12x_pcie_unpowergate(TEGRA_POWERGATE_PCIE));
+
+ return ret;
+}
+
int tegra12x_powergate_partition(int id)
{
int ret;
@@ -710,6 +743,8 @@ int tegra12x_powergate_partition(int id)
ret = tegra12x_venc_powergate(id);
else if (id == TEGRA_POWERGATE_PCIE)
ret = tegra12x_pcie_powergate(id);
+ else if (id == TEGRA_POWERGATE_XUSBC)
+ ret = tegra12x_xusbc_powergate(id);
else {
/* call common power-gate API for t1xx */
ret = tegra1xx_powergate(id,
@@ -734,6 +769,8 @@ int tegra12x_unpowergate_partition(int id)
ret = tegra12x_venc_unpowergate(id);
else if (id == TEGRA_POWERGATE_PCIE)
ret = tegra12x_pcie_unpowergate(id);
+ else if (id == TEGRA_POWERGATE_XUSBC)
+ ret = tegra12x_xusbc_unpowergate(id);
else {
ret = tegra1xx_unpowergate(id,
&tegra12x_powergate_partition_info[id]);
@@ -828,11 +865,23 @@ static int tegra12x_powergate_init_refcount(void)
* powergated only when both XUSB and PCIE are not active.
*/
+ atomic_set(&ref_count_pcie, 0);
+
+#ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
+ if (pcie_powered)
+ atomic_inc(&ref_count_pcie);
+ else {
+ tegra12x_unpowergate_partition(TEGRA_POWERGATE_PCIE);
+ pcie_powered = true;
+ }
+#endif
+
+#ifdef CONFIG_TEGRA_XUSB_PLATFORM
if (pcie_powered)
- atomic_set(&ref_count_pcie, 1);
+ atomic_inc(&ref_count_pcie);
else
- atomic_set(&ref_count_pcie, 0);
-
+ tegra12x_unpowergate_partition(TEGRA_POWERGATE_PCIE);
+#endif
return 0;
}
diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h
index b98c61ee04d0..b9017ec48356 100644
--- a/include/linux/tegra-powergate.h
+++ b/include/linux/tegra-powergate.h
@@ -90,6 +90,7 @@
((id) == TEGRA_POWERGATE_DISB))
#define TEGRA_IS_VENC_POWERGATE_ID(id) ((id) == TEGRA_POWERGATE_VENC)
#define TEGRA_IS_PCIE_POWERGATE_ID(id) ((id) == TEGRA_POWERGATE_PCIE)
+#define TEGRA_IS_XUSBC_POWERGATE_ID(id) ((id) == TEGRA_POWERGATE_XUSBC)
#endif
int __init tegra_powergate_init(void);