blob: 3062f6318c0027c0136687dda27d0ccb137eb80c [file] [log] [blame]
Sumit Garg754073f2018-06-15 15:29:02 +05301/*
Louis Mayencourt1c819c32020-01-24 13:30:28 +00002 * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
Sumit Garg754073f2018-06-15 15:29:02 +05303 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Sumit Garg754073f2018-06-15 15:29:02 +05307#include <assert.h>
Sumit Garg754073f2018-06-15 15:29:02 +05308#include <errno.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009
Sumit Garg754073f2018-06-15 15:29:02 +053010#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000011
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
Sumit Garg754073f2018-06-15 15:29:02 +053019#include <sq_common.h>
20#include "sq_scpi.h"
Sumit Garg754073f2018-06-15 15:29:02 +053021
Sumit Garg754073f2018-06-15 15:29:02 +053022uintptr_t sq_sec_entrypoint;
23
24int sq_pwr_domain_on(u_register_t mpidr)
25{
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +090026#if SQ_USE_SCMI_DRIVER
27 sq_scmi_on(mpidr);
28#else
Sumit Garg754073f2018-06-15 15:29:02 +053029 /*
30 * SCP takes care of powering up parent power domains so we
31 * only need to care about level 0
32 */
33 scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
34 scpi_power_on);
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +090035#endif
Sumit Garg754073f2018-06-15 15:29:02 +053036
37 return PSCI_E_SUCCESS;
38}
39
40static void sq_pwr_domain_on_finisher_common(
41 const psci_power_state_t *target_state)
42{
43 assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
44
45 /*
46 * Perform the common cluster specific operations i.e enable coherency
47 * if this cluster was off.
48 */
49 if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
50 plat_sq_interconnect_enter_coherency();
51}
52
53void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
54{
55 /* Assert that the system power domain need not be initialized */
56 assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
57
58 sq_pwr_domain_on_finisher_common(target_state);
59
60 /* Program the gic per-cpu distributor or re-distributor interface */
61 sq_gic_pcpu_init();
62
63 /* Enable the gic cpu interface */
64 sq_gic_cpuif_enable();
65}
66
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +090067#if !SQ_USE_SCMI_DRIVER
Sumit Garg754073f2018-06-15 15:29:02 +053068static void sq_power_down_common(const psci_power_state_t *target_state)
69{
70 uint32_t cluster_state = scpi_power_on;
71 uint32_t system_state = scpi_power_on;
72
73 /* Prevent interrupts from spuriously waking up this cpu */
74 sq_gic_cpuif_disable();
75
76 /* Check if power down at system power domain level is requested */
77 if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
78 system_state = scpi_power_retention;
79
80 /* Cluster is to be turned off, so disable coherency */
81 if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
82 plat_sq_interconnect_exit_coherency();
83 cluster_state = scpi_power_off;
84 }
85
86 /*
87 * Ask the SCP to power down the appropriate components depending upon
88 * their state.
89 */
90 scpi_set_sq_power_state(read_mpidr_el1(),
91 scpi_power_off,
92 cluster_state,
93 system_state);
94}
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +090095#endif
Sumit Garg754073f2018-06-15 15:29:02 +053096
97void sq_pwr_domain_off(const psci_power_state_t *target_state)
98{
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +090099#if SQ_USE_SCMI_DRIVER
Masahisa Kojima804b6b52021-08-03 16:48:53 +0900100 /* Prevent interrupts from spuriously waking up this cpu */
101 sq_gic_cpuif_disable();
102
103 /* Cluster is to be turned off, so disable coherency */
104 if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
105 plat_sq_interconnect_exit_coherency();
106 }
107
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +0900108 sq_scmi_off(target_state);
109#else
Sumit Garg754073f2018-06-15 15:29:02 +0530110 sq_power_down_common(target_state);
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +0900111#endif
Sumit Garg754073f2018-06-15 15:29:02 +0530112}
113
114void __dead2 sq_system_off(void)
115{
Masahisa Kojimacc6d6702021-11-11 10:17:09 +0900116#if SQ_USE_SCMI_DRIVER
117 sq_scmi_sys_shutdown();
118#else
Sumit Garg754073f2018-06-15 15:29:02 +0530119 volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
120
121 /* set PD[9] high to power off the system */
122 gpio[5] |= 0x2; /* set output */
123 gpio[1] |= 0x2; /* set high */
124 dmbst();
125
126 generic_delay_timer_init();
127
128 mdelay(1);
129
130 while (1) {
131 gpio[1] &= ~0x2; /* set low */
132 dmbst();
133
134 mdelay(1);
135
136 gpio[1] |= 0x2; /* set high */
137 dmbst();
138
139 mdelay(100);
140 }
141
142 wfi();
143 ERROR("SQ System Off: operation not handled.\n");
144 panic();
Masahisa Kojimacc6d6702021-11-11 10:17:09 +0900145#endif
Sumit Garg754073f2018-06-15 15:29:02 +0530146}
147
148void __dead2 sq_system_reset(void)
149{
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +0900150#if SQ_USE_SCMI_DRIVER
151 sq_scmi_sys_reboot();
152#else
Sumit Garg754073f2018-06-15 15:29:02 +0530153 uint32_t response;
154
155 /* Send the system reset request to the SCP */
156 response = scpi_sys_power_state(scpi_system_reboot);
157
158 if (response != SCP_OK) {
159 ERROR("SQ System Reset: SCP error %u.\n", response);
160 panic();
161 }
162 wfi();
163 ERROR("SQ System Reset: operation not handled.\n");
164 panic();
Masahisa Kojimaebfd8eb2019-03-07 10:41:54 +0900165#endif
Sumit Garg754073f2018-06-15 15:29:02 +0530166}
167
168void sq_cpu_standby(plat_local_state_t cpu_state)
169{
Louis Mayencourt1c819c32020-01-24 13:30:28 +0000170 u_register_t scr;
Sumit Garg754073f2018-06-15 15:29:02 +0530171
172 assert(cpu_state == SQ_LOCAL_STATE_RET);
173
174 scr = read_scr_el3();
175 /* Enable PhysicalIRQ bit for NS world to wake the CPU */
176 write_scr_el3(scr | SCR_IRQ_BIT);
177 isb();
178 dsb();
179 wfi();
180
181 /*
182 * Restore SCR to the original value, synchronisation of scr_el3 is
183 * done by eret while el3_exit to save some execution cycles.
184 */
185 write_scr_el3(scr);
186}
187
188const plat_psci_ops_t sq_psci_ops = {
189 .pwr_domain_on = sq_pwr_domain_on,
190 .pwr_domain_off = sq_pwr_domain_off,
191 .pwr_domain_on_finish = sq_pwr_domain_on_finish,
192 .cpu_standby = sq_cpu_standby,
193 .system_off = sq_system_off,
194 .system_reset = sq_system_reset,
195};
196
197int plat_setup_psci_ops(uintptr_t sec_entrypoint,
198 const struct plat_psci_ops **psci_ops)
199{
200 sq_sec_entrypoint = sec_entrypoint;
201 flush_dcache_range((uint64_t)&sq_sec_entrypoint,
202 sizeof(sq_sec_entrypoint));
203
204 *psci_ops = &sq_psci_ops;
205
206 return 0;
207}