bfin: pm: add deepsleep for bf60x
authorSonic Zhang <sonic.zhang@analog.com>
Mon, 23 Jul 2012 03:35:30 +0000 (11:35 +0800)
committerBob Liu <lliubbo@gmail.com>
Tue, 24 Jul 2012 05:39:49 +0000 (13:39 +0800)
Add add deepsleep for bf60x.
1. Call DMC init functions to enter and exit DDR self refresh mode.
2. Wait till CGU PLL is locked after wake up and exit DDR self refresh mode.
3. Make asessembly function enter_deepsleep comply with C funtion ABI in
order to call other C functions.
4. Switch kernel stack by register EX_SCRATCH_REG.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bob Liu <lliubbo@gmail.com>
arch/blackfin/include/asm/context.S
arch/blackfin/mach-bf609/Makefile
arch/blackfin/mach-bf609/dpm.S [new file with mode: 0644]
arch/blackfin/mach-bf609/hibernate.S [deleted file]
arch/blackfin/mach-bf609/include/mach/pm.h
arch/blackfin/mach-bf609/pm.c
arch/blackfin/mach-common/entry.S

index 1f9060395a0a7f767e53bcea97f6f83fa6a787f1..507e7aa6a561d56f0e744181c52ceeef9eab7834 100644 (file)
        call \func;
 #endif
 .endm
