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