]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
arm: tegra: power: add pcie dependency to xusb ops
authorHaribabu Narayanan <hnarayanan@nvidia.com>
Tue, 17 Jun 2014 00:57:46 +0000 (17:57 -0700)
committerMatthew Pedro <mapedro@nvidia.com>
Wed, 17 Sep 2014 04:35:55 +0000 (21:35 -0700)
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>
arch/arm/mach-tegra/powergate-t12x.c
include/linux/tegra-powergate.h

index b549892694682ac60c8236dcac4ddaec8a1cba2e..36deee3172c6d6f753ad994577137f88dd741037 100644 (file)
@@ -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;
 }
 
index b98c61ee04d0de11c78f478954304c28e5451c70..b9017ec48356984da5b991e8ea1b8e6b4c465649 100644 (file)
@@ -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);