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) | |
35 | /* Turn off SMP coherency */ | |
36 | exit_smp r4, r5 | |
37 | ||
38 | /* Powergate this CPU */ | |
39 | mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN | |
40 | bl tegra30_cpu_shutdown | |
41 | mov pc, lr @ should never get here | |
42 | ENDPROC(tegra30_hotplug_shutdown) | |
43 | ||
44 | /* | |
45 | * tegra30_cpu_shutdown(unsigned long flags) | |
46 | * | |
47 | * Puts the current CPU in wait-for-event mode on the flow controller | |
48 | * and powergates it -- flags (in R0) indicate the request type. | |
49 | * Must never be called for CPU 0. | |
50 | * | |
51 | * corrupts r0-r4, r12 | |
52 | */ | |
53 | ENTRY(tegra30_cpu_shutdown) | |
54 | cpu_id r3 | |
55 | cmp r3, #0 | |
56 | moveq pc, lr @ Must never be called for CPU 0 | |
57 | ||
58 | ldr r12, =TEGRA_FLOW_CTRL_VIRT | |
59 | cpu_to_csr_reg r1, r3 | |
60 | add r1, r1, r12 @ virtual CSR address for this CPU | |
61 | cpu_to_halt_reg r2, r3 | |
62 | add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU | |
63 | ||
64 | /* | |
65 | * Clear this CPU's "event" and "interrupt" flags and power gate | |
66 | * it when halting but not before it is in the "WFE" state. | |
67 | */ | |
68 | movw r12, \ | |
69 | FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \ | |
70 | FLOW_CTRL_CSR_ENABLE | |
71 | mov r4, #(1 << 4) | |
72 | orr r12, r12, r4, lsl r3 | |
73 | str r12, [r1] | |
74 | ||
75 | /* Halt this CPU. */ | |
76 | mov r3, #0x400 | |
77 | delay_1: | |
78 | subs r3, r3, #1 @ delay as a part of wfe war. | |
79 | bge delay_1; | |
80 | cpsid a @ disable imprecise aborts. | |
81 | ldr r3, [r1] @ read CSR | |
82 | str r3, [r1] @ clear CSR | |
83 | tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN | |
d457ef35 | 84 | moveq r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT @ For LP2 |
59b0f682 JL |
85 | movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug |
86 | str r3, [r2] | |
87 | ldr r0, [r2] | |
88 | b wfe_war | |
89 | ||
90 | __cpu_reset_again: | |
91 | dsb | |
92 | .align 5 | |
93 | wfe @ CPU should be power gated here | |
94 | wfe_war: | |
95 | b __cpu_reset_again | |
96 | ||
97 | /* | |
98 | * 38 nop's, which fills reset of wfe cache line and | |
99 | * 4 more cachelines with nop | |
100 | */ | |
101 | .rept 38 | |
102 | nop | |
103 | .endr | |
104 | b . @ should never get here | |
105 | ||
106 | ENDPROC(tegra30_cpu_shutdown) | |
107 | #endif | |
d457ef35 JL |
108 | |
109 | #ifdef CONFIG_PM_SLEEP | |
110 | /* | |
111 | * tegra30_sleep_cpu_secondary_finish(unsigned long v2p) | |
112 | * | |
113 | * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU. | |
114 | */ | |
115 | ENTRY(tegra30_sleep_cpu_secondary_finish) | |
116 | mov r7, lr | |
117 | ||
118 | /* Flush and disable the L1 data cache */ | |
119 | bl tegra_disable_clean_inv_dcache | |
120 | ||
121 | /* Powergate this CPU. */ | |
122 | mov r0, #0 @ power mode flags (!hotplug) | |
123 | bl tegra30_cpu_shutdown | |
124 | mov r0, #1 @ never return here | |
125 | mov pc, r7 | |
126 | ENDPROC(tegra30_sleep_cpu_secondary_finish) | |
d552920a JL |
127 | |
128 | /* | |
129 | * tegra30_tear_down_cpu | |
130 | * | |
131 | * Switches the CPU to enter sleep. | |
132 | */ | |
133 | ENTRY(tegra30_tear_down_cpu) | |
134 | mov32 r6, TEGRA_FLOW_CTRL_BASE | |
135 | ||
136 | b tegra30_enter_sleep | |
137 | ENDPROC(tegra30_tear_down_cpu) | |
138 | ||
139 | /* | |
140 | * tegra30_enter_sleep | |
141 | * | |
142 | * uses flow controller to enter sleep state | |
143 | * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1 | |
144 | * executes from SDRAM with target state is LP2 | |
145 | * r6 = TEGRA_FLOW_CTRL_BASE | |
146 | */ | |
147 | tegra30_enter_sleep: | |
148 | cpu_id r1 | |
149 | ||
150 | cpu_to_csr_reg r2, r1 | |
151 | ldr r0, [r6, r2] | |
152 | orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | |
153 | orr r0, r0, #FLOW_CTRL_CSR_ENABLE | |
154 | str r0, [r6, r2] | |
155 | ||
156 | mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT | |
157 | orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ | |
158 | cpu_to_halt_reg r2, r1 | |
159 | str r0, [r6, r2] | |
160 | dsb | |
161 | ldr r0, [r6, r2] /* memory barrier */ | |
162 | ||
163 | halted: | |
164 | isb | |
165 | dsb | |
166 | wfi /* CPU should be power gated here */ | |
167 | ||
168 | /* !!!FIXME!!! Implement halt failure handler */ | |
169 | b halted | |
170 | ||
d457ef35 | 171 | #endif |