Commit | Line | Data |
---|---|---|
59b0f682 JL |
1 | /* |
2 | * Copyright (c) 2012, NVIDIA Corporation. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | */ | |
16 | ||
17 | #include <linux/linkage.h> | |
18 | ||
19 | #include <asm/assembler.h> | |
d457ef35 | 20 | #include <asm/asm-offsets.h> |
59b0f682 | 21 | |
59b0f682 JL |
22 | #include "sleep.h" |
23 | #include "flowctrl.h" | |
24 | ||
25 | #define TEGRA30_POWER_HOTPLUG_SHUTDOWN (1 << 27) /* Hotplug shutdown */ | |
26 | ||
27 | #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) | |
28 | /* | |
29 | * tegra30_hotplug_shutdown(void) | |
30 | * | |
31 | * Powergates the current CPU. | |
32 | * Should never return. | |
33 | */ | |
34 | ENTRY(tegra30_hotplug_shutdown) | |
59b0f682 JL |
35 | /* Powergate this CPU */ |
36 | mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN | |
37 | bl tegra30_cpu_shutdown | |
38 | mov pc, lr @ should never get here | |
39 | ENDPROC(tegra30_hotplug_shutdown) | |
40 | ||
41 | /* | |
42 | * tegra30_cpu_shutdown(unsigned long flags) | |
43 | * | |
44 | * Puts the current CPU in wait-for-event mode on the flow controller | |
45 | * and powergates it -- flags (in R0) indicate the request type. | |
46 | * Must never be called for CPU 0. | |
47 | * | |
48 | * corrupts r0-r4, r12 | |
49 | */ | |
50 | ENTRY(tegra30_cpu_shutdown) | |
51 | cpu_id r3 | |
52 | cmp r3, #0 | |
53 | moveq pc, lr @ Must never be called for CPU 0 | |
54 | ||
55 | ldr r12, =TEGRA_FLOW_CTRL_VIRT | |
56 | cpu_to_csr_reg r1, r3 | |
57 | add r1, r1, r12 @ virtual CSR address for this CPU | |
58 | cpu_to_halt_reg r2, r3 | |
59 | add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU | |
60 | ||
61 | /* | |
62 | * Clear this CPU's "event" and "interrupt" flags and power gate | |
63 | * it when halting but not before it is in the "WFE" state. | |
64 | */ | |
65 | movw r12, \ | |
66 | FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \ | |
67 | FLOW_CTRL_CSR_ENABLE | |
68 | mov r4, #(1 << 4) | |
5777b4b5 JL |
69 | ARM( orr r12, r12, r4, lsl r3 ) |
70 | THUMB( lsl r4, r4, r3 ) | |
71 | THUMB( orr r12, r12, r4 ) | |
59b0f682 JL |
72 | str r12, [r1] |
73 | ||
74 | /* Halt this CPU. */ | |
75 | mov r3, #0x400 | |
76 | delay_1: | |
77 | subs r3, r3, #1 @ delay as a part of wfe war. | |
78 | bge delay_1; | |
79 | cpsid a @ disable imprecise aborts. | |
80 | ldr r3, [r1] @ read CSR | |
81 | str r3, [r1] @ clear CSR | |
82 | tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN | |
d457ef35 | 83 | moveq r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT @ For LP2 |
59b0f682 JL |
84 | movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug |
85 | str r3, [r2] | |
86 | ldr r0, [r2] | |
87 | b wfe_war | |
88 | ||
89 | __cpu_reset_again: | |
90 | dsb | |
91 | .align 5 | |
92 | wfe @ CPU should be power gated here | |
93 | wfe_war: | |
94 | b __cpu_reset_again | |
95 | ||
96 | /* | |
97 | * 38 nop's, which fills reset of wfe cache line and | |
98 | * 4 more cachelines with nop | |
99 | */ | |
100 | .rept 38 | |
101 | nop | |
102 | .endr | |
103 | b . @ should never get here | |
104 | ||
105 | ENDPROC(tegra30_cpu_shutdown) | |
106 | #endif | |
d457ef35 JL |
107 | |
108 | #ifdef CONFIG_PM_SLEEP | |
109 | /* | |
110 | * tegra30_sleep_cpu_secondary_finish(unsigned long v2p) | |
111 | * | |
112 | * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU. | |
113 | */ | |
114 | ENTRY(tegra30_sleep_cpu_secondary_finish) | |
115 | mov r7, lr | |
116 | ||
117 | /* Flush and disable the L1 data cache */ | |
118 | bl tegra_disable_clean_inv_dcache | |
119 | ||
120 | /* Powergate this CPU. */ | |
121 | mov r0, #0 @ power mode flags (!hotplug) | |
122 | bl tegra30_cpu_shutdown | |
123 | mov r0, #1 @ never return here | |
124 | mov pc, r7 | |
125 | ENDPROC(tegra30_sleep_cpu_secondary_finish) | |
d552920a JL |
126 | |
127 | /* | |
128 | * tegra30_tear_down_cpu | |
129 | * | |
130 | * Switches the CPU to enter sleep. | |
131 | */ | |
132 | ENTRY(tegra30_tear_down_cpu) | |
133 | mov32 r6, TEGRA_FLOW_CTRL_BASE | |
134 | ||
135 | b tegra30_enter_sleep | |
136 | ENDPROC(tegra30_tear_down_cpu) | |
137 | ||
138 | /* | |
139 | * tegra30_enter_sleep | |
140 | * | |
141 | * uses flow controller to enter sleep state | |
142 | * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1 | |
143 | * executes from SDRAM with target state is LP2 | |
144 | * r6 = TEGRA_FLOW_CTRL_BASE | |
145 | */ | |
146 | tegra30_enter_sleep: | |
147 | cpu_id r1 | |
148 | ||
149 | cpu_to_csr_reg r2, r1 | |
150 | ldr r0, [r6, r2] | |
151 | orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | |
152 | orr r0, r0, #FLOW_CTRL_CSR_ENABLE | |
153 | str r0, [r6, r2] | |
154 | ||
155 | mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT | |
156 | orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ | |
157 | cpu_to_halt_reg r2, r1 | |
158 | str r0, [r6, r2] | |
159 | dsb | |
160 | ldr r0, [r6, r2] /* memory barrier */ | |
161 | ||
162 | halted: | |
163 | isb | |
164 | dsb | |
165 | wfi /* CPU should be power gated here */ | |
166 | ||
167 | /* !!!FIXME!!! Implement halt failure handler */ | |
168 | b halted | |
169 | ||
d457ef35 | 170 | #endif |