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