]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00229695 MX6x-Set RBC counters correctly in STOP mode.
authorRanjani Vaidyanathan <ra5478@freescale.com>
Mon, 15 Oct 2012 10:36:02 +0000 (05:36 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:34 +0000 (08:35 +0200)
The REG_BYPASS_COUNTER(RBC) holds off interrupts when the PGC
block is sending signals to power gate the core. This is apart
from the RBC counter's basic functionality to act as counter to
power down the analog portions of the chip.
But the counter needs to be set/cleared only when no interrupts
are pending. And also for correct hold off the interrupts, enable the
counter as close to WFI as possible.
The RBC counts CKIL cycles (32KHz)
So follow the following steps to set the counter
in suspend/resume in mx6_suspend.S:
1. Mask all the GPC interrupts.
2. Write the counter value to the RBC
3. Enable the RBC
4. Unmask all the interrupts.
5. Busy wait for a few usecs to wait for RBC to start counting
in case an interrupt is pending.
4. Execute WFI
Reset the counter after resume in pm.c:
1. Mask all the GPC interrupts.
2. Disable the counter.
3. Set the RBC counter to 0.
4. Wait for 80usec for the write to get accepted.
5. Unmask all the interrupts.

With the above steps, we can minimize the PDNSCR and PUPSCR counters
in the GPC. The basic condition for the RBC counter:
RBC count >= 25 * IPG_CLK + PDNSCR_SW2ISO.
PDNSCR_SW2ISO = PDNSCR_ISO = 1 (counts in IPG_CLK)
PUPSCR_SW2ISO = PUPSCR_ISO = 2 (counts in 32K)

Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
arch/arm/mach-mx6/mx6_suspend.S
arch/arm/mach-mx6/pm.c
arch/arm/mach-mx6/system.c

index 1987581e56aa52746a61bfdced1df4a27db1b05a..f712700a8e685dda2c39462105ef54c79bf419e3 100644 (file)
@@ -233,6 +233,11 @@ wait_for_pll_lock:
        bic     r6, r6, #0x2000000
        str     r6, [r3, #0x14]
 
+periph_clk_switch1:
+       ldr     r6, [r3, #0x48]
+       cmp     r6, #0
+       bne     periph_clk_switch1
+
        /* Set the dividers to default value. */
        ldr     r6, [r3, #0x14]
        bic     r6, r6, #0x70000
@@ -241,14 +246,9 @@ wait_for_pll_lock:
        str     r6, [r3, #0x14]
 
 ahb_podf1:
-       ldr     r0, [r3, #0x48]
-       cmp     r0, #0
-       bne     ahb_podf1
-
-periph_clk_switch1:
        ldr     r6, [r3, #0x48]
        cmp     r6, #0
-       bne     periph_clk_switch1
+       bne     ahb_podf1
 
        /* Move MMDC back to PLL2_PFD2_400 */
        ldr     r6, [r3, #0x14]
@@ -262,7 +262,7 @@ mmdc_loop2:
 
        /* Set DDR clock to divide by 1. */
        ldr     r6, [r3, #0x14]
-       bic     r6, r0, #0x38
+       bic     r6, r6, #0x38
        str     r6, [r3, #0x14]
 
 mmdc_div1:
@@ -1099,6 +1099,12 @@ set ddr iomux to low power mode
        ldr     r1, =CCM_BASE_ADDR
        add     r1, r1, #PERIPBASE_VIRT
        ldr     r0, [r1]
+       ldr     r1, =GPC_BASE_ADDR
+       add     r1, r1, #PERIPBASE_VIRT
+       ldr     r0, [r1]
+       ldr     r1, =CCM_BASE_ADDR
+       add     r1, r1, #PERIPBASE_VIRT
+       ldr     r0, [r1]
 #ifdef CONFIG_MX6_INTER_LDO_BYPASS
        ldr     r1, =ANATOP_BASE_ADDR
        add     r1, r1, #PERIPBASE_VIRT
@@ -1173,6 +1179,66 @@ save resume pointer into SRC_GPR1
        add     r1, r1, #PERIPBASE_VIRT
        str     r3, [r1, #SRC_GPR1_OFFSET]
 
+       /* Mask all GPC interrupts before
+         * enabling the RBC counters to
+         * avoid the counter starting too
+         * early if an interupt is already
+         * pending.
+         */
+       ldr     r3, =GPC_BASE_ADDR
+       add     r3, r3, #PERIPBASE_VIRT
+       ldr     r4, [r3, #0x08]
+       ldr     r5, [r3, #0x0c]
+       ldr     r6, [r3, #0x10]
+       ldr     r7, [r3, #0x14]
+
+       ldr     r8, =0xffffffff
+       str     r8, [r3, #0x08]
+       str     r8, [r3, #0x0c]
+       str     r8, [r3, #0x10]
+       str     r8, [r3, #0x14]
+
+       /* Enable the RBC bypass counter here
+        * to hold off the interrupts.
+        * RBC counter = 32 (1ms)
+        * Minimum RBC delay should be
+        * 400us for the analog LDOs to
+        * power down.
+        */
+       ldr     r1, =CCM_BASE_ADDR
+       add     r1, r1, #PERIPBASE_VIRT
+       ldr     r8, [r1, #0x0]
+       ldr     r0, =0x7E00000
+       bic     r8, r8, r0
+       ldr     r0, =0x4000000
+       orr     r8, r8, r0
+       str     r8, [r1, #0x0]
+
+       /* Enable the counter. */
+       ldr     r8, [r1, #0x0]
+       orr     r8, r8, #0x8000000
+       str     r8, [r1, #0x0]
+
+       /* Unmask all the GPC interrupts. */
+       str     r4, [r3, #0x08]
+       str     r5, [r3, #0x0c]
+       str     r6, [r3, #0x10]
+       str     r7, [r3, #0x14]
+
+       /* Now delay for a short while (3usec)
+         * ARM is at 1GHz at this point
+         * so a short loop should be enough.
+         * This delay is required to ensure that
+         * the RBC counter can start counting in case an
+         * interrupt is already pending or in case an interrupt
+         * arrives just as ARM is about to assert DSM_request.
+         */
+       ldr     r4, =2000
+rbc_loop:
+       sub     r4, r4, #0x1
+       cmp     r4, #0x0
+       bne     rbc_loop
+
 #ifdef CONFIG_MX6_INTER_LDO_BYPASS
        ldr     r1, =ANATOP_BASE_ADDR
        add     r1, r1, #PERIPBASE_VIRT
index d7889312aeac2953c5960716b1d8be27e65c8ceb..b29c6f6ab0d3201514d21c46ba3c8e3637a99b7e 100644 (file)
@@ -350,6 +350,30 @@ static int mx6_suspend_enter(suspend_state_t state)
                suspend_in_iram(state, (unsigned long)iram_paddr,
                        (unsigned long)suspend_iram_base, cpu_type);
 
+               /* Reset the RBC counter. */
+               /* All interrupts should be masked before the
+                 * RBC counter is reset.
+                */
+               /* Mask all interrupts. These will be unmasked by
+                 * the mx6_suspend_restore routine below.
+                 */
+               __raw_writel(0xffffffff, gpc_base + 0x08);
+               __raw_writel(0xffffffff, gpc_base + 0x0c);
+               __raw_writel(0xffffffff, gpc_base + 0x10);
+               __raw_writel(0xffffffff, gpc_base + 0x14);
+
+               /* Clear the RBC counter and RBC_EN bit. */
+               /* Disable the REG_BYPASS_COUNTER. */
+               __raw_writel(__raw_readl(MXC_CCM_CCR) &
+                       ~MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR);
+               /* Make sure we clear REG_BYPASS_COUNT*/
+               __raw_writel(__raw_readl(MXC_CCM_CCR) &
+               (~MXC_CCM_CCR_REG_BYPASS_CNT_MASK), MXC_CCM_CCR);
+               /* Need to wait for a minimum of 2 CLKILS (32KHz) for the
+                 * counter to clear and reset.
+                 */
+               udelay(80);
+
                if (arm_pg) {
                        /* restore gic registers */
                        restore_gic_dist_state(0, &gds);
index 1c37bacdebda9252e0559b6c7e04c4c40298cd0c..6ecd51e9f9eae1176999fcc960aec9c0165986ff 100644 (file)
@@ -153,8 +153,15 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
        if (stop_mode > 0) {
                gpc_set_wakeup(gpc_wake_irq);
                /* Power down and power up sequence */
-               __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET);
-               __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET);
+               /* The PUPSCR counter counts in terms of CLKIL (32KHz) cycles.
+                  * The PUPSCR should include the time it takes for the ARM LDO to
+                  * ramp up.
+                  */
+               __raw_writel(0x202, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET);
+               /* The PDNSCR is a counter that counts in IPG_CLK cycles. This counter
+                 * can be set to minimum values to power down faster.
+                 */
+               __raw_writel(0x101, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET);
                if (stop_mode >= 2) {
                        /* dormant mode, need to power off the arm core */
                        __raw_writel(0x1, gpc_base + GPC_PGC_CPU_PDN_OFFSET);
@@ -198,25 +205,17 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
                                                HW_ANADIG_REG_2P5);
                                }
                        }
-                       /* DL's TO1.0 can't support DSM mode due to ipg glitch */
-                       if ((mx6dl_revision() != IMX_CHIP_REVISION_1_0)
-                                       && stop_mode != 3)
-                               __raw_writel(__raw_readl(MXC_CCM_CCR) |
-                                       MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR);
-
                        if (stop_mode != 3) {
                                /* Make sure we clear WB_COUNT
                                  * and re-config it.
                                  */
                                __raw_writel(__raw_readl(MXC_CCM_CCR) &
-                                       (~MXC_CCM_CCR_WB_COUNT_MASK) &
-                                       (~MXC_CCM_CCR_REG_BYPASS_CNT_MASK), MXC_CCM_CCR);
-                               udelay(80);
-                               /* Reconfigurate WB and RBC counter, need to set WB counter
+                                       (~MXC_CCM_CCR_WB_COUNT_MASK),
+                                       MXC_CCM_CCR);
+                               /* Reconfigure WB, need to set WB counter
                                 * to 0x7 to make sure it work normally */
                                __raw_writel(__raw_readl(MXC_CCM_CCR) |
-                                       (0x7 << MXC_CCM_CCR_WB_COUNT_OFFSET) |
-                                       (0x20 << MXC_CCM_CCR_REG_BYPASS_CNT_OFFSET),
+                                       (0x7 << MXC_CCM_CCR_WB_COUNT_OFFSET),
                                        MXC_CCM_CCR);
 
                                /* Set WB_PER enable */