arm: tegra: make sure that the PG request is accepted by PMC
Prashant Gaikwad [Mon, 30 Sep 2013 12:28:59 +0000 (17:28 +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.

Bug 1376147

Change-Id: I5d7818681d1766bf7eca3846ea7d5d7a4d42a109
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Reviewed-on: http://git-master/r/280287
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Bharat Nihalani <bnihalani@nvidia.com>
(cherry picked from commit 7028bfdcaee06241d1691400ccb73afe0a2c659e)
Signed-off-by: Ajay Nandakumar <anandakumarm@nvidia.com>

arch/arm/mach-tegra/powergate.c

index f61de0a..6ebaf30 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);