xref: /rk3399_ARM-atf/plat/xilinx/versal_net/pm_service/pm_client.c (revision d23acc9e4f94d95280ee7985e3f96482eb7fe04d)
1 /*
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 <lib/spinlock.h>
22 #include <plat/common/platform.h>
23 
24 #include <plat_ipi.h>
25 #include <platform_def.h>
26 #include "pm_api_sys.h"
27 #include "pm_client.h"
28 #include <versal_net_def.h>
29 
30 #define UNDEFINED_CPUID		(~0)
31 
32 DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7)
33 
34 /*
35  * ARM v8.2, the cache will turn off automatically when cpu
36  * power down. Therefore, there is no doubt to use the spin_lock here.
37  */
38 #if !HW_ASSISTED_COHERENCY
39 DEFINE_BAKERY_LOCK(pm_client_secure_lock);
40 static inline void pm_client_lock_get(void)
41 {
42 	bakery_lock_get(&pm_client_secure_lock);
43 }
44 
45 static inline void pm_client_lock_release(void)
46 {
47 	bakery_lock_release(&pm_client_secure_lock);
48 }
49 #else
50 spinlock_t pm_client_secure_lock;
51 static inline void pm_client_lock_get(void)
52 {
53 	spin_lock(&pm_client_secure_lock);
54 }
55 
56 static inline void pm_client_lock_release(void)
57 {
58 	spin_unlock(&pm_client_secure_lock);
59 }
60 #endif
61 
62 static const struct pm_ipi apu_ipi = {
63 	.local_ipi_id = IPI_ID_APU,
64 	.remote_ipi_id = IPI_ID_PMC,
65 	.buffer_base = IPI_BUFFER_APU_BASE,
66 };
67 
68 /* Order in pm_procs_all array must match cpu ids */
69 static const struct pm_proc pm_procs_all[] = {
70 	{
71 		.node_id = PM_DEV_CLUSTER0_ACPU_0,
72 		.ipi = &apu_ipi,
73 		.pwrdn_mask = 0,
74 	},
75 	{
76 		.node_id = PM_DEV_CLUSTER0_ACPU_1,
77 		.ipi = &apu_ipi,
78 		.pwrdn_mask = 0,
79 	},
80 	{
81 		.node_id = PM_DEV_CLUSTER0_ACPU_2,
82 		.ipi = &apu_ipi,
83 		.pwrdn_mask = 0,
84 	},
85 	{
86 		.node_id = PM_DEV_CLUSTER0_ACPU_3,
87 		.ipi = &apu_ipi,
88 		.pwrdn_mask = 0,
89 	},
90 	{
91 		.node_id = PM_DEV_CLUSTER1_ACPU_0,
92 		.ipi = &apu_ipi,
93 		.pwrdn_mask = 0,
94 	},
95 	{
96 		.node_id = PM_DEV_CLUSTER1_ACPU_1,
97 		.ipi = &apu_ipi,
98 		.pwrdn_mask = 0,
99 	},
100 	{
101 		.node_id = PM_DEV_CLUSTER1_ACPU_2,
102 		.ipi = &apu_ipi,
103 		.pwrdn_mask = 0,
104 	},
105 	{
106 		.node_id = PM_DEV_CLUSTER1_ACPU_3,
107 		.ipi = &apu_ipi,
108 		.pwrdn_mask = 0,
109 	},
110 	{
111 		.node_id = PM_DEV_CLUSTER2_ACPU_0,
112 		.ipi = &apu_ipi,
113 		.pwrdn_mask = 0,
114 	},
115 	{
116 		.node_id = PM_DEV_CLUSTER2_ACPU_1,
117 		.ipi = &apu_ipi,
118 		.pwrdn_mask = 0,
119 	},
120 	{
121 		.node_id = PM_DEV_CLUSTER2_ACPU_2,
122 		.ipi = &apu_ipi,
123 		.pwrdn_mask = 0,
124 	},
125 	{
126 		.node_id = PM_DEV_CLUSTER2_ACPU_3,
127 		.ipi = &apu_ipi,
128 		.pwrdn_mask = 0,
129 	},
130 	{
131 		.node_id = PM_DEV_CLUSTER3_ACPU_0,
132 		.ipi = &apu_ipi,
133 		.pwrdn_mask = 0,
134 	},
135 	{
136 		.node_id = PM_DEV_CLUSTER3_ACPU_1,
137 		.ipi = &apu_ipi,
138 		.pwrdn_mask = 0,
139 	},
140 	{
141 		.node_id = PM_DEV_CLUSTER3_ACPU_2,
142 		.ipi = &apu_ipi,
143 		.pwrdn_mask = 0,
144 	},
145 	{
146 		.node_id = PM_DEV_CLUSTER3_ACPU_3,
147 		.ipi = &apu_ipi,
148 		.pwrdn_mask = 0,
149 	}
150 };
151 
152 const struct pm_proc *primary_proc = &pm_procs_all[0];
153 
154 /**
155  * pm_get_proc() - returns pointer to the proc structure
156  * @param cpuid	id of the cpu whose proc struct pointer should be returned
157  *
158  * @return pointer to a proc structure if proc is found, otherwise NULL
159  */
160 const struct pm_proc *pm_get_proc(uint32_t cpuid)
161 {
162 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
163 		return &pm_procs_all[cpuid];
164 	}
165 
166 	NOTICE("ERROR: cpuid: %d proc NULL\n", cpuid);
167 	return NULL;
168 }
169 
170 /**
171  * pm_client_suspend() - Client-specific suspend actions
172  *
173  * This function should contain any PU-specific actions
174  * required prior to sending suspend request to PMU
175  * Actions taken depend on the state system is suspending to.
176  *
177  * @param proc	processor which need to suspend
178  * @param state	desired suspend state
179  */
180 void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
181 {
182 	uint32_t cpu_id = plat_my_core_pos();
183 	uintptr_t val;
184 
185 	pm_client_lock_get();
186 
187 	/* TODO: Set wakeup source */
188 
189 	val = read_cpu_pwrctrl_val();
190 	val |= CORE_PWRDN_EN_BIT_MASK;
191 	write_cpu_pwrctrl_val(val);
192 
193 	isb();
194 
195 	/* Clear power down interrupt status before enabling */
196 	mmio_write_32(APU_PCIL_CORE_X_ISR_POWER_REG(cpu_id),
197 		      APU_PCIL_CORE_X_ISR_POWER_MASK);
198 	/* Enable power down interrupt */
199 	mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id),
200 		      APU_PCIL_CORE_X_IEN_POWER_MASK);
201 	/* Clear wakeup interrupt status before enabling */
202 	mmio_write_32(APU_PCIL_CORE_X_ISR_WAKE_REG(cpu_id),
203 		      APU_PCIL_CORE_X_ISR_WAKE_MASK);
204 	/* Enable wake interrupt */
205 	mmio_write_32(APU_PCIL_CORE_X_IEN_WAKE_REG(cpu_id),
206 		      APU_PCIL_CORE_X_IEN_WAKE_MASK);
207 
208 	pm_client_lock_release();
209 }
210 
211 /**
212  * pm_get_cpuid() - get the local cpu ID for a global node ID
213  * @param nid	node id of the processor
214  *
215  * @return the cpu ID (starting from 0) for the subsystem
216  */
217 static uint32_t pm_get_cpuid(uint32_t nid)
218 {
219 	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
220 		if (pm_procs_all[i].node_id == nid) {
221 			return i;
222 		}
223 	}
224 	return UNDEFINED_CPUID;
225 }
226 
227 /**
228  * pm_client_wakeup() - Client-specific wakeup actions
229  *
230  * This function should contain any PU-specific actions
231  * required for waking up another APU core
232  *
233  * @param proc	Processor which need to wakeup
234  */
235 void pm_client_wakeup(const struct pm_proc *proc)
236 {
237 	uint32_t cpuid = pm_get_cpuid(proc->node_id);
238 	uintptr_t val;
239 
240 	if (cpuid == UNDEFINED_CPUID) {
241 		return;
242 	}
243 
244 	pm_client_lock_get();
245 
246 	/* Clear powerdown request */
247 	val = read_cpu_pwrctrl_val();
248 	val &= ~CORE_PWRDN_EN_BIT_MASK;
249 	write_cpu_pwrctrl_val(val);
250 
251 	isb();
252 
253 	/* Disabled power down interrupt */
254 	mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpuid),
255 			APU_PCIL_CORE_X_IDS_POWER_MASK);
256 	/* Clear wakeup interrupt status before disabling */
257 	mmio_write_32(APU_PCIL_CORE_X_ISR_WAKE_REG(cpuid),
258 		      APU_PCIL_CORE_X_ISR_WAKE_MASK);
259 	/* Disable wake interrupt */
260 	mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(cpuid),
261 		      APU_PCIL_CORE_X_IDS_WAKE_MASK);
262 
263 	pm_client_lock_release();
264 }
265 
266 /**
267  * pm_client_abort_suspend() - Client-specific abort-suspend actions
268  *
269  * This function should contain any PU-specific actions
270  * required for aborting a prior suspend request
271  */
272 void pm_client_abort_suspend(void)
273 {
274 	uint32_t cpu_id = plat_my_core_pos();
275 	uintptr_t val;
276 
277 	/* Enable interrupts at processor level (for current cpu) */
278 	gicv3_cpuif_enable(plat_my_core_pos());
279 
280 	pm_client_lock_get();
281 
282 	/* Clear powerdown request */
283 	val = read_cpu_pwrctrl_val();
284 	val &= ~CORE_PWRDN_EN_BIT_MASK;
285 	write_cpu_pwrctrl_val(val);
286 
287 	isb();
288 
289 	/* Disabled power down interrupt */
290 	mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
291 			APU_PCIL_CORE_X_IDS_POWER_MASK);
292 
293 	pm_client_lock_release();
294 }
295