+
+#if defined(CONFIG_BFIN_SCRATCH_REG_RETN)
+# define EX_SCRATCH_REG RETN
+#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE)
+# define EX_SCRATCH_REG RETE
+#else
+# define EX_SCRATCH_REG CYCLES
+#endif
+
index 2a27f817454367cb1c5b42aac49355f58cd8bee4..9a3d9f252c11ee9b1e69ed86f14d461f32c7ebe0 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 obj-y := dma.o clock.o
-obj-$(CONFIG_PM) += pm.o hibernate.o
+obj-$(CONFIG_PM) += pm.o dpm.o
diff --git a/arch/blackfin/mach-bf609/dpm.S b/arch/blackfin/mach-bf609/dpm.S
new file mode 100644 (file)
index 0000000..62cc319
--- /dev/null
@@ -0,0 +1,155 @@
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/dpmc.h>
+
+#include <asm/context.S>
+
+#define PM_STACK   (COREA_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
+
+.section .l1.text
+ENTRY(_enter_hibernate)
+       /* switch stack to L1 scratch, prepare for ddr srfr */
+       P0.H = HI(PM_STACK);
+       P0.L = LO(PM_STACK);
+       SP = P0;
+
+       call _bf609_ddr_sr;
+       call _bfin_hibernate_syscontrol;
+
+       P0.H = HI(DPM0_RESTORE4);
+       P0.L = LO(DPM0_RESTORE4);
+       P1.H = _bf609_pm_data;
+       P1.L = _bf609_pm_data;
+       [P0] = P1;
+
+       P0.H = HI(DPM0_CTL);
+       P0.L = LO(DPM0_CTL);
+       R3.H = HI(0x00000010);
+       R3.L = LO(0x00000010);
+
+       bfin_init_pm_bench_cycles;
+
+       [P0] = R3;
+
+       SSYNC;
+ENDPROC(_enter_hibernate)
+
+/* DPM wake up interrupt won't wake up core on bf60x if its core IMASK
+ * is disabled. This behavior differ from bf5xx serial processor.
+ */
+ENTRY(_dummy_deepsleep)
+       [--sp] = SYSCFG;
+       [--sp] = (R7:0,P5:0);
+       cli r0;
+
+       /* get wake up interrupt ID */
+       P0.l = LO(SEC_SCI_BASE + SEC_CSID);
+       P0.h = HI(SEC_SCI_BASE + SEC_CSID);
+       R0 = [P0];
+
+       /* ACK wake up interrupt in SEC */
+       P1.l = LO(SEC_END);
+       P1.h = HI(SEC_END);
+
+       [P1] = R0;
+       SSYNC;
+
+       /* restore EVT 11 entry */
+       p0.h = hi(EVT11);
+       p0.l = lo(EVT11);
+       p1.h = _evt_evt11;
+       p1.l = _evt_evt11;
+
+       [p0] = p1;
+       SSYNC;
+
+       (R7:0,P5:0) = [sp++];
+       SYSCFG = [sp++];
+       RTI;
+ENDPROC(_dummy_deepsleep)
+
+ENTRY(_enter_deepsleep)
+       LINK 0x0;
+       [--sp] = (R7:0,P5:0);
+
+       /* Change EVT 11 entry to dummy handler for wake up event */
+       p0.h = hi(EVT11);
+       p0.l = lo(EVT11);
+       p1.h = _dummy_deepsleep;
+       p1.l = _dummy_deepsleep;
+
+       [p0] = p1;
+
+       P0.H = HI(PM_STACK);
+       P0.L = LO(PM_STACK);
+
+       EX_SCRATCH_REG = SP;
+       SP = P0;
+
+       SSYNC;
+
+       /* should put ddr to self refresh mode before sleep */
+       call _bf609_ddr_sr;
+
+       /* Set DPM controller to deep sleep mode */
+       P0.H = HI(DPM0_CTL);
+       P0.L = LO(DPM0_CTL);
+       R3.H = HI(0x00000008);
+       R3.L = LO(0x00000008);
+       [P0] = R3;
+       CSYNC;
+
+       /* Enable evt 11 in IMASK before idle, otherwise core doesn't wake up. */
+       r0.l = 0x800;
+       r0.h = 0;
+       sti r0;
+       SSYNC;
+
+       /* Fall into deep sleep in idle*/
+       idle;
+       SSYNC;
+
+       /* Restore PLL after wake up from deep sleep */
+       call _bf609_resume_ccbuf;
+
+       /* turn ddr out of self refresh mode */
+       call _bf609_ddr_sr_exit;
+
+       SP = EX_SCRATCH_REG;
+
+       (R7:0,P5:0) = [SP++];
+       UNLINK;
+       RTS;
+ENDPROC(_enter_deepsleep)
+
+.section .text
+ENTRY(_bf609_hibernate)
+       bfin_cpu_reg_save;
+       bfin_core_mmr_save;
+
+       P0.H = _bf609_pm_data;
+       P0.L = _bf609_pm_data;
+       R1.H = 0xDEAD;
+       R1.L = 0xBEEF;
+       R2.H = .Lpm_resume_here;
+       R2.L = .Lpm_resume_here;
+       [P0++] = R1;
+       [P0++] = R2;
+       [P0++] = SP;
+
+       P1.H = _enter_hibernate;
+       P1.L = _enter_hibernate;
+
+       call (P1);
+.Lpm_resume_here:
+
+       bfin_core_mmr_restore;
+       bfin_cpu_reg_restore;
+
+       [--sp] = RETI;  /* Clear Global Interrupt Disable */
+       SP += 4;
+
+       RTS;
+
+ENDPROC(_bf609_hibernate)
+
diff --git a/arch/blackfin/mach-bf609/hibernate.S b/arch/blackfin/mach-bf609/hibernate.S
deleted file mode 100644 (file)
index d37a532..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <linux/linkage.h>
-#include <asm/blackfin.h>
-#include <asm/dpmc.h>
-
-#define PM_STACK   (COREA_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
-
-.section .l1.text
-ENTRY(_enter_hibernate)
-       /* switch stack to L1 scratch, prepare for ddr srfr */
-       P0.H = HI(PM_STACK);
-       P0.L = LO(PM_STACK);
-       SP = P0;
-
-       call _bf609_ddr_sr;
-       call _bfin_hibernate_syscontrol;
-
-       P0.H = HI(DPM0_RESTORE4);
-       P0.L = LO(DPM0_RESTORE4);
-       P1.H = _bf609_pm_data;
-       P1.L = _bf609_pm_data;
-       [P0] = P1;
-
-       P0.H = HI(DPM0_CTL);
-       P0.L = LO(DPM0_CTL);
-       R3.H = HI(0x00000010);
-       R3.L = LO(0x00000010);
-
-       bfin_init_pm_bench_cycles;
-
-       [P0] = R3;
-
-       SSYNC;
-ENDPROC(_enter_hibernate_mode)
-
-.section .text
-ENTRY(_bf609_hibernate)
-       bfin_cpu_reg_save;
-       bfin_core_mmr_save;
-
-       P0.H = _bf609_pm_data;
-       P0.L = _bf609_pm_data;
-       R1.H = 0xDEAD;
-       R1.L = 0xBEEF;
-       R2.H = .Lpm_resume_here;
-       R2.L = .Lpm_resume_here;
-       [P0++] = R1;
-       [P0++] = R2;
-       [P0++] = SP;
-
-       P1.H = _enter_hibernate;
-       P1.L = _enter_hibernate;
-
-       call (P1);
-.Lpm_resume_here:
-
-       bfin_core_mmr_restore;
-       bfin_cpu_reg_restore;
-
-       [--sp] = RETI;  /* Clear Global Interrupt Disable */
-       SP += 4;
-
-       RTS;
-
-ENDPROC(_bf609_hibernate)
-
index 036d9bdc889e0d8c9e7b4719d3872bc9cfdecfda..68435f9bafca4cd9118685918f119f93a8b8c240 100644 (file)
@@ -11,9 +11,9 @@
 
 #include <linux/suspend.h>
 
