xref: /rk3399_ARM-atf/plat/socionext/synquacer/sq_psci.c (revision b67d20297fd67d29931283c6a01e4aab7898d570)
1753701ccSSumit Garg /*
2753701ccSSumit Garg  * Copyright (c) 2018, 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 
24753701ccSSumit Garg int sq_pwr_domain_on(u_register_t mpidr)
25753701ccSSumit Garg {
26*b67d2029SMasahisa Kojima #if SQ_USE_SCMI_DRIVER
27*b67d2029SMasahisa Kojima 	sq_scmi_on(mpidr);
28*b67d2029SMasahisa 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);
35*b67d2029SMasahisa Kojima #endif
36753701ccSSumit Garg 
37753701ccSSumit Garg 	return PSCI_E_SUCCESS;
38753701ccSSumit Garg }
39753701ccSSumit Garg 
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 
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 
67*b67d2029SMasahisa Kojima #if !SQ_USE_SCMI_DRIVER
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 }
95*b67d2029SMasahisa Kojima #endif
96753701ccSSumit Garg 
97753701ccSSumit Garg void sq_pwr_domain_off(const psci_power_state_t *target_state)
98753701ccSSumit Garg {
99*b67d2029SMasahisa Kojima #if SQ_USE_SCMI_DRIVER
100*b67d2029SMasahisa Kojima 	sq_scmi_off(target_state);
101*b67d2029SMasahisa Kojima #else
102753701ccSSumit Garg 	sq_power_down_common(target_state);
103*b67d2029SMasahisa Kojima #endif
104753701ccSSumit Garg }
105753701ccSSumit Garg 
106753701ccSSumit Garg void __dead2 sq_system_off(void)
107753701ccSSumit Garg {
108753701ccSSumit Garg 	volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
109753701ccSSumit Garg 
110753701ccSSumit Garg 	/* set PD[9] high to power off the system */
111753701ccSSumit Garg 	gpio[5] |= 0x2;		/* set output */
112753701ccSSumit Garg 	gpio[1] |= 0x2;		/* set high */
113753701ccSSumit Garg 	dmbst();
114753701ccSSumit Garg 
115753701ccSSumit Garg 	generic_delay_timer_init();
116753701ccSSumit Garg 
117753701ccSSumit Garg 	mdelay(1);
118753701ccSSumit Garg 
119753701ccSSumit Garg 	while (1) {
120753701ccSSumit Garg 		gpio[1] &= ~0x2;	/* set low */
121753701ccSSumit Garg 		dmbst();
122753701ccSSumit Garg 
123753701ccSSumit Garg 		mdelay(1);
124753701ccSSumit Garg 
125753701ccSSumit Garg 		gpio[1] |= 0x2;		/* set high */
126753701ccSSumit Garg 		dmbst();
127753701ccSSumit Garg 
128753701ccSSumit Garg 		mdelay(100);
129753701ccSSumit Garg 	}
130753701ccSSumit Garg 
131753701ccSSumit Garg 	wfi();
132753701ccSSumit Garg 	ERROR("SQ System Off: operation not handled.\n");
133753701ccSSumit Garg 	panic();
134753701ccSSumit Garg }
135753701ccSSumit Garg 
136753701ccSSumit Garg void __dead2 sq_system_reset(void)
137753701ccSSumit Garg {
138*b67d2029SMasahisa Kojima #if SQ_USE_SCMI_DRIVER
139*b67d2029SMasahisa Kojima 	sq_scmi_sys_reboot();
140*b67d2029SMasahisa Kojima #else
141753701ccSSumit Garg 	uint32_t response;
142753701ccSSumit Garg 
143753701ccSSumit Garg 	/* Send the system reset request to the SCP */
144753701ccSSumit Garg 	response = scpi_sys_power_state(scpi_system_reboot);
145753701ccSSumit Garg 
146753701ccSSumit Garg 	if (response != SCP_OK) {
147753701ccSSumit Garg 		ERROR("SQ System Reset: SCP error %u.\n", response);
148753701ccSSumit Garg 		panic();
149753701ccSSumit Garg 	}
150753701ccSSumit Garg 	wfi();
151753701ccSSumit Garg 	ERROR("SQ System Reset: operation not handled.\n");
152753701ccSSumit Garg 	panic();
153*b67d2029SMasahisa Kojima #endif
154753701ccSSumit Garg }
155753701ccSSumit Garg 
156753701ccSSumit Garg void sq_cpu_standby(plat_local_state_t cpu_state)
157753701ccSSumit Garg {
158753701ccSSumit Garg 	unsigned int scr;
159753701ccSSumit Garg 
160753701ccSSumit Garg 	assert(cpu_state == SQ_LOCAL_STATE_RET);
161753701ccSSumit Garg 
162753701ccSSumit Garg 	scr = read_scr_el3();
163753701ccSSumit Garg 	/* Enable PhysicalIRQ bit for NS world to wake the CPU */
164753701ccSSumit Garg 	write_scr_el3(scr | SCR_IRQ_BIT);
165753701ccSSumit Garg 	isb();
166753701ccSSumit Garg 	dsb();
167753701ccSSumit Garg 	wfi();
168753701ccSSumit Garg 
169753701ccSSumit Garg 	/*
170753701ccSSumit Garg 	 * Restore SCR to the original value, synchronisation of scr_el3 is
171753701ccSSumit Garg 	 * done by eret while el3_exit to save some execution cycles.
172753701ccSSumit Garg 	 */
173753701ccSSumit Garg 	write_scr_el3(scr);
174753701ccSSumit Garg }
175753701ccSSumit Garg 
176753701ccSSumit Garg const plat_psci_ops_t sq_psci_ops = {
177753701ccSSumit Garg 	.pwr_domain_on		= sq_pwr_domain_on,
178753701ccSSumit Garg 	.pwr_domain_off		= sq_pwr_domain_off,
179753701ccSSumit Garg 	.pwr_domain_on_finish	= sq_pwr_domain_on_finish,
180753701ccSSumit Garg 	.cpu_standby		= sq_cpu_standby,
181753701ccSSumit Garg 	.system_off		= sq_system_off,
182753701ccSSumit Garg 	.system_reset		= sq_system_reset,
183753701ccSSumit Garg };
184753701ccSSumit Garg 
185753701ccSSumit Garg int plat_setup_psci_ops(uintptr_t sec_entrypoint,
186753701ccSSumit Garg 			const struct plat_psci_ops **psci_ops)
187753701ccSSumit Garg {
188753701ccSSumit Garg 	sq_sec_entrypoint = sec_entrypoint;
189753701ccSSumit Garg 	flush_dcache_range((uint64_t)&sq_sec_entrypoint,
190753701ccSSumit Garg 			   sizeof(sq_sec_entrypoint));
191753701ccSSumit Garg 
192753701ccSSumit Garg 	*psci_ops = &sq_psci_ops;
193753701ccSSumit Garg 
194753701ccSSumit Garg 	return 0;
195753701ccSSumit Garg }
196