1 /*
2  * Copyright (c) 2018-2022, 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 	/* Prevent interrupts from spuriously waking up this cpu */
101 	sq_gic_cpuif_disable();
102 
103 	/* Cluster is to be turned off, so disable coherency */
104 	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
105 		plat_sq_interconnect_exit_coherency();
106 	}
107 
108 	sq_scmi_off(target_state);
109 #else
110 	sq_power_down_common(target_state);
111 #endif
112 }
113 
sq_system_off(void)114 void __dead2 sq_system_off(void)
115 {
116 #if SQ_USE_SCMI_DRIVER
117 	sq_scmi_sys_shutdown();
118 #else
119 	volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
120 
121 	/* set PD[9] high to power off the system */
122 	gpio[5] |= 0x2;		/* set output */
123 	gpio[1] |= 0x2;		/* set high */
124 	dmbst();
125 
126 	generic_delay_timer_init();
127 
128 	mdelay(1);
129 
130 	while (1) {
131 		gpio[1] &= ~0x2;	/* set low */
132 		dmbst();
133 
134 		mdelay(1);
135 
136 		gpio[1] |= 0x2;		/* set high */
137 		dmbst();
138 
139 		mdelay(100);
140 	}
141 
142 	wfi();
143 	ERROR("SQ System Off: operation not handled.\n");
144 	panic();
145 #endif
146 }
147 
sq_system_reset(void)148 void __dead2 sq_system_reset(void)
149 {
150 #if SQ_USE_SCMI_DRIVER
151 	sq_scmi_sys_reboot();
152 #else
153 	uint32_t response;
154 
155 	/* Send the system reset request to the SCP */
156 	response = scpi_sys_power_state(scpi_system_reboot);
157 
158 	if (response != SCP_OK) {
159 		ERROR("SQ System Reset: SCP error %u.\n", response);
160 		panic();
161 	}
162 	wfi();
163 	ERROR("SQ System Reset: operation not handled.\n");
164 	panic();
165 #endif
166 }
167 
sq_cpu_standby(plat_local_state_t cpu_state)168 void sq_cpu_standby(plat_local_state_t cpu_state)
169 {
170 	u_register_t scr;
171 
172 	assert(cpu_state == SQ_LOCAL_STATE_RET);
173 
174 	scr = read_scr_el3();
175 	/* Enable PhysicalIRQ bit for NS world to wake the CPU */
176 	write_scr_el3(scr | SCR_IRQ_BIT);
177 	isb();
178 	dsb();
179 	wfi();
180 
181 	/*
182 	 * Restore SCR to the original value, synchronisation of scr_el3 is
183 	 * done by eret while el3_exit to save some execution cycles.
184 	 */
185 	write_scr_el3(scr);
186 }
187 
188 const plat_psci_ops_t sq_psci_ops = {
189 	.pwr_domain_on		= sq_pwr_domain_on,
190 	.pwr_domain_off		= sq_pwr_domain_off,
191 	.pwr_domain_on_finish	= sq_pwr_domain_on_finish,
192 	.cpu_standby		= sq_cpu_standby,
193 	.system_off		= sq_system_off,
194 	.system_reset		= sq_system_reset,
195 };
196 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)197 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
198 			const struct plat_psci_ops **psci_ops)
199 {
200 #if !RESET_TO_BL31
201 	uintptr_t *sq_sec_ep = (uintptr_t *)BL2_MAILBOX_BASE;
202 
203 	*sq_sec_ep = sec_entrypoint;
204 	flush_dcache_range((uint64_t)sq_sec_ep,
205 			   sizeof(*sq_sec_ep));
206 #else
207 	sq_sec_entrypoint = sec_entrypoint;
208 	flush_dcache_range((uint64_t)&sq_sec_entrypoint,
209 			   sizeof(sq_sec_entrypoint));
210 #endif
211 
212 	*psci_ops = &sq_psci_ops;
213 
214 	return 0;
215 }
216