xref: /rk3399_ARM-atf/plat/socionext/synquacer/sq_psci.c (revision 4bbdc3912bcc3f664e902ab3e2815b459615075f)
1753701ccSSumit Garg /*
2*48ab3904SJassi Brar  * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
3753701ccSSumit Garg  *
4753701ccSSumit Garg  * SPDX-License-Identifier: BSD-3-Clause
5753701ccSSumit Garg  */
6753701ccSSumit Garg 
7753701ccSSumit Garg #include <assert.h>
8753701ccSSumit Garg #include <errno.h>
909d40e0eSAntonio Nino Diaz 
10753701ccSSumit Garg #include <platform_def.h>
1109d40e0eSAntonio Nino Diaz 
1209d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1309d40e0eSAntonio Nino Diaz #include <common/debug.h>
1409d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
1509d40e0eSAntonio Nino Diaz #include <drivers/generic_delay_timer.h>
1609d40e0eSAntonio Nino Diaz #include <lib/cassert.h>
1709d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h>
1809d40e0eSAntonio Nino Diaz 
19753701ccSSumit Garg #include <sq_common.h>
20753701ccSSumit Garg #include "sq_scpi.h"
21753701ccSSumit Garg 
22753701ccSSumit Garg uintptr_t sq_sec_entrypoint;
23753701ccSSumit Garg 
sq_pwr_domain_on(u_register_t mpidr)24753701ccSSumit Garg int sq_pwr_domain_on(u_register_t mpidr)
25753701ccSSumit Garg {
26b67d2029SMasahisa Kojima #if SQ_USE_SCMI_DRIVER
27b67d2029SMasahisa Kojima 	sq_scmi_on(mpidr);
28b67d2029SMasahisa Kojima #else
29753701ccSSumit Garg 	/*
30753701ccSSumit Garg 	 * SCP takes care of powering up parent power domains so we
31753701ccSSumit Garg 	 * only need to care about level 0
32753701ccSSumit Garg 	 */
33753701ccSSumit Garg 	scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
34753701ccSSumit Garg 				 scpi_power_on);
35b67d2029SMasahisa Kojima #endif
36753701ccSSumit Garg 
37753701ccSSumit Garg 	return PSCI_E_SUCCESS;
38753701ccSSumit Garg }
39753701ccSSumit Garg 
sq_pwr_domain_on_finisher_common(const psci_power_state_t * target_state)40753701ccSSumit Garg static void sq_pwr_domain_on_finisher_common(
41753701ccSSumit Garg 		const psci_power_state_t *target_state)
42753701ccSSumit Garg {
43753701ccSSumit Garg 	assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
44753701ccSSumit Garg 
45753701ccSSumit Garg 	/*
46753701ccSSumit Garg 	 * Perform the common cluster specific operations i.e enable coherency
47753701ccSSumit Garg 	 * if this cluster was off.
48753701ccSSumit Garg 	 */
49753701ccSSumit Garg 	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
50753701ccSSumit Garg 		plat_sq_interconnect_enter_coherency();
51753701ccSSumit Garg }
52753701ccSSumit Garg 
sq_pwr_domain_on_finish(const psci_power_state_t * target_state)53753701ccSSumit Garg void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
54753701ccSSumit Garg {
55753701ccSSumit Garg 	/* Assert that the system power domain need not be initialized */
56753701ccSSumit Garg 	assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
57753701ccSSumit Garg 
58753701ccSSumit Garg 	sq_pwr_domain_on_finisher_common(target_state);
59753701ccSSumit Garg 
60753701ccSSumit Garg 	/* Program the gic per-cpu distributor or re-distributor interface */
61753701ccSSumit Garg 	sq_gic_pcpu_init();
62753701ccSSumit Garg 
63753701ccSSumit Garg 	/* Enable the gic cpu interface */
64753701ccSSumit Garg 	sq_gic_cpuif_enable();
65753701ccSSumit Garg }
66753701ccSSumit Garg 
67b67d2029SMasahisa Kojima #if !SQ_USE_SCMI_DRIVER
sq_power_down_common(const psci_power_state_t * target_state)68753701ccSSumit Garg static void sq_power_down_common(const psci_power_state_t *target_state)
69753701ccSSumit Garg {
70753701ccSSumit Garg 	uint32_t cluster_state = scpi_power_on;
71753701ccSSumit Garg 	uint32_t system_state = scpi_power_on;
72753701ccSSumit Garg 
73753701ccSSumit Garg 	/* Prevent interrupts from spuriously waking up this cpu */
74753701ccSSumit Garg 	sq_gic_cpuif_disable();
75753701ccSSumit Garg 
76753701ccSSumit Garg 	/* Check if power down at system power domain level is requested */
77753701ccSSumit Garg 	if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
78753701ccSSumit Garg 		system_state = scpi_power_retention;
79753701ccSSumit Garg 
80753701ccSSumit Garg 	/* Cluster is to be turned off, so disable coherency */
81753701ccSSumit Garg 	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
82753701ccSSumit Garg 		plat_sq_interconnect_exit_coherency();
83753701ccSSumit Garg 		cluster_state = scpi_power_off;
84753701ccSSumit Garg 	}
85753701ccSSumit Garg 
86753701ccSSumit Garg 	/*
87753701ccSSumit Garg 	 * Ask the SCP to power down the appropriate components depending upon
88753701ccSSumit Garg 	 * their state.
89753701ccSSumit Garg 	 */
90753701ccSSumit Garg 	scpi_set_sq_power_state(read_mpidr_el1(),
91753701ccSSumit Garg 				 scpi_power_off,
92753701ccSSumit Garg 				 cluster_state,
93753701ccSSumit Garg 				 system_state);
94753701ccSSumit Garg }
95b67d2029SMasahisa Kojima #endif
96753701ccSSumit Garg 
sq_pwr_domain_off(const psci_power_state_t * target_state)97753701ccSSumit Garg void sq_pwr_domain_off(const psci_power_state_t *target_state)
98753701ccSSumit Garg {
99b67d2029SMasahisa Kojima #if SQ_USE_SCMI_DRIVER
100f7f5d2c4SMasahisa Kojima 	/* Prevent interrupts from spuriously waking up this cpu */
101f7f5d2c4SMasahisa Kojima 	sq_gic_cpuif_disable();
102f7f5d2c4SMasahisa Kojima 
103f7f5d2c4SMasahisa Kojima 	/* Cluster is to be turned off, so disable coherency */
104f7f5d2c4SMasahisa Kojima 	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
105f7f5d2c4SMasahisa Kojima 		plat_sq_interconnect_exit_coherency();
106f7f5d2c4SMasahisa Kojima 	}
107f7f5d2c4SMasahisa Kojima 
108b67d2029SMasahisa Kojima 	sq_scmi_off(target_state);
109b67d2029SMasahisa Kojima #else
110753701ccSSumit Garg 	sq_power_down_common(target_state);
111b67d2029SMasahisa Kojima #endif
112753701ccSSumit Garg }
113753701ccSSumit Garg 
sq_system_off(void)114753701ccSSumit Garg void __dead2 sq_system_off(void)
115753701ccSSumit Garg {
116e01acbe9SMasahisa Kojima #if SQ_USE_SCMI_DRIVER
117e01acbe9SMasahisa Kojima 	sq_scmi_sys_shutdown();
118e01acbe9SMasahisa Kojima #else
119753701ccSSumit Garg 	volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
120753701ccSSumit Garg 
121753701ccSSumit Garg 	/* set PD[9] high to power off the system */
122753701ccSSumit Garg 	gpio[5] |= 0x2;		/* set output */
123753701ccSSumit Garg 	gpio[1] |= 0x2;		/* set high */
124753701ccSSumit Garg 	dmbst();
125753701ccSSumit Garg 
126753701ccSSumit Garg 	generic_delay_timer_init();
127753701ccSSumit Garg 
128753701ccSSumit Garg 	mdelay(1);
129753701ccSSumit Garg 
130753701ccSSumit Garg 	while (1) {
131753701ccSSumit Garg 		gpio[1] &= ~0x2;	/* set low */
132753701ccSSumit Garg 		dmbst();
133753701ccSSumit Garg 
134753701ccSSumit Garg 		mdelay(1);
135753701ccSSumit Garg 
136753701ccSSumit Garg 		gpio[1] |= 0x2;		/* set high */
137753701ccSSumit Garg 		dmbst();
138753701ccSSumit Garg 
139753701ccSSumit Garg 		mdelay(100);
140753701ccSSumit Garg 	}
141753701ccSSumit Garg 
142753701ccSSumit Garg 	wfi();
143753701ccSSumit Garg 	ERROR("SQ System Off: operation not handled.\n");
144753701ccSSumit Garg 	panic();
145e01acbe9SMasahisa Kojima #endif
146753701ccSSumit Garg }
147753701ccSSumit Garg 
sq_system_reset(void)148753701ccSSumit Garg void __dead2 sq_system_reset(void)
149753701ccSSumit Garg {
150b67d2029SMasahisa Kojima #if SQ_USE_SCMI_DRIVER
151b67d2029SMasahisa Kojima 	sq_scmi_sys_reboot();
152b67d2029SMasahisa Kojima #else
153753701ccSSumit Garg 	uint32_t response;
154753701ccSSumit Garg 
155753701ccSSumit Garg 	/* Send the system reset request to the SCP */
156753701ccSSumit Garg 	response = scpi_sys_power_state(scpi_system_reboot);
157753701ccSSumit Garg 
158753701ccSSumit Garg 	if (response != SCP_OK) {
159753701ccSSumit Garg 		ERROR("SQ System Reset: SCP error %u.\n", response);
160753701ccSSumit Garg 		panic();
161753701ccSSumit Garg 	}
162753701ccSSumit Garg 	wfi();
163753701ccSSumit Garg 	ERROR("SQ System Reset: operation not handled.\n");
164753701ccSSumit Garg 	panic();
165b67d2029SMasahisa Kojima #endif
166753701ccSSumit Garg }
167753701ccSSumit Garg 
sq_cpu_standby(plat_local_state_t cpu_state)168753701ccSSumit Garg void sq_cpu_standby(plat_local_state_t cpu_state)
169753701ccSSumit Garg {
170f1be00daSLouis Mayencourt 	u_register_t scr;
171753701ccSSumit Garg 
172753701ccSSumit Garg 	assert(cpu_state == SQ_LOCAL_STATE_RET);
173753701ccSSumit Garg 
174753701ccSSumit Garg 	scr = read_scr_el3();
175753701ccSSumit Garg 	/* Enable PhysicalIRQ bit for NS world to wake the CPU */
176753701ccSSumit Garg 	write_scr_el3(scr | SCR_IRQ_BIT);
177753701ccSSumit Garg 	isb();
178753701ccSSumit Garg 	dsb();
179753701ccSSumit Garg 	wfi();
180753701ccSSumit Garg 
181753701ccSSumit Garg 	/*
182753701ccSSumit Garg 	 * Restore SCR to the original value, synchronisation of scr_el3 is
183753701ccSSumit Garg 	 * done by eret while el3_exit to save some execution cycles.
184753701ccSSumit Garg 	 */
185753701ccSSumit Garg 	write_scr_el3(scr);
186753701ccSSumit Garg }
187753701ccSSumit Garg 
188753701ccSSumit Garg const plat_psci_ops_t sq_psci_ops = {
189753701ccSSumit Garg 	.pwr_domain_on		= sq_pwr_domain_on,
190753701ccSSumit Garg 	.pwr_domain_off		= sq_pwr_domain_off,
191753701ccSSumit Garg 	.pwr_domain_on_finish	= sq_pwr_domain_on_finish,
192753701ccSSumit Garg 	.cpu_standby		= sq_cpu_standby,
193753701ccSSumit Garg 	.system_off		= sq_system_off,
194753701ccSSumit Garg 	.system_reset		= sq_system_reset,
195753701ccSSumit Garg };
196753701ccSSumit Garg 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const struct plat_psci_ops ** psci_ops)197753701ccSSumit Garg int plat_setup_psci_ops(uintptr_t sec_entrypoint,
198753701ccSSumit Garg 			const struct plat_psci_ops **psci_ops)
199753701ccSSumit Garg {
200*48ab3904SJassi Brar #if !RESET_TO_BL31
201*48ab3904SJassi Brar 	uintptr_t *sq_sec_ep = (uintptr_t *)BL2_MAILBOX_BASE;
202*48ab3904SJassi Brar 
203*48ab3904SJassi Brar 	*sq_sec_ep = sec_entrypoint;
204*48ab3904SJassi Brar 	flush_dcache_range((uint64_t)sq_sec_ep,
205*48ab3904SJassi Brar 			   sizeof(*sq_sec_ep));
206*48ab3904SJassi Brar #else
207753701ccSSumit Garg 	sq_sec_entrypoint = sec_entrypoint;
208753701ccSSumit Garg 	flush_dcache_range((uint64_t)&sq_sec_entrypoint,
209753701ccSSumit Garg 			   sizeof(sq_sec_entrypoint));
210*48ab3904SJassi Brar #endif
211753701ccSSumit Garg 
212753701ccSSumit Garg 	*psci_ops = &sq_psci_ops;
213753701ccSSumit Garg 
214753701ccSSumit Garg 	return 0;
215753701ccSSumit Garg }
216