-int bfin609_pm_enter(suspend_state_t state);
-int bf609_pm_prepare(void);
-void bf609_pm_finish(void);
+extern int bfin609_pm_enter(suspend_state_t state);
+extern int bf609_pm_prepare(void);
+extern void bf609_pm_finish(void);
 
 void bf609_hibernate(void);
 void bfin_sec_raise_irq(unsigned int sid);
index b76966eb16ad9e387925243a477aee48130f83dd..6094c7d3b1f2cd564643a5ee91d70624bfd8db70 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/pm.h>
 #include <mach/pm.h>
 #include <asm/blackfin.h>
+#include <asm/mem_init.h>
 
 /***********************************************************/
 /*                                                         */
@@ -132,60 +133,30 @@ void bfin_cpu_suspend(void)
 }
 
 __attribute__((l1_text))
-void bfin_deepsleep(unsigned long mask)
+void bf609_ddr_sr(void)
 {
-       uint32_t dpm0_ctl;
-
-       bfin_write32(DPM0_WAKE_EN, 0x10);
-       bfin_write32(DPM0_WAKE_POL, 0x10);
-       dpm0_ctl = 0x00000008;
-       bfin_write32(DPM0_CTL, dpm0_ctl);
-       SSYNC();
-       __asm__ __volatile__( \
-                       ".align 8;" \
-                       "idle;" \
-                       : : \
-                       );
-#ifdef CONFIG_BFIN_PM_WAKEUP_TIME_BENCH
-       __asm__ __volatile__(
-               "R0 = 0;"
-               "CYCLES = R0;"
-               "CYCLES2 = R0;"
-               "R0 = SYSCFG;"
-               "BITSET(R0, 1);"
-               "SYSCFG = R0;"
-               : : : "R0"
-       );
-#endif
-
+       dmc_enter_self_refresh();
 }
 
 __attribute__((l1_text))
-void bf609_ddr_sr(void)
+void bf609_ddr_sr_exit(void)
 {
-       uint32_t reg;
-
-       reg = bfin_read_DMC0_CTL();
-       reg |= 0x8;
-       bfin_write_DMC0_CTL(reg);
+       dmc_exit_self_refresh();
 
-       while (!(bfin_read_DMC0_STAT() & 0x8))
+       /* After wake up from deep sleep and exit DDR from self refress mode,
+        * should wait till CGU PLL is locked.
+        */
+       while (bfin_read32(CGU0_STAT) & CLKSALGN)
                continue;
 }
 
 __attribute__((l1_text))
