xref: /rk3399_ARM-atf/plat/socionext/synquacer/sq_psci.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
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>
9*09d40e0eSAntonio Nino Diaz 
10753701ccSSumit Garg #include <platform_def.h>
11*09d40e0eSAntonio Nino Diaz 
12*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
13*09d40e0eSAntonio Nino Diaz #include <common/debug.h>
14*09d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
15*09d40e0eSAntonio Nino Diaz #include <drivers/generic_delay_timer.h>
16*09d40e0eSAntonio Nino Diaz #include <lib/cassert.h>
17*09d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h>
18*09d40e0eSAntonio Nino Diaz 
19753701ccSSumit Garg #include <sq_common.h>
20753701ccSSumit Garg #include "sq_scpi.h"
21753701ccSSumit Garg 
22753701ccSSumit Garg /* Macros to read the SQ power domain state */
23753701ccSSumit Garg #define SQ_PWR_LVL0	MPIDR_AFFLVL0
24753701ccSSumit Garg #define SQ_PWR_LVL1	MPIDR_AFFLVL1
25753701ccSSumit Garg #define SQ_PWR_LVL2	MPIDR_AFFLVL2
26753701ccSSumit Garg 
27753701ccSSumit Garg #define SQ_CORE_PWR_STATE(state)	(state)->pwr_domain_state[SQ_PWR_LVL0]
28753701ccSSumit Garg #define SQ_CLUSTER_PWR_STATE(state)	(state)->pwr_domain_state[SQ_PWR_LVL1]
29753701ccSSumit Garg #define SQ_SYSTEM_PWR_STATE(state)	((PLAT_MAX_PWR_LVL > SQ_PWR_LVL1) ?\
30753701ccSSumit Garg 				(state)->pwr_domain_state[SQ_PWR_LVL2] : 0)
31753701ccSSumit Garg 
32753701ccSSumit Garg uintptr_t sq_sec_entrypoint;
33753701ccSSumit Garg 
34753701ccSSumit Garg int sq_pwr_domain_on(u_register_t mpidr)
35753701ccSSumit Garg {
36753701ccSSumit Garg 	/*
37753701ccSSumit Garg 	 * SCP takes care of powering up parent power domains so we
38753701ccSSumit Garg 	 * only need to care about level 0
39753701ccSSumit Garg 	 */
40753701ccSSumit Garg 	scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
41753701ccSSumit Garg 				 scpi_power_on);
42753701ccSSumit Garg 
43753701ccSSumit Garg 	return PSCI_E_SUCCESS;
44753701ccSSumit Garg }
45753701ccSSumit Garg 
46753701ccSSumit Garg static void sq_pwr_domain_on_finisher_common(
47753701ccSSumit Garg 		const psci_power_state_t *target_state)
48753701ccSSumit Garg {
49753701ccSSumit Garg 	assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
50753701ccSSumit Garg 
51753701ccSSumit Garg 	/*
52753701ccSSumit Garg 	 * Perform the common cluster specific operations i.e enable coherency
53753701ccSSumit Garg 	 * if this cluster was off.
54753701ccSSumit Garg 	 */
55753701ccSSumit Garg 	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
56753701ccSSumit Garg 		plat_sq_interconnect_enter_coherency();
57753701ccSSumit Garg }
58753701ccSSumit Garg 
59753701ccSSumit Garg void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
60753701ccSSumit Garg {
61753701ccSSumit Garg 	/* Assert that the system power domain need not be initialized */
62753701ccSSumit Garg 	assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
63753701ccSSumit Garg 
64753701ccSSumit Garg 	sq_pwr_domain_on_finisher_common(target_state);
65753701ccSSumit Garg 
66753701ccSSumit Garg 	/* Program the gic per-cpu distributor or re-distributor interface */
67753701ccSSumit Garg 	sq_gic_pcpu_init();
68753701ccSSumit Garg 
69753701ccSSumit Garg 	/* Enable the gic cpu interface */
70753701ccSSumit Garg 	sq_gic_cpuif_enable();
71753701ccSSumit Garg }
72753701ccSSumit Garg 
73753701ccSSumit Garg static void sq_power_down_common(const psci_power_state_t *target_state)
74753701ccSSumit Garg {
75753701ccSSumit Garg 	uint32_t cluster_state = scpi_power_on;
76753701ccSSumit Garg 	uint32_t system_state = scpi_power_on;
77753701ccSSumit Garg 
78753701ccSSumit Garg 	/* Prevent interrupts from spuriously waking up this cpu */
79753701ccSSumit Garg 	sq_gic_cpuif_disable();
80753701ccSSumit Garg 
81753701ccSSumit Garg 	/* Check if power down at system power domain level is requested */
82753701ccSSumit Garg 	if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
83753701ccSSumit Garg 		system_state = scpi_power_retention;
84753701ccSSumit Garg 
85753701ccSSumit Garg 	/* Cluster is to be turned off, so disable coherency */
86753701ccSSumit Garg 	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
87753701ccSSumit Garg 		plat_sq_interconnect_exit_coherency();
88753701ccSSumit Garg 		cluster_state = scpi_power_off;
89753701ccSSumit Garg 	}
90753701ccSSumit Garg 
91753701ccSSumit Garg 	/*
92753701ccSSumit Garg 	 * Ask the SCP to power down the appropriate components depending upon
93753701ccSSumit Garg 	 * their state.
94753701ccSSumit Garg 	 */
95753701ccSSumit Garg 	scpi_set_sq_power_state(read_mpidr_el1(),
96753701ccSSumit Garg 				 scpi_power_off,
97753701ccSSumit Garg 				 cluster_state,
98753701ccSSumit Garg 				 system_state);
99753701ccSSumit Garg }
100753701ccSSumit Garg 
101753701ccSSumit Garg void sq_pwr_domain_off(const psci_power_state_t *target_state)
102753701ccSSumit Garg {
103753701ccSSumit Garg 	sq_power_down_common(target_state);
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 {
138753701ccSSumit Garg 	uint32_t response;
139753701ccSSumit Garg 
140753701ccSSumit Garg 	/* Send the system reset request to the SCP */
141753701ccSSumit Garg 	response = scpi_sys_power_state(scpi_system_reboot);
142753701ccSSumit Garg 
143753701ccSSumit Garg 	if (response != SCP_OK) {
144753701ccSSumit Garg 		ERROR("SQ System Reset: SCP error %u.\n", response);
145753701ccSSumit Garg 		panic();
146753701ccSSumit Garg 	}
147753701ccSSumit Garg 	wfi();
148753701ccSSumit Garg 	ERROR("SQ System Reset: operation not handled.\n");
149753701ccSSumit Garg 	panic();
150753701ccSSumit Garg }
151753701ccSSumit Garg 
152753701ccSSumit Garg void sq_cpu_standby(plat_local_state_t cpu_state)
153753701ccSSumit Garg {
154753701ccSSumit Garg 	unsigned int scr;
155753701ccSSumit Garg 
156753701ccSSumit Garg 	assert(cpu_state == SQ_LOCAL_STATE_RET);
157753701ccSSumit Garg 
158753701ccSSumit Garg 	scr = read_scr_el3();
159753701ccSSumit Garg 	/* Enable PhysicalIRQ bit for NS world to wake the CPU */
160753701ccSSumit Garg 	write_scr_el3(scr | SCR_IRQ_BIT);
161753701ccSSumit Garg 	isb();
162753701ccSSumit Garg 	dsb();
163753701ccSSumit Garg 	wfi();
164753701ccSSumit Garg 
165753701ccSSumit Garg 	/*
166753701ccSSumit Garg 	 * Restore SCR to the original value, synchronisation of scr_el3 is
167753701ccSSumit Garg 	 * done by eret while el3_exit to save some execution cycles.
168753701ccSSumit Garg 	 */
169753701ccSSumit Garg 	write_scr_el3(scr);
170753701ccSSumit Garg }
171753701ccSSumit Garg 
172753701ccSSumit Garg const plat_psci_ops_t sq_psci_ops = {
173753701ccSSumit Garg 	.pwr_domain_on		= sq_pwr_domain_on,
174753701ccSSumit Garg 	.pwr_domain_off		= sq_pwr_domain_off,
175753701ccSSumit Garg 	.pwr_domain_on_finish	= sq_pwr_domain_on_finish,
176753701ccSSumit Garg 	.cpu_standby		= sq_cpu_standby,
177753701ccSSumit Garg 	.system_off		= sq_system_off,
178753701ccSSumit Garg 	.system_reset		= sq_system_reset,
179753701ccSSumit Garg };
180753701ccSSumit Garg 
181753701ccSSumit Garg int plat_setup_psci_ops(uintptr_t sec_entrypoint,
182753701ccSSumit Garg 			const struct plat_psci_ops **psci_ops)
183753701ccSSumit Garg {
184753701ccSSumit Garg 	sq_sec_entrypoint = sec_entrypoint;
185753701ccSSumit Garg 	flush_dcache_range((uint64_t)&sq_sec_entrypoint,
186753701ccSSumit Garg 			   sizeof(sq_sec_entrypoint));
187753701ccSSumit Garg 
188753701ccSSumit Garg 	*psci_ops = &sq_psci_ops;
189753701ccSSumit Garg 
190753701ccSSumit Garg 	return 0;
191753701ccSSumit Garg }
192