arm: tegra: make sure that the PG request is accepted by PMC
Prashant Gaikwad [Tue, 15 Oct 2013 12:19:54 +0000 (17:19 +0530)]
The role of START bit has changed, beginning T35. To account
for bug 863229 start bit will now be cleared by HW when PMC
accepts the request to powergate or unpowergate the partition.
So in order to powergate/unpowergate a partition SW needs to
do the following.

1. Check to see if the partition is already in the correct state,
by looking at the PWRGATE_STATUS register. If not then SW reads
the PWRGATE_TOGGLE register to see if START bit is 0. If not poll
till start bit is set to 0.
2. After that program the PWRGATE_TOGGLE register with start bit
set as 1 and choose the required partition to be powrgated.
3. Ideally then SW can poll to check the START bit going back to 0,
to indicate that PMC has accepted the request.
4. Then poll the STATUS register to make sure the required partition
is powergated/unpowergated.

Also, in current implementation SW is polling REMOVE_CLAMPING_CMD to
check the CLAMP remove status. As per the HW guys this register is
write only and does no make sense polling it. Instead use CLAMP_STATUS
for polling.

Bug 1376147

Change-Id: Id34e900dff870d4d22288922ee1d0487ab4911dc
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Reviewed-on: http://git-master/r/299801
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>

arch/arm/mach-tegra/powergate.c

index 1b88a8f..565da8f 100644 (file)
@@ -58,6 +58,7 @@ int tegra_powergate_set(int id, bool new_state)
        bool status;
        unsigned long flags;
        spinlock_t *lock;
+       u32 reg;
 
        /* 10us timeout for toggle operation if it takes affect*/
        int toggle_timeout = 10;
@@ -88,7 +89,38 @@ int tegra_powergate_set(int id, bool new_state)
                return 0;
        }
 
+#if !defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       /* Wait if PMC is already processing some other power gating request */
+       do {
+               udelay(1);
+               reg = pmc_read(PWRGATE_TOGGLE);
+               contention_timeout--;
+       } while ((contention_timeout > 0) && (status & PWRGATE_TOGGLE_START));
+
+       if (contention_timeout <= 0)
+               pr_err(" Timed out waiting for PMC to submit \
+                               new power gate request \n");
+       contention_timeout = 100;
+#endif
+
+       /* Submit power gate request */
        pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
+
+#if !defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       /* Wait while PMC accepts the request */
+       do {
+               udelay(1);
+               reg = pmc_read(PWRGATE_TOGGLE);
+               contention_timeout--;
+       } while ((contention_timeout > 0) && (status & PWRGATE_TOGGLE_START));
+
+       if (contention_timeout <= 0)
+               pr_err(" Timed out waiting for PMC to accept \
+                               new power gate request \n");
+       contention_timeout = 100;
+#endif
+
+       /* Check power gate status */
        do {
                do {
                        udelay(1);
@@ -330,7 +362,7 @@ int tegra_powergate_remove_clamping(int id)
                udelay(1);
                contention_timeout--;
        } while ((contention_timeout > 0)
-                       && (pmc_read(REMOVE_CLAMPING) & mask));
+                       && (pmc_read(PWRGATE_CLAMP_STATUS) & mask));
 
        WARN(contention_timeout <= 0, "Couldn't remove clamping");