blob: 64873241510a9a2e84a5725a6f68d6c29c12c181 [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
167 mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id),
168 APU_PCIL_CORE_X_IEN_POWER_MASK);
169
170 bakery_lock_release(&pm_client_secure_lock);
171}
172
173/**
174 * pm_get_cpuid() - get the local cpu ID for a global node ID
175 * @param nid node id of the processor
176 *
177 * @return the cpu ID (starting from 0) for the subsystem
178 */
179static uint32_t pm_get_cpuid(uint32_t nid)
180{
181 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
182 if (pm_procs_all[i].node_id == nid) {
183 return i;
184 }
185 }
186 return UNDEFINED_CPUID;
187}
188
189/**
190 * pm_client_wakeup() - Client-specific wakeup actions
191 *
192 * This function should contain any PU-specific actions
193 * required for waking up another APU core
194 *
195 * @param proc Processor which need to wakeup
196 */
197void pm_client_wakeup(const struct pm_proc *proc)
198{
199 uint32_t cpuid = pm_get_cpuid(proc->node_id);
200
201 if (cpuid == UNDEFINED_CPUID) {
202 return;
203 }
204
205 bakery_lock_get(&pm_client_secure_lock);
206
207 /* TODO: clear powerdown bit for affected cpu */
208
209 bakery_lock_release(&pm_client_secure_lock);
210}
211
212/**
213 * pm_client_abort_suspend() - Client-specific abort-suspend actions
214 *
215 * This function should contain any PU-specific actions
216 * required for aborting a prior suspend request
217 */
218void pm_client_abort_suspend(void)
219{
220 uint32_t cpu_id = plat_my_core_pos();
221 uintptr_t val;
222
223 /* Enable interrupts at processor level (for current cpu) */
224 gicv3_cpuif_enable(plat_my_core_pos());
225
226 bakery_lock_get(&pm_client_secure_lock);
227
228 /* Clear powerdown request */
229 val = read_cpu_pwrctrl_val();
230 val &= ~CORE_PWRDN_EN_BIT_MASK;
231 write_cpu_pwrctrl_val(val);
232
233 isb();
234
235 /* Disabled power down interrupt */
236 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
237 APU_PCIL_CORE_X_IDS_POWER_MASK);
238
239 bakery_lock_release(&pm_client_secure_lock);
240}