ARM: tegra: add refcount to powergate for display
Jon Mayo [Thu, 6 Dec 2012 21:55:27 +0000 (13:55 -0800)]
Keep a refcount for DISA and DISB power domains, as they are shared between
multiple drivers.

Bug 1178366

Change-Id: I30edf2d4922705f15c762342d9f502880f1e01b7
Signed-off-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-on: http://git-master/r/169147
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>

arch/arm/mach-tegra/powergate.c

index 97adc61..c605033 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/spinlock.h>
 #include <linux/clk/tegra.h>
 #include <trace/events/power.h>
+#include <asm/atomic.h>
 
 #include <mach/powergate.h>
 
@@ -1127,6 +1128,11 @@ static bool skip_pg_check(int id, bool is_unpowergate)
 }
 #endif
 
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
+static atomic_t ref_count_a = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISA */
+static atomic_t ref_count_b = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISB */
+#endif
+
 /*
  * Must be called with clk disabled, and returns with clk disabled
  * Drivers should enable clks for partition. Unpowergates only the
@@ -1138,6 +1144,14 @@ int tegra_unpowergate_partition(int id)
 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
        bool is_pg_skip;
 
+       WARN_ONCE(atomic_read(&ref_count_a) < 0, "ref count A underflow");
+       WARN_ONCE(atomic_read(&ref_count_b) < 0, "ref count B underflow");
+       if (id == TEGRA_POWERGATE_DISA && atomic_inc_return(&ref_count_a) != 1)
+               return 0;
+       else if (id == TEGRA_POWERGATE_DISB &&
+               atomic_inc_return(&ref_count_b) != 1)
+               return 0;
+
        is_pg_skip = skip_pg_check(id, true);
        if (is_pg_skip)
                return 0;
@@ -1510,6 +1524,14 @@ int tegra_powergate_partition(int id)
 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
        bool is_pg_skip;
 
+       WARN_ONCE(atomic_read(&ref_count_a) < 0, "ref count A underflow");
+       WARN_ONCE(atomic_read(&ref_count_b) < 0, "ref count B underflow");
+       if (id == TEGRA_POWERGATE_DISA && atomic_dec_return(&ref_count_a) != 0)
+               return 0;
+       else if (id == TEGRA_POWERGATE_DISB &&
+               atomic_dec_return(&ref_count_b) != 0)
+               return 0;
+
        is_pg_skip = skip_pg_check(id, false);
        if (is_pg_skip)
                return 0;