blob: 12060ef08fbafbf358e870849cf0896e48e36378 [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{
Hadi Asyrafi616da772019-06-27 11:34:03 +080064 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
65 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
66 __func__, i, target_state->pwr_domain_state[i]);
67
Hadi Asyrafi91071fc2019-09-12 15:14:01 +080068 /* Prevent interrupts from spuriously waking up this cpu */
69 gicv2_cpuif_disable();
Hadi Asyrafi616da772019-06-27 11:34:03 +080070}
71
72/*******************************************************************************
73 * plat handler called when a power domain is about to be suspended. The
74 * target_state encodes the power state that each level should transition to.
75 ******************************************************************************/
76void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
77{
78 unsigned int cpu_id = plat_my_core_pos();
79
80 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
81 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
82 __func__, i, target_state->pwr_domain_state[i]);
83 /* assert core reset */
84 mmio_setbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST,
85 1 << cpu_id);
86
87}
88
89/*******************************************************************************
90 * plat handler called when a power domain has just been powered on after
91 * being turned off earlier. The target_state encodes the low power state that
92 * each level has woken up from.
93 ******************************************************************************/
94void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
95{
96 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
97 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
98 __func__, i, target_state->pwr_domain_state[i]);
99
100 /* Program the gic per-cpu distributor or re-distributor interface */
101 gicv2_pcpu_distif_init();
102 gicv2_set_pe_target_mask(plat_my_core_pos());
103
104 /* Enable the gic cpu interface */
105 gicv2_cpuif_enable();
106}
107
108/*******************************************************************************
109 * plat handler called when a power domain has just been powered on after
110 * having been suspended earlier. The target_state encodes the low power state
111 * that each level has woken up from.
112 * TODO: At the moment we reuse the on finisher and reinitialize the secure
113 * context. Need to implement a separate suspend finisher.
114 ******************************************************************************/
115void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
116{
117 unsigned int cpu_id = plat_my_core_pos();
118
119 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
120 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
121 __func__, i, target_state->pwr_domain_state[i]);
122
123 /* release core reset */
124 mmio_clrbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST,
125 1 << cpu_id);
126}
127
128/*******************************************************************************
129 * plat handlers to shutdown/reboot the system
130 ******************************************************************************/
131static void __dead2 socfpga_system_off(void)
132{
133 wfi();
134 ERROR("System Off: operation not handled.\n");
135 panic();
136}
137
138static void __dead2 socfpga_system_reset(void)
139{
140 INFO("assert Peripheral from Reset\r\n");
141
142 deassert_peripheral_reset();
143 mailbox_reset_cold();
144
145 while (1)
146 wfi();
147}
148
149int socfpga_validate_power_state(unsigned int power_state,
150 psci_power_state_t *req_state)
151{
152 VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
153
154 return PSCI_E_SUCCESS;
155}
156
157int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
158{
159 VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
160 return PSCI_E_SUCCESS;
161}
162
163void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
164{
165 req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
166 req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
167}
168
169/*******************************************************************************
170 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
171 * platform layer will take care of registering the handlers with PSCI.
172 ******************************************************************************/
173const plat_psci_ops_t socfpga_psci_pm_ops = {
174 .cpu_standby = socfpga_cpu_standby,
175 .pwr_domain_on = socfpga_pwr_domain_on,
176 .pwr_domain_off = socfpga_pwr_domain_off,
177 .pwr_domain_suspend = socfpga_pwr_domain_suspend,
178 .pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
179 .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
180 .system_off = socfpga_system_off,
181 .system_reset = socfpga_system_reset,
182 .validate_power_state = socfpga_validate_power_state,
183 .validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
184 .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
185};
186
187/*******************************************************************************
188 * Export the platform specific power ops.
189 ******************************************************************************/
190int plat_setup_psci_ops(uintptr_t sec_entrypoint,
191 const struct plat_psci_ops **psci_ops)
192{
193 /* Save warm boot entrypoint.*/
194 *agilex_sec_entry = sec_entrypoint;
195
196 *psci_ops = &socfpga_psci_pm_ops;
197 return 0;
198}