blob: b42b466511c50ae4fdb64a2ec0473e139ac7b410 [file] [log] [blame]
Jay Buddhabhattic6daff02022-09-05 02:56:32 -07001/*
2 * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
3 * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8/*
9 * APU specific definition of processors in the subsystem as well as functions
10 * for getting information about and changing state of the APU.
11 */
12
13#include <assert.h>
14
15#include <drivers/arm/gic_common.h>
16#include <drivers/arm/gicv3.h>
17#include <lib/bakery_lock.h>
18#include <lib/mmio.h>
19#include <lib/mmio.h>
20#include <lib/utils.h>
21#include <plat/common/platform.h>
22
23#include <plat_ipi.h>
24#include <platform_def.h>
25#include "pm_api_sys.h"
26#include "pm_client.h"
27#include <versal_net_def.h>
28
29#define UNDEFINED_CPUID (~0)
30
31DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7)
32DEFINE_BAKERY_LOCK(pm_client_secure_lock);
33
34static const struct pm_ipi apu_ipi = {
35 .local_ipi_id = IPI_ID_APU,
36 .remote_ipi_id = IPI_ID_PMC,
37 .buffer_base = IPI_BUFFER_APU_BASE,
38};
39
40/* Order in pm_procs_all array must match cpu ids */
41static const struct pm_proc pm_procs_all[] = {
42 {
43 .node_id = PM_DEV_CLUSTER0_ACPU_0,
44 .ipi = &apu_ipi,
45 .pwrdn_mask = 0,
46 },
47 {
48 .node_id = PM_DEV_CLUSTER0_ACPU_1,
49 .ipi = &apu_ipi,
50 .pwrdn_mask = 0,
51 },
52 {
53 .node_id = PM_DEV_CLUSTER0_ACPU_2,
54 .ipi = &apu_ipi,
55 .pwrdn_mask = 0,
56 },
57 {
58 .node_id = PM_DEV_CLUSTER0_ACPU_3,
59 .ipi = &apu_ipi,
60 .pwrdn_mask = 0,
61 },
62 {
63 .node_id = PM_DEV_CLUSTER1_ACPU_0,
64 .ipi = &apu_ipi,
65 .pwrdn_mask = 0,
66 },
67 {
68 .node_id = PM_DEV_CLUSTER1_ACPU_1,
69 .ipi = &apu_ipi,
70 .pwrdn_mask = 0,
71 },
72 {
73 .node_id = PM_DEV_CLUSTER1_ACPU_2,
74 .ipi = &apu_ipi,
75 .pwrdn_mask = 0,
76 },
77 {
78 .node_id = PM_DEV_CLUSTER1_ACPU_3,
79 .ipi = &apu_ipi,
80 .pwrdn_mask = 0,
81 },
82 {
83 .node_id = PM_DEV_CLUSTER2_ACPU_0,
84 .ipi = &apu_ipi,
85 .pwrdn_mask = 0,
86 },
87 {
88 .node_id = PM_DEV_CLUSTER2_ACPU_1,
89 .ipi = &apu_ipi,
90 .pwrdn_mask = 0,
91 },
92 {
93 .node_id = PM_DEV_CLUSTER2_ACPU_2,
94 .ipi = &apu_ipi,
95 .pwrdn_mask = 0,
96 },
97 {
98 .node_id = PM_DEV_CLUSTER2_ACPU_3,
99 .ipi = &apu_ipi,
100 .pwrdn_mask = 0,
101 },
102 {
103 .node_id = PM_DEV_CLUSTER3_ACPU_0,
104 .ipi = &apu_ipi,
105 .pwrdn_mask = 0,
106 },
107 {
108 .node_id = PM_DEV_CLUSTER3_ACPU_1,
109 .ipi = &apu_ipi,
110 .pwrdn_mask = 0,
111 },
112 {
113 .node_id = PM_DEV_CLUSTER3_ACPU_2,
114 .ipi = &apu_ipi,
115 .pwrdn_mask = 0,
116 },
117 {
118 .node_id = PM_DEV_CLUSTER3_ACPU_3,
119 .ipi = &apu_ipi,
120 .pwrdn_mask = 0,
121 }
122};
123
124const struct pm_proc *primary_proc = &pm_procs_all[0];
125
126/**
127 * pm_get_proc() - returns pointer to the proc structure
128 * @param cpuid id of the cpu whose proc struct pointer should be returned
129 *
130 * @return pointer to a proc structure if proc is found, otherwise NULL
131 */
132const struct pm_proc *pm_get_proc(uint32_t cpuid)
133{
134 if (cpuid < ARRAY_SIZE(pm_procs_all)) {
135 return &pm_procs_all[cpuid];
136 }
137
138 NOTICE("ERROR: cpuid: %d proc NULL\n", cpuid);
139 return NULL;
140}
141
142/**
143 * pm_client_suspend() - Client-specific suspend actions
144 *
145 * This function should contain any PU-specific actions
146 * required prior to sending suspend request to PMU
147 * Actions taken depend on the state system is suspending to.
148 *
149 * @param proc processor which need to suspend
150 * @param state desired suspend state
151 */
152void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
153{
154 uint32_t cpu_id = plat_my_core_pos();
155 uintptr_t val;
156
157 bakery_lock_get(&pm_client_secure_lock);
158
159 /* TODO: Set wakeup source */
160
161 val = read_cpu_pwrctrl_val();
162 val |= CORE_PWRDN_EN_BIT_MASK;
163 write_cpu_pwrctrl_val(val);
164
165 isb();
166
Jay Buddhabhattic2358652022-12-29 21:47:54 -0800167 /* Clear power down interrupt status before enabling */
168 mmio_write_32(APU_PCIL_CORE_X_ISR_POWER_REG(cpu_id),
169 APU_PCIL_CORE_X_ISR_POWER_MASK);
170 /* Enable power down interrupt */
Jay Buddhabhattic6daff02022-09-05 02:56:32 -0700171 mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id),
172 APU_PCIL_CORE_X_IEN_POWER_MASK);
173
174 bakery_lock_release(&pm_client_secure_lock);
175}
176
177/**
178 * pm_get_cpuid() - get the local cpu ID for a global node ID
179 * @param nid node id of the processor
180 *
181 * @return the cpu ID (starting from 0) for the subsystem
182 */
183static uint32_t pm_get_cpuid(uint32_t nid)
184{
185 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
186 if (pm_procs_all[i].node_id == nid) {
187 return i;
188 }
189 }
190 return UNDEFINED_CPUID;
191}
192
193/**
194 * pm_client_wakeup() - Client-specific wakeup actions
195 *
196 * This function should contain any PU-specific actions
197 * required for waking up another APU core
198 *
199 * @param proc Processor which need to wakeup
200 */
201void pm_client_wakeup(const struct pm_proc *proc)
202{
203 uint32_t cpuid = pm_get_cpuid(proc->node_id);
Jay Buddhabhatti07d85c92022-12-29 22:15:19 -0800204 uintptr_t val;
Jay Buddhabhattic6daff02022-09-05 02:56:32 -0700205
206 if (cpuid == UNDEFINED_CPUID) {
207 return;
208 }
209
210 bakery_lock_get(&pm_client_secure_lock);
211
Jay Buddhabhatti07d85c92022-12-29 22:15:19 -0800212 /* Clear powerdown request */
213 val = read_cpu_pwrctrl_val();
214 val &= ~CORE_PWRDN_EN_BIT_MASK;
215 write_cpu_pwrctrl_val(val);
216
217 isb();
218
219 /* Disabled power down interrupt */
220 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpuid),
221 APU_PCIL_CORE_X_IDS_POWER_MASK);
Jay Buddhabhattiedfadb72022-12-29 22:21:00 -0800222 /* Clear wakeup interrupt status before disabling */
223 mmio_write_32(APU_PCIL_CORE_X_ISR_WAKE_REG(cpuid),
224 APU_PCIL_CORE_X_ISR_WAKE_MASK);
225 /* Disable wake interrupt */
226 mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(cpuid),
227 APU_PCIL_CORE_X_IDS_WAKE_MASK);
Jay Buddhabhattic6daff02022-09-05 02:56:32 -0700228
229 bakery_lock_release(&pm_client_secure_lock);
230}
231
232/**
233 * pm_client_abort_suspend() - Client-specific abort-suspend actions
234 *
235 * This function should contain any PU-specific actions
236 * required for aborting a prior suspend request
237 */
238void pm_client_abort_suspend(void)
239{
240 uint32_t cpu_id = plat_my_core_pos();
241 uintptr_t val;
242
243 /* Enable interrupts at processor level (for current cpu) */
244 gicv3_cpuif_enable(plat_my_core_pos());
245
246 bakery_lock_get(&pm_client_secure_lock);
247
248 /* Clear powerdown request */
249 val = read_cpu_pwrctrl_val();
250 val &= ~CORE_PWRDN_EN_BIT_MASK;
251 write_cpu_pwrctrl_val(val);
252
253 isb();
254
255 /* Disabled power down interrupt */
256 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
257 APU_PCIL_CORE_X_IDS_POWER_MASK);
258
259 bakery_lock_release(&pm_client_secure_lock);
260}