blob: c327f1d4834c9fca43d9020c8fc4b749399d71f7 [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
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
29uintptr_t sq_sec_entrypoint;
30
31int 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
43static 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
56void 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
70static 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
98void sq_pwr_domain_off(const psci_power_state_t *target_state)
99{
100 sq_power_down_common(target_state);
101}
102
103void __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
133void __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
149void 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
169const 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
178int 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}