summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mvf/mvf_suspend.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mvf/mvf_suspend.S')
-rw-r--r--arch/arm/mach-mvf/mvf_suspend.S484
1 files changed, 484 insertions, 0 deletions
diff --git a/arch/arm/mach-mvf/mvf_suspend.S b/arch/arm/mach-mvf/mvf_suspend.S
new file mode 100644
index 000000000000..ce9205162538
--- /dev/null
+++ b/arch/arm/mach-mvf/mvf_suspend.S
@@ -0,0 +1,484 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/linkage.h>
+#include <mach/hardware.h>
+#include <asm/memory.h>
+#include <mach/mvf.h>
+#include "regs-src.h"
+#include "crm_regs.h"
+
+#define PERIPBASE_VIRT_OFFSET 0xb2000000
+#define TTRBIT_MASK 0xffffc000
+#define TABLE_INDEX_MASK 0xfff00000
+#define TABLE_ENTRY 0x00000c02
+#define CACHE_DISABLE_MASK 0xfffffffb
+#define IRAM_SUSPEND_SIZE (1 << 15)
+
+/*************************************************************
+mvf_suspend:
+
+Suspend the processor (eg, wait for interrupt).
+
+r1: iram_paddr
+r2: suspend_iram_base
+*************************************************************/
+
+ .macro mvf_stop_mode_enter
+
+ ldr r3, =MVF_ANATOP_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+
+ /* pll7 disable */
+ ldr r4, [r3, #0x20]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x20]
+
+ /* pll3 disable */
+ ldr r4, [r3, #0x10]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x10]
+
+ /* pll4 disable */
+ ldr r4, [r3, #0x70]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x70]
+
+ /* pll6 disable */
+ ldr r4, [r3, #0xa0]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0xa0]
+
+ /* pll5 disable */
+ ldr r4, [r3, #0xe0]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0xe0]
+
+ /* pll1 disable */
+ ldr r4, [r3, #0x270]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x270]
+
+ /* stop mode is masked to Anatop */
+ ldr r3, =MVF_CCM_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+
+ ldr r4, [r3, #0x2c]
+ bic r4, r4, #0x100
+ str r4, [r3, #0x2c]
+
+ ldr r3, =MVF_GPC_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+
+ /* ensure power domain 0 */
+ ldr r4, [r3, #0x0]
+ bic r4, r4, #0x01
+ str r4, [r3, #0x0]
+
+ /* enable deep sleep for memories */
+ ldr r4, [r3, #0x0]
+ orr r4, r4, #0x80
+ str r4, [r3, #0x0]
+
+ /* disable well bias */
+ ldr r4, [r3, #0x0]
+ bic r4, r4, #0x10
+ str r4, [r3, #0x0]
+
+ /* turn off HPREG in stop mode */
+ ldr r4, [r3, #0x0]
+ orr r4, r4, #0x08
+ str r4, [r3, #0x0]
+
+ /* gpc_lpmr set stop mode */
+ ldr r4, =0x02
+ str r4, [r3, #0x40]
+
+ .endm
+
+ .macro mvf_lpstop_mode_enter
+
+ ldr r3, =MVF_ANATOP_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+
+ /* pll7 disable */
+ ldr r4, [r3, #0x20]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x20]
+
+ /* pll3 disable */
+ ldr r4, [r3, #0x10]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x10]
+
+ /* pll4 disable */
+ ldr r4, [r3, #0x70]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x70]
+
+ /* pll6 disable */
+ ldr r4, [r3, #0xa0]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0xa0]
+
+ /* pll5 disable */
+ ldr r4, [r3, #0xe0]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0xe0]
+
+ /* pll1 disable */
+ ldr r4, [r3, #0x270]
+ bic r4, r4, #0x2000
+ str r4, [r3, #0x270]
+
+ ldr r3, =MVF_CCM_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+
+ ldr r4, [r3, #0x2c]
+ bic r4, r4, #0x100
+ str r4, [r3, #0x2c]
+
+ ldr r3, =MVF_GPC_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+
+ /* enable deep sleep for memories */
+ ldr r4, [r3, #0x0]
+ orr r4, r4, #0x40
+ str r4, [r3, #0x0]
+
+ /* enable LPSTOP3 */
+ ldr r4, [r3, #0x0]
+ bic r4, r4, #0x04
+ bic r4, r4, #0x02
+ str r4, [r3, #0x0]
+
+ /* ensure power domain 1 */
+ ldr r4, [r3, #0x0]
+ orr r4, r4, #0x01
+ str r4, [r3, #0x0]
+
+ /* gpc_lpmr set low-power stop mode */
+ ldr r4, =0x02
+ str r4, [r3, #0x40]
+
+ .endm
+
+/******************************************************************
+Invalidate l1 dcache, r0-r4, r6, r7 used
+******************************************************************/
+ .macro invalidate_l1_dcache
+
+ mov r0, #0
+ mcr p15, 2, r0, c0, c0, 0
+ mrc p15, 1, r0, c0, c0, 0
+
+ ldr r1, =0x7fff
+ and r2, r1, r0, lsr #13
+
+ ldr r1, =0x3ff
+
+ and r3, r1, r0, lsr #3 @ NumWays - 1
+ add r2, r2, #1 @ NumSets
+
+ and r0, r0, #0x7
+ add r0, r0, #4 @ SetShift
+
+ clz r1, r3 @ WayShift
+ add r4, r3, #1 @ NumWays
+1:
+ sub r2, r2, #1 @ NumSets--
+ mov r3, r4 @ Temp = NumWays
+2:
+ subs r3, r3, #1 @ Temp--
+ mov r7, r3, lsl r1
+ mov r6, r2, lsl r0
+ orr r7, r7, r6
+ mcr p15, 0, r7, c7, c6, 2
+ bgt 2b
+ cmp r2, #0
+ bgt 1b
+ dsb
+ isb
+
+ .endm
+
+/******************************************************************
+Flush and disable L1 dcache
+******************************************************************/
+ .macro flush_disable_l1_dcache
+
+ /*
+ * Flush all data from the L1 data cache before disabling
+ * SCTLR.C bit.
+ */
+ push {r0-r12, lr}
+ ldr r0, =v7_flush_dcache_all
+ mov lr, pc
+ mov pc, r0
+ pop {r0-r12, lr}
+
+ /*
+ * Clear the SCTLR.C bit to prevent further data cache
+ * allocation. Clearing SCTLR.C would make all the data accesses
+ * strongly ordered and would not hit the cache.
+ */
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, r0, #(1 << 2) @ Disable the C bit
+ mcr p15, 0, r0, c1, c0, 0
+ isb
+
+ /*
+ * Invalidate L1 data cache. Even though only invalidate is
+ * necessary exported flush API is used here. Doing clean
+ * on already clean cache would be almost NOP.
+ */
+ push {r0-r12, lr}
+ ldr r0, =v7_flush_dcache_all
+ mov lr, pc
+ mov pc, r0
+ pop {r0-r12, lr}
+
+ /*
+ * Execute an ISB instruction to ensure that all of the
+ * CP15 register changes have been committed.
+ */
+ isb
+
+ /*
+ * Execute a barrier instruction to ensure that all cache,
+ * TLB and branch predictor maintenance operations issued
+ * by any CPU in the cluster have completed.
+ */
+ dsb
+ dmb
+
+ .endm
+
+ENTRY(mvf_suspend)
+ stmfd sp!, {r0-r12} @ Save registers
+/*************************************************************
+suspend mode entry
+*************************************************************/
+ mov r11, r0
+
+ cmp r0, #0x1
+ bne dormant
+
+ /* Need to flush and disable L1 dcache*/
+ flush_disable_l1_dcache
+
+ wfi
+
+ nop
+ nop
+ nop
+ nop
+
+ /* Invalidate L1 I-cache first */
+ mov r1, #0x0
+ mcr p15, 0, r1, c7, c5, 0 @ Invalidate I-Cache
+
+ /* Need to invalidate L1 dcache, as the power is dropped */
+ invalidate_l1_dcache
+
+ /* Enable L1 dcache first */
+ mrc p15, 0, r0, c1, c0, 0
+ orr r0, r0, #(1 << 2) @ Disable the C bit
+ mcr p15, 0, r0, c1, c0, 0
+
+/***********************************************************
+never run to here
+************************************************************/
+ b out /* exit standby */
+ /* Place the literal pool here so that literals are
+ within 16KB range */
+ .ltorg
+
+/************************************************************
+dormant entry, data save in stack
+************************************************************/
+dormant:
+
+/************************************************************
+saved register and context as below:
+ sp
+ spsr
+ lr
+ CPACR
+ TTBR0
+ TTBR1
+ TTBCR
+ DACR
+ PRRR
+ NMRR
+ ACTLR
+ Context ID
+ User r/w thread ID
+ Secure or NS VBAR
+ CPSR
+ SCTLR
+************************************************************/
+ /* stack is from the tail of iram_suspend base */
+ mov r0, r2 /* get suspend_iram_base */
+ add r0, r0, #IRAM_SUSPEND_SIZE
+
+ mov r4, r11 @ Store state entered
+ stmfd r0!, {r4}
+
+ mov r4, sp @ Store sp
+ mrs r5, spsr @ Store spsr
+ mov r6, lr @ Store lr
+ stmfd r0!, {r4-r6}
+
+ /* c1 and c2 registers */
+ mrc p15, 0, r4, c1, c0, 2 @ CPACR
+ mrc p15, 0, r5, c2, c0, 0 @ TTBR0
+ mrc p15, 0, r6, c2, c0, 1 @ TTBR1
+ mrc p15, 0, r7, c2, c0, 2 @ TTBCR
+ stmfd r0!, {r4-r7}
+
+ /* c3 and c10 registers */
+ mrc p15, 0, r4, c3, c0, 0 @ DACR
+ mrc p15, 0, r5, c10, c2, 0 @ PRRR
+ mrc p15, 0, r6, c10, c2, 1 @ NMRR
+ mrc p15, 0, r7, c1, c0, 1 @ ACTLR
+ stmfd r0!,{r4-r7}
+
+ /* c12, c13 and CPSR registers */
+ mrc p15, 0, r4, c13, c0, 1 @ Context ID
+ mrc p15, 0, r5, c13, c0, 2 @ User r/w thread ID
+ mrc p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR
+ mrs r7, cpsr @ Store CPSR
+ stmfd r0!, {r4-r7}
+
+ /* c1 control register */
+ mrc p15, 0, r4, c1, c0, 0 @ SCTLR
+ stmfd r0!, {r4}
+
+ /* Need to flush and disable L1 dcache*/
+ flush_disable_l1_dcache
+
+ /* Make sure TLBs are primed */
+ ldr r1, =MVF_IOMUXC_BASE_ADDR
+ add r1, r1, #PERIPBASE_VIRT_OFFSET
+ add r1, r1, #0x20000
+ ldr r0, [r1]
+ ldr r1, =MVF_SRC_BASE_ADDR
+ add r1, r1, #PERIPBASE_VIRT_OFFSET
+ add r1, r1, #0x20000
+ ldr r0, [r1]
+ ldr r1, =MVF_CCM_BASE_ADDR
+ add r1, r1, #PERIPBASE_VIRT_OFFSET
+ add r1, r1, #0x20000
+ ldr r0, [r1]
+ ldr r1, =MVF_GPC_BASE_ADDR
+ add r1, r1, #PERIPBASE_VIRT_OFFSET
+ add r1, r1, #0x20000
+ ldr r0, [r1]
+ ldr r1, =MVF_CCM_BASE_ADDR
+ add r1, r1, #PERIPBASE_VIRT_OFFSET
+ add r1, r1, #0x20000
+ ldr r0, [r1]
+
+ /* Do a DSB to drain the buffers */
+ dsb
+
+ mvf_stop_mode_enter
+
+/****************************************************************
+execute a wfi instruction to let SOC go into stop mode.
+****************************************************************/
+ wfi
+
+ nop
+ nop
+ nop
+ nop
+
+/****************************************************************
+if go here, means there is a wakeup irq pending, we should resume
+system immediately.
+****************************************************************/
+ mov r0, r2 /* get suspend_iram_base */
+ add r0, r0, #IRAM_SUSPEND_SIZE
+
+ ldmea r0!, {r11} @ standby or mem
+
+ /* mask all the GPC interrupts */
+ ldr r3, =MVF_GPC_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+ ldr r4, =0xffffffff
+ str r4, [r3, #0x44]
+ str r4, [r3, #0x48]
+ str r4, [r3, #0x4c]
+ str r4, [r3, #0x50]
+
+ /* pll2 enable */
+ ldr r3, =MVF_ANATOP_BASE_ADDR
+ add r3, r3, #PERIPBASE_VIRT_OFFSET
+ add r3, r3, #0x20000
+
+ ldr r4, [r3, #0x30]
+ orr r4, r4, #0x2000
+ str r4, [r3, #0x30]
+
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ mrc p15, 0, r1, c1, c0, 0
+ orr r1, r1, #(1 << 2) @ Enable the C bit
+ mcr p15, 0, r1, c1, c0, 0
+
+ b out
+
+/************************************************
+return back to mvf_suspend_enter for suspend
+*************************************************/
+out:
+ ldmfd sp!, {r0-r12}
+ mov pc, lr
+
+ .type mvf_do_suspend, #object
+ENTRY(mvf_do_suspend)
+ .word mvf_suspend
+ .size mvf_suspend, . - mvf_suspend