1 /*
2 * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9
10 #include <platform_def.h>
11
12 #include <arch_helpers.h>
13 #include <common/debug.h>
14 #include <drivers/delay_timer.h>
15 #include <drivers/generic_delay_timer.h>
16 #include <lib/cassert.h>
17 #include <lib/psci/psci.h>
18
19 #include <sq_common.h>
20 #include "sq_scpi.h"
21
22 uintptr_t sq_sec_entrypoint;
23
sq_pwr_domain_on(u_register_t mpidr)24 int sq_pwr_domain_on(u_register_t mpidr)
25 {
26 #if SQ_USE_SCMI_DRIVER
27 sq_scmi_on(mpidr);
28 #else
29 /*
30 * SCP takes care of powering up parent power domains so we
31 * only need to care about level 0
32 */
33 scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
34 scpi_power_on);
35 #endif
36
37 return PSCI_E_SUCCESS;
38 }
39
sq_pwr_domain_on_finisher_common(const psci_power_state_t * target_state)40 static void sq_pwr_domain_on_finisher_common(
41 const psci_power_state_t *target_state)
42 {
43 assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
44
45 /*
46 * Perform the common cluster specific operations i.e enable coherency
47 * if this cluster was off.
48 */
49 if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
50 plat_sq_interconnect_enter_coherency();
51 }
52
sq_pwr_domain_on_finish(const psci_power_state_t * target_state)53 void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
54 {
55 /* Assert that the system power domain need not be initialized */
56 assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
57
58 sq_pwr_domain_on_finisher_common(target_state);
59
60 /* Program the gic per-cpu distributor or re-distributor interface */
61 sq_gic_pcpu_init();
62
63 /* Enable the gic cpu interface */
64 sq_gic_cpuif_enable();
65 }
66
67 #if !SQ_USE_SCMI_DRIVER
sq_power_down_common(const psci_power_state_t * target_state)68 static void sq_power_down_common(const psci_power_state_t *target_state)
69 {
70 uint32_t cluster_state = scpi_power_on;
71 uint32_t system_state = scpi_power_on;
72
73 /* Prevent interrupts from spuriously waking up this cpu */
74 sq_gic_cpuif_disable();
75
76 /* Check if power down at system power domain level is requested */
77 if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
78 system_state = scpi_power_retention;
79
80 /* Cluster is to be turned off, so disable coherency */
81 if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
82 plat_sq_interconnect_exit_coherency();
83 cluster_state = scpi_power_off;
84 }
85
86 /*
87 * Ask the SCP to power down the appropriate components depending upon
88 * their state.
89 */
90 scpi_set_sq_power_state(read_mpidr_el1(),
91 scpi_power_off,
92 cluster_state,
93 system_state);
94 }
95 #endif
96
sq_pwr_domain_off(const psci_power_state_t * target_state)97 void sq_pwr_domain_off(const psci_power_state_t *target_state)
98 {
99 #if SQ_USE_SCMI_DRIVER
100 sq_scmi_off(target_state);
101 #else
102 sq_power_down_common(target_state);
103 #endif
104 }
105
sq_system_off(void)106 void __dead2 sq_system_off(void)
107 {
108 volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
109
110 /* set PD[9] high to power off the system */
111 gpio[5] |= 0x2; /* set output */
112 gpio[1] |= 0x2; /* set high */
113 dmbst();
114
115 generic_delay_timer_init();
116
117 mdelay(1);
118
119 while (1) {
120 gpio[1] &= ~0x2; /* set low */
121 dmbst();
122
123 mdelay(1);
124
125 gpio[1] |= 0x2; /* set high */
126 dmbst();
127
128 mdelay(100);
129 }
130
131 wfi();
132 ERROR("SQ System Off: operation not handled.\n");
133 panic();
134 }
135
sq_system_reset(void)136 void __dead2 sq_system_reset(void)
137 {
138 #if SQ_USE_SCMI_DRIVER
139 sq_scmi_sys_reboot();
140 #else
141 uint32_t response;
142
143 /* Send the system reset request to the SCP */
144 response = scpi_sys_power_state(scpi_system_reboot);
145
146 if (response != SCP_OK) {
147 ERROR("SQ System Reset: SCP error %u.\n", response);
148 panic();
149 }
150 wfi();
151 ERROR("SQ System Reset: operation not handled.\n");
152 panic();
153 #endif
154 }
155
sq_cpu_standby(plat_local_state_t cpu_state)156 void sq_cpu_standby(plat_local_state_t cpu_state)
157 {
158 u_register_t scr;
159
160 assert(cpu_state == SQ_LOCAL_STATE_RET);
161
162 scr = read_scr_el3();
163 /* Enable PhysicalIRQ bit for NS world to wake the CPU */
164 write_scr_el3(scr | SCR_IRQ_BIT);
165 isb();
166 dsb();
167 wfi();
168
169 /*
170 * Restore SCR to the original value, synchronisation of scr_el3 is
171 * done by eret while el3_exit to save some execution cycles.
172 */
173 write_scr_el3(scr);
174 }
175
176 const plat_psci_ops_t sq_psci_ops = {
177 .pwr_domain_on = sq_pwr_domain_on,
178 .pwr_domain_off = sq_pwr_domain_off,
179 .pwr_domain_on_finish = sq_pwr_domain_on_finish,
180 .cpu_standby = sq_cpu_standby,
181 .system_off = sq_system_off,
182 .system_reset = sq_system_reset,
183 };
184
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)185 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
186 const struct plat_psci_ops **psci_ops)
187 {
188 sq_sec_entrypoint = sec_entrypoint;
189 flush_dcache_range((uint64_t)&sq_sec_entrypoint,
190 sizeof(sq_sec_entrypoint));
191
192 *psci_ops = &sq_psci_ops;
193
194 return 0;
195 }
196