xref: /rk3399_ARM-atf/plat/amd/versal2/pm_service/pm_client.c (revision 885ed9e05eace7f128629380bd0b1a72bb6f6b2c)
1 /*
2  * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
3  * Copyright (c) 2022-2025, 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/spinlock.h>
20 #include <lib/utils.h>
21 #include <plat/common/platform.h>
22 
23 #include <platform_def.h>
24 #include "def.h"
25 #include <plat_ipi.h>
26 #include <plat_pm_common.h>
27 #include "pm_api_sys.h"
28 #include "pm_client.h"
29 
30 #define UNDEFINED_CPUID	UINT32_MAX
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 static spinlock_t pm_client_secure_lock;
39 static inline void pm_client_lock_get(void)
40 {
41 	spin_lock(&pm_client_secure_lock);
42 }
43 
44 static inline void pm_client_lock_release(void)
45 {
46 	spin_unlock(&pm_client_secure_lock);
47 }
48 
49 static const struct pm_ipi apu_ipi = {
50 	.local_ipi_id = IPI_LOCAL_ID,
51 	.remote_ipi_id = IPI_REMOTE_ID,
52 	.buffer_base = IPI_BUFFER_LOCAL_BASE,
53 };
54 
55 /* Order in pm_procs_all array must match cpu ids */
56 static const struct pm_proc pm_procs_all[] = {
57 	{
58 		.node_id = PM_DEV_CLUSTER0_ACPU_0,
59 		.ipi = &apu_ipi,
60 	},
61 	{
62 		.node_id = PM_DEV_CLUSTER0_ACPU_1,
63 		.ipi = &apu_ipi,
64 	},
65 	{
66 		.node_id = PM_DEV_CLUSTER1_ACPU_0,
67 		.ipi = &apu_ipi,
68 	},
69 	{
70 		.node_id = PM_DEV_CLUSTER1_ACPU_1,
71 		.ipi = &apu_ipi,
72 	},
73 	{
74 		.node_id = PM_DEV_CLUSTER2_ACPU_0,
75 		.ipi = &apu_ipi,
76 	},
77 	{
78 		.node_id = PM_DEV_CLUSTER2_ACPU_1,
79 		.ipi = &apu_ipi,
80 	},
81 	{
82 		.node_id = PM_DEV_CLUSTER3_ACPU_0,
83 		.ipi = &apu_ipi,
84 	},
85 	{
86 		.node_id = PM_DEV_CLUSTER3_ACPU_1,
87 		.ipi = &apu_ipi,
88 	},
89 };
90 
91 const struct pm_proc *primary_proc = &pm_procs_all[0];
92 
93 /**
94  * pm_get_proc() - returns pointer to the proc structure.
95  * @cpuid: id of the cpu whose proc struct pointer should be returned.
96  *
97  * Return: Pointer to a proc structure if proc is found, otherwise NULL.
98  */
99 const struct pm_proc *pm_get_proc(uint32_t cpuid)
100 {
101 	const struct pm_proc *proc = NULL;
102 
103 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
104 		proc = &pm_procs_all[cpuid];
105 	} else {
106 		ERROR("cpuid: %d proc NULL\n", cpuid);
107 	}
108 
109 	return proc;
110 }
111 
112 /**
113  * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number.
114  * @irq: Interrupt number.
115  *
116  * Return: PM node index corresponding to the specified interrupt.
117  */
118 enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
119 {
120 	enum pm_device_node_idx dev_idx = XPM_NODEIDX_DEV_MIN;
121 
122 	assert(irq <= IRQ_MAX);
123 
124 	switch (irq) {
125 	case 11:
126 		dev_idx = XPM_NODEIDX_DEV_I2C_2;
127 		break;
128 	case 12:
129 		dev_idx = XPM_NODEIDX_DEV_I2C_3;
130 		break;
131 	case 13:
132 		dev_idx = XPM_NODEIDX_DEV_I2C_4;
133 		break;
134 	case 20:
135 		dev_idx = XPM_NODEIDX_DEV_GPIO;
136 		break;
137 	case 21:
138 		dev_idx = XPM_NODEIDX_DEV_I2C_0;
139 		break;
140 	case 22:
141 		dev_idx = XPM_NODEIDX_DEV_I2C_1;
142 		break;
143 	case 23:
144 		dev_idx = XPM_NODEIDX_DEV_SPI_0;
145 		break;
146 	case 24:
147 		dev_idx = XPM_NODEIDX_DEV_SPI_1;
148 		break;
149 	case 25:
150 		dev_idx = XPM_NODEIDX_DEV_UART_0;
151 		break;
152 	case 26:
153 		dev_idx = XPM_NODEIDX_DEV_UART_1;
154 		break;
155 	case 27:
156 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_0;
157 		break;
158 	case 28:
159 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_1;
160 		break;
161 	case 29:
162 	case 30:
163 	case 31:
164 	case 32:
165 	case 33:
166 	case 98:
167 		dev_idx = XPM_NODEIDX_DEV_USB_0;
168 		break;
169 	case 34:
170 	case 35:
171 	case 36:
172 	case 37:
173 	case 38:
174 	case 99:
175 		dev_idx = XPM_NODEIDX_DEV_USB_1;
176 		break;
177 	case 39:
178 	case 40:
179 		dev_idx = XPM_NODEIDX_DEV_GEM_0;
180 		break;
181 	case 41:
182 	case 42:
183 		dev_idx = XPM_NODEIDX_DEV_GEM_1;
184 		break;
185 	case 43:
186 		dev_idx = XPM_NODEIDX_DEV_TTC_0;
187 		break;
188 	case 44:
189 		dev_idx = XPM_NODEIDX_DEV_TTC_1;
190 		break;
191 	case 45:
192 		dev_idx = XPM_NODEIDX_DEV_TTC_2;
193 		break;
194 	case 46:
195 		dev_idx = XPM_NODEIDX_DEV_TTC_3;
196 		break;
197 	case 47:
198 		dev_idx = XPM_NODEIDX_DEV_TTC_4;
199 		break;
200 	case 48:
201 		dev_idx = XPM_NODEIDX_DEV_TTC_5;
202 		break;
203 	case 49:
204 		dev_idx = XPM_NODEIDX_DEV_TTC_6;
205 		break;
206 	case 50:
207 		dev_idx = XPM_NODEIDX_DEV_TTC_7;
208 		break;
209 	case 72:
210 		dev_idx = XPM_NODEIDX_DEV_ADMA_0;
211 		break;
212 	case 73:
213 		dev_idx = XPM_NODEIDX_DEV_ADMA_1;
214 		break;
215 	case 74:
216 		dev_idx = XPM_NODEIDX_DEV_ADMA_2;
217 		break;
218 	case 75:
219 		dev_idx = XPM_NODEIDX_DEV_ADMA_3;
220 		break;
221 	case 76:
222 		dev_idx = XPM_NODEIDX_DEV_ADMA_4;
223 		break;
224 	case 77:
225 		dev_idx = XPM_NODEIDX_DEV_ADMA_5;
226 		break;
227 	case 78:
228 		dev_idx = XPM_NODEIDX_DEV_ADMA_6;
229 		break;
230 	case 79:
231 		dev_idx = XPM_NODEIDX_DEV_ADMA_7;
232 		break;
233 	case 95:
234 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_2;
235 		break;
236 	case 96:
237 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_3;
238 		break;
239 	case 100:
240 		dev_idx = XPM_NODEIDX_DEV_I2C_5;
241 		break;
242 	case 101:
243 		dev_idx = XPM_NODEIDX_DEV_I2C_6;
244 		break;
245 	case 102:
246 		dev_idx = XPM_NODEIDX_DEV_I2C_7;
247 		break;
248 	case 164:
249 		dev_idx = XPM_NODEIDX_DEV_MMI_GEM;
250 		break;
251 	case 200:
252 		dev_idx = XPM_NODEIDX_DEV_RTC;
253 		break;
254 	case 218:
255 		dev_idx = XPM_NODEIDX_DEV_SDIO_0;
256 		break;
257 	case 220:
258 		dev_idx = XPM_NODEIDX_DEV_SDIO_1;
259 		break;
260 	default:
261 		dev_idx = XPM_NODEIDX_DEV_MIN;
262 		break;
263 	}
264 
265 	return dev_idx;
266 }
267 
268 /**
269  * pm_client_suspend() - Client-specific suspend actions. This function
270  *                       perform actions required prior to sending suspend
271  *                       request.
272  *                       Actions taken depend on the state system is
273  *                       suspending to.
274  * @proc: processor which need to suspend.
275  * @state: desired suspend state.
276  * @flag: 0 - Call from secure source.
277  *	  1 - Call from non-secure source.
278  */
279 void pm_client_suspend(const struct pm_proc *proc, uint32_t state, uint32_t flag)
280 {
281 	uint32_t cpu_id = plat_my_core_pos();
282 	uintptr_t val;
283 	/*
284 	 * Get the core index, use it calculate offset for secondary cores
285 	 * to match with register database
286 	 */
287 	uint32_t core_index = cpu_id + ((cpu_id / 2U) * 2U);
288 
289 	pm_client_lock_get();
290 
291 	if (state == PM_STATE_SUSPEND_TO_RAM) {
292 		pm_client_set_wakeup_sources((uint32_t)proc->node_id, flag);
293 	}
294 
295 	val = read_cpu_pwrctrl_val();
296 	val |= CORE_PWRDN_EN_BIT_MASK;
297 	write_cpu_pwrctrl_val(val);
298 
299 	isb();
300 
301 	/* Enable power down interrupt */
302 	mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(core_index),
303 		      APU_PCIL_CORE_X_IEN_POWER_MASK);
304 	/* Enable wake interrupt */
305 	mmio_write_32(APU_PCIL_CORE_X_IEN_WAKE_REG(core_index),
306 		      APU_PCIL_CORE_X_IEN_WAKE_MASK);
307 
308 	pm_client_lock_release();
309 }
310 
311 /**
312  * pm_get_cpuid() - get the local cpu ID for a global node ID.
313  * @nid: node id of the processor.
314  *
315  * Return: the cpu ID (starting from 0) for the subsystem.
316  */
317 static uint32_t pm_get_cpuid(uint32_t nid)
318 {
319 	uint32_t ret = (uint32_t) UNDEFINED_CPUID;
320 	size_t i;
321 
322 	for (i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
323 		if (pm_procs_all[i].node_id == nid) {
324 			ret = (uint32_t)i;
325 			break;
326 		}
327 	}
328 
329 	return ret;
330 }
331 
332 /**
333  * pm_client_wakeup() - Client-specific wakeup actions.
334  * @proc: Processor which need to wakeup.
335  *
336  * This function should contain any PU-specific actions
337  * required for waking up another APU core.
338  */
339 void pm_client_wakeup(const struct pm_proc *proc)
340 {
341 	uint32_t cpuid = pm_get_cpuid(proc->node_id);
342 	uintptr_t val;
343 
344 	if (cpuid != (uint32_t) UNDEFINED_CPUID) {
345 		/*
346 		 * Get the core index and use it to calculate offset for
347 		 * disabling power down and wakeup interrupts.
348 		 * i.e., Convert cpu-id to core_index with the following mapping:
349 		 *  cpu-id -> core_index
350 		 *       0 -> 0
351 		 *       1 -> 1
352 		 *       2 -> 4
353 		 *       3 -> 5
354 		 *       4 -> 8
355 		 *       5 -> 9
356 		 *       6 -> 12
357 		 *       7 -> 13
358 		 * to match with register database.
359 		 */
360 		uint32_t core_index = cpuid + ((cpuid / 2U) * 2U);
361 
362 		pm_client_lock_get();
363 
364 		/* Clear powerdown request */
365 		val = read_cpu_pwrctrl_val();
366 		val &= ~CORE_PWRDN_EN_BIT_MASK;
367 		write_cpu_pwrctrl_val(val);
368 
369 		isb();
370 
371 		/* Disabled power down interrupt */
372 		mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(core_index),
373 			      APU_PCIL_CORE_X_IDS_POWER_MASK);
374 		/* Disable wake interrupt */
375 		mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(core_index),
376 			      APU_PCIL_CORE_X_IDS_WAKE_MASK);
377 
378 		pm_client_lock_release();
379 	}
380 }
381 
382 /**
383  * pm_client_abort_suspend() - Client-specific abort-suspend actions.
384  *
385  * This function should contain any PU-specific actions
386  * required for aborting a prior suspend request.
387  */
388 void pm_client_abort_suspend(void)
389 {
390 	uint32_t cpu_id = plat_my_core_pos();
391 	uintptr_t val;
392 
393 	/* Enable interrupts at processor level (for current cpu) */
394 	gicv3_cpuif_enable(plat_my_core_pos());
395 
396 	pm_client_lock_get();
397 
398 	/* Clear powerdown request */
399 	val = read_cpu_pwrctrl_val();
400 	val &= ~CORE_PWRDN_EN_BIT_MASK;
401 	write_cpu_pwrctrl_val(val);
402 
403 	isb();
404 
405 	/* Disabled power down interrupt */
406 	mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
407 		      APU_PCIL_CORE_X_IDS_POWER_MASK);
408 
409 	pm_client_lock_release();
410 }
411