blob: 134224dce64ab1ed7ef9a0ab7f8b2516bb13b300 [file] [log] [blame]
Sumit Garg754073f2018-06-15 15:29:02 +05301/*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
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
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
32uintptr_t sq_sec_entrypoint;
33
34int 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
46static 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
59void 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
73static 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
101void sq_pwr_domain_off(const psci_power_state_t *target_state)
102{
103 sq_power_down_common(target_state);
104}
105
106void __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
136void __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
152void 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
172const 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
181int 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}