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