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