blob: 7cc4b61dd31b59b3cbaec5b020024f2cf5c659d0 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/*
2 * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved.
3 * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * Neither the name of ARM nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific
17 * prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <assert.h>
33#include <arch_helpers.h>
34#include <arm_gic.h>
35#include <debug.h>
36#include <cci400.h>
37#include <errno.h>
38#include <gic_v2.h>
39#include <gpio.h>
40#include <hi6220.h>
41#include <hisi_ipc.h>
42#include <hisi_pwrc.h>
43#include <mmio.h>
44#include <platform.h>
45#include <platform_def.h>
46#include <psci.h>
47#include <sp804_timer.h>
48
49#include "hikey_def.h"
50#include "hikey_private.h"
51
52#define PLAT_SOC_SUSPEND_STATE 0x4
53
54static int32_t hikey_do_plat_actions(uint32_t afflvl, uint32_t state)
55{
56 assert(afflvl <= MPIDR_AFFLVL1);
57
58 if (state != PSCI_STATE_OFF)
59 return -EAGAIN;
60
61 return 0;
62}
63
64int32_t hikey_affinst_on(uint64_t mpidr,
65 uint64_t sec_entrypoint,
66 uint32_t afflvl,
67 uint32_t state)
68{
69 int cpu, cluster;
70
71 cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFF1_SHIFT;
72 cpu = mpidr & MPIDR_CPU_MASK;
73
74 VERBOSE("#%s, mpidr:%llx, afflvl:%x, state:%x\n", __func__, mpidr, afflvl, state);
75
76 /* directly return for power on */
77 if (state == PSCI_STATE_ON)
78 return PSCI_E_SUCCESS;
79
80 switch (afflvl) {
81 case MPIDR_AFFLVL0:
82 hisi_pwrc_set_core_bx_addr(cpu, cluster, sec_entrypoint);
83 hisi_ipc_cpu_on(cpu, cluster);
84 break;
85
86 case MPIDR_AFFLVL1:
87 hisi_ipc_cluster_on(cpu, cluster);
88 break;
89 }
90
91 return PSCI_E_SUCCESS;
92}
93
94
95static void hikey_affinst_off(uint32_t afflvl, uint32_t state)
96{
97 unsigned int mpidr = read_mpidr_el1();
98 int cpu, cluster;
99
100 cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFF1_SHIFT;
101 cpu = mpidr & MPIDR_CPU_MASK;
102
103 if (hikey_do_plat_actions(afflvl, state) == -EAGAIN)
104 return;
105
106 switch (afflvl) {
107 case MPIDR_AFFLVL1:
108 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
109 cci_disable_cluster_coherency(mpidr);
110 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
111
112 hisi_ipc_cluster_off(cpu, cluster);
113 break;
114
115 case MPIDR_AFFLVL0:
116 arm_gic_cpuif_deactivate();
117 hisi_ipc_cpu_off(cpu, cluster);
118 break;
119 }
120
121 return;
122}
123
124static void hikey_affinst_suspend(uint64_t sec_entrypoint,
125 uint32_t afflvl,
126 uint32_t state)
127{
128 unsigned int mpidr = read_mpidr_el1();
129 int cpu, cluster;
130
131 cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFF1_SHIFT;
132 cpu = mpidr & MPIDR_CPU_MASK;
133
134 if (hikey_do_plat_actions(afflvl, state) == -EAGAIN)
135 return;
136
137 switch (afflvl) {
138 case MPIDR_AFFLVL1:
139
140 hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
141 cci_disable_cluster_coherency(mpidr);
142 hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
143
144 if (psci_get_suspend_stateid() == PLAT_SOC_SUSPEND_STATE) {
145 hisi_pwrc_set_cluster_wfi(1);
146 hisi_pwrc_set_cluster_wfi(0);
147 hisi_ipc_psci_system_off();
148 } else
149 hisi_ipc_cluster_suspend(cpu, cluster);
150
151 break;
152
153 case MPIDR_AFFLVL0:
154
155 /* Program the jump address for the target cpu */
156 hisi_pwrc_set_core_bx_addr(cpu, cluster, sec_entrypoint);
157
158 arm_gic_cpuif_deactivate();
159
160 if (psci_get_suspend_stateid() != PLAT_SOC_SUSPEND_STATE)
161 hisi_ipc_cpu_suspend(cpu, cluster);
162 break;
163 }
164
165 return;
166}
167
168void hikey_affinst_on_finish(uint32_t afflvl, uint32_t state)
169{
170 unsigned long mpidr;
171 int cpu, cluster;
172
173 if (hikey_do_plat_actions(afflvl, state) == -EAGAIN)
174 return;
175
176 /* Get the mpidr for this cpu */
177 mpidr = read_mpidr_el1();
178 cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFF1_SHIFT;
179 cpu = mpidr & MPIDR_CPU_MASK;
180
181 /* Perform the common cluster specific operations */
182 if (afflvl != MPIDR_AFFLVL0)
183 cci_enable_cluster_coherency(mpidr);
184
185 /* Zero the jump address in the mailbox for this cpu */
186 hisi_pwrc_set_core_bx_addr(cpu, cluster, 0);
187
188 if (psci_get_suspend_stateid() == PLAT_SOC_SUSPEND_STATE) {
189 arm_gic_setup();
190 } else {
191 /* Enable the gic cpu interface */
192 arm_gic_cpuif_setup();
193
194 /* TODO: This setup is needed only after a cold boot */
195 arm_gic_pcpu_distif_setup();
196 }
197
198 return;
199}
200
201static void hikey_affinst_suspend_finish(uint32_t afflvl,
202 uint32_t state)
203{
204 hikey_affinst_on_finish(afflvl, state);
205 return;
206}
207
208static void __dead2 hikey_system_off(void)
209{
210 gpio_set_value(0, 0);
211 mdelay(1000);
212 /* Send the system reset request since it fails to power off */
213 mmio_write_32(AO_SC_SYS_STAT0, 0x48698284);
214 wfi();
215 panic();
216}
217
218static void __dead2 hikey_system_reset(void)
219{
220 VERBOSE("%s: reset system\n", __func__);
221
222 /* Send the system reset request */
223 mmio_write_32(AO_SC_SYS_STAT0, 0x48698284);
224
225 wfi();
226 panic();
227}
228
229unsigned int hikey_get_sys_suspend_power_state(void)
230{
231 unsigned int power_state;
232
233 power_state = psci_make_powerstate(PLAT_SOC_SUSPEND_STATE,
234 PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL1);
235
236 return power_state;
237}
238
239static const plat_pm_ops_t hikey_plat_pm_ops = {
240 .affinst_on = hikey_affinst_on,
241 .affinst_on_finish = hikey_affinst_on_finish,
242 .affinst_off = hikey_affinst_off,
243 .affinst_standby = NULL,
244 .affinst_suspend = hikey_affinst_suspend,
245 .affinst_suspend_finish = hikey_affinst_suspend_finish,
246 .system_off = hikey_system_off,
247 .system_reset = hikey_system_reset,
248 .get_sys_suspend_power_state = hikey_get_sys_suspend_power_state,
249};
250
251int platform_setup_pm(const plat_pm_ops_t **plat_ops)
252{
253 *plat_ops = &hikey_plat_pm_ops;
254 return 0;
255}