blob: f4a970e75ca37bd2dcc5c636e2b66164dad9a987 [file] [log] [blame]
Tien Hock, Lohab34f742019-02-26 09:25:14 +08001/*
2 * Copyright (c) 2019, 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 <common/debug.h>
10#include <errno.h>
11#include <lib/mmio.h>
12#include <drivers/arm/gic_common.h>
13#include <drivers/arm/gicv2.h>
14#include <plat/common/platform.h>
15#include <lib/psci/psci.h>
16
17#include "platform_def.h"
Tien Hock, Lohab34f742019-02-26 09:25:14 +080018#include "s10_reset_manager.h"
19#include "s10_mailbox.h"
20
21#define S10_RSTMGR_OFST 0xffd11000
22#define S10_RSTMGR_MPUMODRST_OFST 0x20
23
Hadi Asyrafi309ac012019-08-01 14:48:39 +080024uintptr_t *stratix10_sec_entry = (uintptr_t *) PLAT_SEC_ENTRY;
Tien Hock, Lohab34f742019-02-26 09:25:14 +080025uintptr_t *cpuid_release = (uintptr_t *) PLAT_CPUID_RELEASE;
26
27/*******************************************************************************
28 * plat handler called when a CPU is about to enter standby.
29 ******************************************************************************/
30void plat_cpu_standby(plat_local_state_t cpu_state)
31{
32 /*
33 * Enter standby state
34 * dsb is good practice before using wfi to enter low power states
35 */
36 VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
37 dsb();
38 wfi();
39}
40
41/*******************************************************************************
42 * plat handler called when a power domain is about to be turned on. The
43 * mpidr determines the CPU to be turned on.
44 ******************************************************************************/
45int plat_pwr_domain_on(u_register_t mpidr)
46{
47 unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
48
49 VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
50
51 if (cpu_id == -1)
52 return PSCI_E_INTERN_FAIL;
53
54 *cpuid_release = cpu_id;
55
56 /* release core reset */
57 mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
58 1 << cpu_id);
59 return PSCI_E_SUCCESS;
60}
61
62/*******************************************************************************
63 * plat handler called when a power domain is about to be turned off. The
64 * target_state encodes the power state that each level should transition to.
65 ******************************************************************************/
66void plat_pwr_domain_off(const psci_power_state_t *target_state)
67{
68 unsigned int cpu_id = plat_my_core_pos();
69
70 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
71 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
72 __func__, i, target_state->pwr_domain_state[i]);
73
74 /* TODO: Prevent interrupts from spuriously waking up this cpu */
75 /* gicv2_cpuif_disable(); */
76
77 /* assert core reset */
78 mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
79 1 << cpu_id);
80}
81
82/*******************************************************************************
83 * plat handler called when a power domain is about to be suspended. The
84 * target_state encodes the power state that each level should transition to.
85 ******************************************************************************/
86void plat_pwr_domain_suspend(const psci_power_state_t *target_state)
87{
88 unsigned int cpu_id = plat_my_core_pos();
89
90 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
91 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
92 __func__, i, target_state->pwr_domain_state[i]);
93 /* assert core reset */
94 mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
95 1 << cpu_id);
96
97}
98
99/*******************************************************************************
100 * plat handler called when a power domain has just been powered on after
101 * being turned off earlier. The target_state encodes the low power state that
102 * each level has woken up from.
103 ******************************************************************************/
104void plat_pwr_domain_on_finish(const psci_power_state_t *target_state)
105{
106 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
107 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
108 __func__, i, target_state->pwr_domain_state[i]);
109
110 /* Program the gic per-cpu distributor or re-distributor interface */
111 gicv2_pcpu_distif_init();
112 gicv2_set_pe_target_mask(plat_my_core_pos());
113
114 /* Enable the gic cpu interface */
115 gicv2_cpuif_enable();
116}
117
118/*******************************************************************************
119 * plat handler called when a power domain has just been powered on after
120 * having been suspended earlier. The target_state encodes the low power state
121 * that each level has woken up from.
122 * TODO: At the moment we reuse the on finisher and reinitialize the secure
123 * context. Need to implement a separate suspend finisher.
124 ******************************************************************************/
125void plat_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
126{
127 unsigned int cpu_id = plat_my_core_pos();
128
129 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
130 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
131 __func__, i, target_state->pwr_domain_state[i]);
132
133 /* release core reset */
134 mmio_clrbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
135 1 << cpu_id);
136}
137
138/*******************************************************************************
139 * plat handlers to shutdown/reboot the system
140 ******************************************************************************/
141static void __dead2 plat_system_off(void)
142{
143 wfi();
144 ERROR("System Off: operation not handled.\n");
145 panic();
146}
147
148static void __dead2 plat_system_reset(void)
149{
150 INFO("assert Peripheral from Reset\r\n");
151
152 deassert_peripheral_reset();
153 mailbox_reset_cold();
154
155 while (1)
156 wfi();
157}
158
159int plat_validate_power_state(unsigned int power_state,
160 psci_power_state_t *req_state)
161{
162 VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
163
164 return PSCI_E_SUCCESS;
165}
166
167int plat_validate_ns_entrypoint(unsigned long ns_entrypoint)
168{
169 VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
170 return PSCI_E_SUCCESS;
171}
172
173void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
174{
175 req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
176 req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
177}
178
179/*******************************************************************************
180 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
181 * platform layer will take care of registering the handlers with PSCI.
182 ******************************************************************************/
183const plat_psci_ops_t plat_psci_pm_ops = {
184 .cpu_standby = plat_cpu_standby,
185 .pwr_domain_on = plat_pwr_domain_on,
186 .pwr_domain_off = plat_pwr_domain_off,
187 .pwr_domain_suspend = plat_pwr_domain_suspend,
188 .pwr_domain_on_finish = plat_pwr_domain_on_finish,
189 .pwr_domain_suspend_finish = plat_pwr_domain_suspend_finish,
190 .system_off = plat_system_off,
191 .system_reset = plat_system_reset,
192 .validate_power_state = plat_validate_power_state,
193 .validate_ns_entrypoint = plat_validate_ns_entrypoint,
194 .get_sys_suspend_power_state = plat_get_sys_suspend_power_state
195};
196
197/*******************************************************************************
198 * Export the platform specific power ops.
199 ******************************************************************************/
200int plat_setup_psci_ops(uintptr_t sec_entrypoint,
201 const struct plat_psci_ops **psci_ops)
202{
203 /* Save warm boot entrypoint.*/
204 *stratix10_sec_entry = sec_entrypoint;
205
206 *psci_ops = &plat_psci_pm_ops;
207 return 0;
208}