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