-void bf609_ddr_sr_exit(void)
+void bf609_resume_ccbuf(void)
 {
-       uint32_t reg;
-       while (!(bfin_read_DMC0_STAT() & 0x1))
-               continue;
+       bfin_write32(DPM0_CCBF_EN, 3);
+       bfin_write32(DPM0_CTL, 2);
 
-       reg = bfin_read_DMC0_CTL();
-       reg &= ~0x8;
-       bfin_write_DMC0_CTL(reg);
-
-       while ((bfin_read_DMC0_STAT() & 0x8))
-               continue;
+       while ((bfin_read32(DPM0_STAT) & 0xf) != 1);
 }
 
 __attribute__((l1_text))
@@ -208,6 +179,17 @@ void bfin_hibernate_syscontrol(void)
 #else
 # define SIC_SYSIRQ(irq)       ((irq) - IVG15)
 #endif
+asmlinkage void enter_deepsleep(void);
+
+__attribute__((l1_text))
+void bfin_deepsleep(unsigned long mask)
+{
+       bfin_write32(DPM0_WAKE_EN, 0x10);
+       bfin_write32(DPM0_WAKE_POL, 0x10);
+       SSYNC();
+       enter_deepsleep();
+}
+
 void bfin_hibernate(unsigned long mask)
 {
        bfin_write32(DPM0_WAKE_EN, 0x10);
@@ -215,8 +197,6 @@ void bfin_hibernate(unsigned long mask)
        bfin_write32(DPM0_PGCNTR, 0x0000FFFF);
        bfin_write32(DPM0_HIB_DIS, 0xFFFF);
 
-       printk(KERN_DEBUG "hibernate: restore %x pgcnt %x\n", bfin_read32(DPM0_RESTORE0), bfin_read32(DPM0_PGCNTR));
-
        bf609_hibernate();
 }
 
@@ -294,6 +274,7 @@ void bf609_cpu_pm_enter(suspend_state_t state)
        else {
                bfin_hibernate(wakeup);
        }
+
 }
 
 int bf609_cpu_pm_prepare(void)
@@ -320,21 +301,18 @@ static irqreturn_t test_isr(int irq, void *dev_id)
 
 static irqreturn_t dpm0_isr(int irq, void *dev_id)
 {
-       uint32_t wake_stat;
-
-       wake_stat = bfin_read32(DPM0_WAKE_STAT);
-       printk(KERN_DEBUG "enter %s wake stat %08x\n", __func__, wake_stat);
-
-       bfin_write32(DPM0_WAKE_STAT, wake_stat);
+       bfin_write32(DPM0_WAKE_STAT, bfin_read32(DPM0_WAKE_STAT));
+       bfin_write32(CGU0_STAT, bfin_read32(CGU0_STAT));
        return IRQ_HANDLED;
 }
+#endif
 
 static int __init bf609_init_pm(void)
 {
        int irq;
        int error;
 
-#if CONFIG_PM_BFIN_WAKE_PE12
+#ifdef CONFIG_PM_BFIN_WAKE_PE12
        irq = gpio_to_irq(GPIO_PE12);
        if (irq < 0) {
                error = irq;
index 04c2fbe41a7ff3e7193532b1e809b8dbcb7474ee..1c3d2c5bb0bb873fcec8f65eb48379279e479c65 100644 (file)
 
 #include <asm/context.S>
 
-#if defined(CONFIG_BFIN_SCRATCH_REG_RETN)
-# define EX_SCRATCH_REG RETN
-#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE)
-# define EX_SCRATCH_REG RETE
-#else
-# define EX_SCRATCH_REG CYCLES
-#endif
 
 #ifdef CONFIG_EXCPT_IRQ_SYSC_L1
 .section .l1.text