aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-03-04 05:25:45 -0500
committerPaul Burton <paul.burton@imgtec.com>2014-05-02 11:39:10 -0400
commit74e91335190c628b870c69cff8360d23707b1f53 (patch)
tree255cb7709b6123938c057f206522f00e2b450d9f /arch/mips
parenteaa38d6343adbb5070c27af29aeeb3df126f47f2 (diff)
MIPS: PM: Implement PM helper macros
Implement assembler helper macros in asm/pm.h for platform code to use for saving context across low power states - for example suspend to RAM or powered down cpuidle states. Macros are provided for saving and restoring the main CPU context used by C code and doing important configuration which must be done very early during resume. Notably EVA needs segmentation control registers to be restored before the stack or dynamically allocated memory is accessed, so that state is saved in global data. Signed-off-by: James Hogan <james.hogan@imgtec.com> Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/include/asm/pm.h167
-rw-r--r--arch/mips/kernel/asm-offsets.c15
-rw-r--r--arch/mips/kernel/pm.c4
3 files changed, 186 insertions, 0 deletions
diff --git a/arch/mips/include/asm/pm.h b/arch/mips/include/asm/pm.h
new file mode 100644
index 000000000000..268546f7f189
--- /dev/null
+++ b/arch/mips/include/asm/pm.h
@@ -0,0 +1,167 @@
1/*
2 * Copyright (C) 2014 Imagination Technologies Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * PM helper macros for CPU power off (e.g. Suspend-to-RAM).
10 */
11
12#ifndef __ASM_PM_H
13#define __ASM_PM_H
14
15#ifdef __ASSEMBLY__
16
17#include <asm/asm-offsets.h>
18#include <asm/asm.h>
19#include <asm/mipsregs.h>
20#include <asm/regdef.h>
21
22/* Save CPU state to stack for suspend to RAM */
23.macro SUSPEND_SAVE_REGS
24 subu sp, PT_SIZE
25 /* Call preserved GPRs */
26 LONG_S $16, PT_R16(sp)
27 LONG_S $17, PT_R17(sp)
28 LONG_S $18, PT_R18(sp)
29 LONG_S $19, PT_R19(sp)
30 LONG_S $20, PT_R20(sp)
31 LONG_S $21, PT_R21(sp)
32 LONG_S $22, PT_R22(sp)
33 LONG_S $23, PT_R23(sp)
34 LONG_S $28, PT_R28(sp)
35 LONG_S $30, PT_R30(sp)
36 LONG_S $31, PT_R31(sp)
37 /* A couple of CP0 registers with space in pt_regs */
38 mfc0 k0, CP0_STATUS
39 LONG_S k0, PT_STATUS(sp)
40#ifdef CONFIG_MIPS_MT_SMTC
41 mfc0 k0, CP0_TCSTATUS
42 LONG_S k0, PT_TCSTATUS(sp)
43#endif
44.endm
45
46/* Restore CPU state from stack after resume from RAM */
47.macro RESUME_RESTORE_REGS_RETURN
48 .set push
49 .set noreorder
50 /* A couple of CP0 registers with space in pt_regs */
51 LONG_L k0, PT_STATUS(sp)
52 mtc0 k0, CP0_STATUS
53#ifdef CONFIG_MIPS_MT_SMTC
54 LONG_L k0, PT_TCSTATUS(sp)
55 mtc0 k0, CP0_TCSTATUS
56#endif
57 /* Call preserved GPRs */
58 LONG_L $16, PT_R16(sp)
59 LONG_L $17, PT_R17(sp)
60 LONG_L $18, PT_R18(sp)
61 LONG_L $19, PT_R19(sp)
62 LONG_L $20, PT_R20(sp)
63 LONG_L $21, PT_R21(sp)
64 LONG_L $22, PT_R22(sp)
65 LONG_L $23, PT_R23(sp)
66 LONG_L $28, PT_R28(sp)
67 LONG_L $30, PT_R30(sp)
68 LONG_L $31, PT_R31(sp)
69 /* Pop and return */
70 jr ra
71 addiu sp, PT_SIZE
72 .set pop
73.endm
74
75/* Get address of static suspend state into t1 */
76.macro LA_STATIC_SUSPEND
77 la t1, mips_static_suspend_state
78.endm
79
80/* Save important CPU state for early restoration to global data */
81.macro SUSPEND_SAVE_STATIC
82#ifdef CONFIG_EVA
83 /*
84 * Segment configuration is saved in global data where it can be easily
85 * reloaded without depending on the segment configuration.
86 */
87 mfc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */
88 LONG_S k0, SSS_SEGCTL0(t1)
89 mfc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */
90 LONG_S k0, SSS_SEGCTL1(t1)
91 mfc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */
92 LONG_S k0, SSS_SEGCTL2(t1)
93#endif
94 /* save stack pointer (pointing to GPRs) */
95 LONG_S sp, SSS_SP(t1)
96.endm
97
98/* Restore important CPU state early from global data */
99.macro RESUME_RESTORE_STATIC
100#ifdef CONFIG_EVA
101 /*
102 * Segment configuration must be restored prior to any access to
103 * allocated memory, as it may reside outside of the legacy kernel
104 * segments.
105 */
106 LONG_L k0, SSS_SEGCTL0(t1)
107 mtc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */
108 LONG_L k0, SSS_SEGCTL1(t1)
109 mtc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */
110 LONG_L k0, SSS_SEGCTL2(t1)
111 mtc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */
112 tlbw_use_hazard
113#endif
114 /* restore stack pointer (pointing to GPRs) */
115 LONG_L sp, SSS_SP(t1)
116.endm
117
118/* flush caches to make sure context has reached memory */
119.macro SUSPEND_CACHE_FLUSH
120 .extern __wback_cache_all
121 .set push
122 .set noreorder
123 la t1, __wback_cache_all
124 LONG_L t0, 0(t1)
125 jalr t0
126 nop
127 .set pop
128 .endm
129
130/* Save suspend state and flush data caches to RAM */
131.macro SUSPEND_SAVE
132 SUSPEND_SAVE_REGS
133 LA_STATIC_SUSPEND
134 SUSPEND_SAVE_STATIC
135 SUSPEND_CACHE_FLUSH
136.endm
137
138/* Restore saved state after resume from RAM and return */
139.macro RESUME_RESTORE_RETURN
140 LA_STATIC_SUSPEND
141 RESUME_RESTORE_STATIC
142 RESUME_RESTORE_REGS_RETURN
143.endm
144
145#else /* __ASSEMBLY__ */
146
147/**
148 * struct mips_static_suspend_state - Core saved CPU state across S2R.
149 * @segctl: CP0 Segment control registers.
150 * @sp: Stack frame where GP register context is saved.
151 *
152 * This structure contains minimal CPU state that must be saved in static kernel
153 * data in order to be able to restore the rest of the state. This includes
154 * segmentation configuration in the case of EVA being enabled, as they must be
155 * restored prior to any kmalloc'd memory being referenced (even the stack
156 * pointer).
157 */
158struct mips_static_suspend_state {
159#ifdef CONFIG_EVA
160 unsigned long segctl[3];
161#endif
162 unsigned long sp;
163};
164
165#endif /* !__ASSEMBLY__ */
166
167#endif /* __ASM_PM_HELPERS_H */
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 0ea75c244b48..e085cde13dba 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -14,6 +14,7 @@
14#include <linux/mm.h> 14#include <linux/mm.h>
15#include <linux/kbuild.h> 15#include <linux/kbuild.h>
16#include <linux/suspend.h> 16#include <linux/suspend.h>
17#include <asm/pm.h>
17#include <asm/ptrace.h> 18#include <asm/ptrace.h>
18#include <asm/processor.h> 19#include <asm/processor.h>
19#include <asm/smp-cps.h> 20#include <asm/smp-cps.h>
@@ -404,6 +405,20 @@ void output_pbe_defines(void)
404} 405}
405#endif 406#endif
406 407
408#ifdef CONFIG_CPU_PM
409void output_pm_defines(void)
410{
411 COMMENT(" PM offsets. ");
412#ifdef CONFIG_EVA
413 OFFSET(SSS_SEGCTL0, mips_static_suspend_state, segctl[0]);
414 OFFSET(SSS_SEGCTL1, mips_static_suspend_state, segctl[1]);
415 OFFSET(SSS_SEGCTL2, mips_static_suspend_state, segctl[2]);
416#endif
417 OFFSET(SSS_SP, mips_static_suspend_state, sp);
418 BLANK();
419}
420#endif
421
407void output_kvm_defines(void) 422void output_kvm_defines(void)
408{ 423{
409 COMMENT(" KVM/MIPS Specfic offsets. "); 424 COMMENT(" KVM/MIPS Specfic offsets. ");
diff --git a/arch/mips/kernel/pm.c b/arch/mips/kernel/pm.c
index 112903f36b89..fefdf39d3df3 100644
--- a/arch/mips/kernel/pm.c
+++ b/arch/mips/kernel/pm.c
@@ -15,8 +15,12 @@
15#include <asm/dsp.h> 15#include <asm/dsp.h>
16#include <asm/fpu.h> 16#include <asm/fpu.h>
17#include <asm/mmu_context.h> 17#include <asm/mmu_context.h>
18#include <asm/pm.h>
18#include <asm/watch.h> 19#include <asm/watch.h>
19 20
21/* Used by PM helper macros in asm/pm.h */
22struct mips_static_suspend_state mips_static_suspend_state;
23
20/** 24/**
21 * mips_cpu_save() - Save general CPU state. 25 * mips_cpu_save() - Save general CPU state.
22 * Ensures that general CPU context is saved, notably FPU and DSP. 26 * Ensures that general CPU context is saved, notably FPU and DSP.