xref: /arm-trusted-firmware/plat/xilinx/versal/pm_service/pm_client.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
3*91f16700Schasinglulu  * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
4*91f16700Schasinglulu  *
5*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu /*
9*91f16700Schasinglulu  * APU specific definition of processors in the subsystem as well as functions
10*91f16700Schasinglulu  * for getting information about and changing state of the APU.
11*91f16700Schasinglulu  */
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <assert.h>
14*91f16700Schasinglulu 
15*91f16700Schasinglulu #include <drivers/arm/gic_common.h>
16*91f16700Schasinglulu #include <drivers/arm/gicv3.h>
17*91f16700Schasinglulu #include <lib/bakery_lock.h>
18*91f16700Schasinglulu #include <lib/mmio.h>
19*91f16700Schasinglulu #include <lib/utils.h>
20*91f16700Schasinglulu #include <plat/common/platform.h>
21*91f16700Schasinglulu 
22*91f16700Schasinglulu #include <plat_ipi.h>
23*91f16700Schasinglulu #include <platform_def.h>
24*91f16700Schasinglulu #include "pm_api_sys.h"
25*91f16700Schasinglulu #include "pm_client.h"
26*91f16700Schasinglulu #include "pm_defs.h"
27*91f16700Schasinglulu #include <versal_def.h>
28*91f16700Schasinglulu 
29*91f16700Schasinglulu #define UNDEFINED_CPUID		(~0)
30*91f16700Schasinglulu 
31*91f16700Schasinglulu DEFINE_BAKERY_LOCK(pm_client_secure_lock);
32*91f16700Schasinglulu 
33*91f16700Schasinglulu static const struct pm_ipi apu_ipi = {
34*91f16700Schasinglulu 	.local_ipi_id = IPI_LOCAL_ID,
35*91f16700Schasinglulu 	.remote_ipi_id = IPI_REMOTE_ID,
36*91f16700Schasinglulu 	.buffer_base = IPI_BUFFER_LOCAL_BASE,
37*91f16700Schasinglulu };
38*91f16700Schasinglulu 
39*91f16700Schasinglulu /* Order in pm_procs_all array must match cpu ids */
40*91f16700Schasinglulu static const struct pm_proc pm_procs_all[] = {
41*91f16700Schasinglulu 	{
42*91f16700Schasinglulu 		.node_id = XPM_DEVID_ACPU_0,
43*91f16700Schasinglulu 		.ipi = &apu_ipi,
44*91f16700Schasinglulu 		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
45*91f16700Schasinglulu 	},
46*91f16700Schasinglulu 	{
47*91f16700Schasinglulu 		.node_id = XPM_DEVID_ACPU_1,
48*91f16700Schasinglulu 		.ipi = &apu_ipi,
49*91f16700Schasinglulu 		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
50*91f16700Schasinglulu 	}
51*91f16700Schasinglulu };
52*91f16700Schasinglulu 
53*91f16700Schasinglulu const struct pm_proc *primary_proc = &pm_procs_all[0];
54*91f16700Schasinglulu 
55*91f16700Schasinglulu /**
56*91f16700Schasinglulu  * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number.
57*91f16700Schasinglulu  * @irq: Interrupt number
58*91f16700Schasinglulu  *
59*91f16700Schasinglulu  * Return: PM node index corresponding to the specified interrupt.
60*91f16700Schasinglulu  *
61*91f16700Schasinglulu  */
62*91f16700Schasinglulu enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
63*91f16700Schasinglulu {
64*91f16700Schasinglulu 	enum pm_device_node_idx dev_idx = XPM_NODEIDX_DEV_MIN;
65*91f16700Schasinglulu 
66*91f16700Schasinglulu 	assert(irq <= IRQ_MAX);
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	switch (irq) {
69*91f16700Schasinglulu 	case 13:
70*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_GPIO;
71*91f16700Schasinglulu 		break;
72*91f16700Schasinglulu 	case 14:
73*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_I2C_0;
74*91f16700Schasinglulu 		break;
75*91f16700Schasinglulu 	case 15:
76*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_I2C_1;
77*91f16700Schasinglulu 		break;
78*91f16700Schasinglulu 	case 16:
79*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_SPI_0;
80*91f16700Schasinglulu 		break;
81*91f16700Schasinglulu 	case 17:
82*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_SPI_1;
83*91f16700Schasinglulu 		break;
84*91f16700Schasinglulu 	case 18:
85*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_UART_0;
86*91f16700Schasinglulu 		break;
87*91f16700Schasinglulu 	case 19:
88*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_UART_1;
89*91f16700Schasinglulu 		break;
90*91f16700Schasinglulu 	case 20:
91*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_0;
92*91f16700Schasinglulu 		break;
93*91f16700Schasinglulu 	case 21:
94*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_1;
95*91f16700Schasinglulu 		break;
96*91f16700Schasinglulu 	case 22:
97*91f16700Schasinglulu 	case 23:
98*91f16700Schasinglulu 	case 24:
99*91f16700Schasinglulu 	case 25:
100*91f16700Schasinglulu 	case 26:
101*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_USB_0;
102*91f16700Schasinglulu 		break;
103*91f16700Schasinglulu 	case 37:
104*91f16700Schasinglulu 	case 38:
105*91f16700Schasinglulu 	case 39:
106*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_TTC_0;
107*91f16700Schasinglulu 		break;
108*91f16700Schasinglulu 	case 40:
109*91f16700Schasinglulu 	case 41:
110*91f16700Schasinglulu 	case 42:
111*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_TTC_1;
112*91f16700Schasinglulu 		break;
113*91f16700Schasinglulu 	case 43:
114*91f16700Schasinglulu 	case 44:
115*91f16700Schasinglulu 	case 45:
116*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_TTC_2;
117*91f16700Schasinglulu 		break;
118*91f16700Schasinglulu 	case 46:
119*91f16700Schasinglulu 	case 47:
120*91f16700Schasinglulu 	case 48:
121*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_TTC_3;
122*91f16700Schasinglulu 		break;
123*91f16700Schasinglulu 	case 56:
124*91f16700Schasinglulu 	case 57:
125*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_GEM_0;
126*91f16700Schasinglulu 		break;
127*91f16700Schasinglulu 	case 58:
128*91f16700Schasinglulu 	case 59:
129*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_GEM_1;
130*91f16700Schasinglulu 		break;
131*91f16700Schasinglulu 	case 60:
132*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_0;
133*91f16700Schasinglulu 		break;
134*91f16700Schasinglulu 	case 61:
135*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_1;
136*91f16700Schasinglulu 		break;
137*91f16700Schasinglulu 	case 62:
138*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_2;
139*91f16700Schasinglulu 		break;
140*91f16700Schasinglulu 	case 63:
141*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_3;
142*91f16700Schasinglulu 		break;
143*91f16700Schasinglulu 	case 64:
144*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_4;
145*91f16700Schasinglulu 		break;
146*91f16700Schasinglulu 	case 65:
147*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_5;
148*91f16700Schasinglulu 		break;
149*91f16700Schasinglulu 	case 66:
150*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_6;
151*91f16700Schasinglulu 		break;
152*91f16700Schasinglulu 	case 67:
153*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_ADMA_7;
154*91f16700Schasinglulu 		break;
155*91f16700Schasinglulu 	case 74:
156*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_USB_0;
157*91f16700Schasinglulu 		break;
158*91f16700Schasinglulu 	case 126:
159*91f16700Schasinglulu 	case 127:
160*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_SDIO_0;
161*91f16700Schasinglulu 		break;
162*91f16700Schasinglulu 	case 128:
163*91f16700Schasinglulu 	case 129:
164*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_SDIO_1;
165*91f16700Schasinglulu 		break;
166*91f16700Schasinglulu 	case 142:
167*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_RTC;
168*91f16700Schasinglulu 		break;
169*91f16700Schasinglulu 	default:
170*91f16700Schasinglulu 		dev_idx = XPM_NODEIDX_DEV_MIN;
171*91f16700Schasinglulu 		break;
172*91f16700Schasinglulu 	}
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 	return dev_idx;
175*91f16700Schasinglulu }
176*91f16700Schasinglulu 
177*91f16700Schasinglulu /**
178*91f16700Schasinglulu  * pm_client_suspend() - Client-specific suspend actions.
179*91f16700Schasinglulu  * @proc: processor which need to suspend.
180*91f16700Schasinglulu  * @state: desired suspend state.
181*91f16700Schasinglulu  *
182*91f16700Schasinglulu  * This function should contain any PU-specific actions
183*91f16700Schasinglulu  * required prior to sending suspend request to PMU
184*91f16700Schasinglulu  * Actions taken depend on the state system is suspending to.
185*91f16700Schasinglulu  *
186*91f16700Schasinglulu  */
187*91f16700Schasinglulu void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
188*91f16700Schasinglulu {
189*91f16700Schasinglulu 	bakery_lock_get(&pm_client_secure_lock);
190*91f16700Schasinglulu 
191*91f16700Schasinglulu 	if (state == PM_STATE_SUSPEND_TO_RAM) {
192*91f16700Schasinglulu 		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
193*91f16700Schasinglulu 	}
194*91f16700Schasinglulu 
195*91f16700Schasinglulu 	/* Set powerdown request */
196*91f16700Schasinglulu 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
197*91f16700Schasinglulu 		      (uint32_t)proc->pwrdn_mask);
198*91f16700Schasinglulu 
199*91f16700Schasinglulu 	bakery_lock_release(&pm_client_secure_lock);
200*91f16700Schasinglulu }
201*91f16700Schasinglulu 
202*91f16700Schasinglulu /**
203*91f16700Schasinglulu  * pm_client_abort_suspend() - Client-specific abort-suspend actions.
204*91f16700Schasinglulu  *
205*91f16700Schasinglulu  * This function should contain any PU-specific actions
206*91f16700Schasinglulu  * required for aborting a prior suspend request.
207*91f16700Schasinglulu  *
208*91f16700Schasinglulu  */
209*91f16700Schasinglulu void pm_client_abort_suspend(void)
210*91f16700Schasinglulu {
211*91f16700Schasinglulu 	/* Enable interrupts at processor level (for current cpu) */
212*91f16700Schasinglulu 	gicv3_cpuif_enable(plat_my_core_pos());
213*91f16700Schasinglulu 
214*91f16700Schasinglulu 	bakery_lock_get(&pm_client_secure_lock);
215*91f16700Schasinglulu 
216*91f16700Schasinglulu 	/* Clear powerdown request */
217*91f16700Schasinglulu 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
218*91f16700Schasinglulu 		      ~((uint32_t)primary_proc->pwrdn_mask));
219*91f16700Schasinglulu 
220*91f16700Schasinglulu 	bakery_lock_release(&pm_client_secure_lock);
221*91f16700Schasinglulu }
222*91f16700Schasinglulu 
223*91f16700Schasinglulu /**
224*91f16700Schasinglulu  * pm_get_cpuid() - get the local cpu ID for a global node ID.
225*91f16700Schasinglulu  * @nid: node id of the processor.
226*91f16700Schasinglulu  *
227*91f16700Schasinglulu  * Return: the cpu ID (starting from 0) for the subsystem.
228*91f16700Schasinglulu  *
229*91f16700Schasinglulu  */
230*91f16700Schasinglulu static uint32_t pm_get_cpuid(uint32_t nid)
231*91f16700Schasinglulu {
232*91f16700Schasinglulu 	for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
233*91f16700Schasinglulu 		if (pm_procs_all[i].node_id == nid) {
234*91f16700Schasinglulu 			return i;
235*91f16700Schasinglulu 		}
236*91f16700Schasinglulu 	}
237*91f16700Schasinglulu 	return UNDEFINED_CPUID;
238*91f16700Schasinglulu }
239*91f16700Schasinglulu 
240*91f16700Schasinglulu /**
241*91f16700Schasinglulu  * pm_client_wakeup() - Client-specific wakeup actions.
242*91f16700Schasinglulu  * @proc: Processor which need to wakeup.
243*91f16700Schasinglulu  *
244*91f16700Schasinglulu  * This function should contain any PU-specific actions
245*91f16700Schasinglulu  * required for waking up another APU core.
246*91f16700Schasinglulu  *
247*91f16700Schasinglulu  */
248*91f16700Schasinglulu void pm_client_wakeup(const struct pm_proc *proc)
249*91f16700Schasinglulu {
250*91f16700Schasinglulu 	uint32_t cpuid = pm_get_cpuid(proc->node_id);
251*91f16700Schasinglulu 
252*91f16700Schasinglulu 	if (cpuid == UNDEFINED_CPUID) {
253*91f16700Schasinglulu 		return;
254*91f16700Schasinglulu 	}
255*91f16700Schasinglulu 
256*91f16700Schasinglulu 	bakery_lock_get(&pm_client_secure_lock);
257*91f16700Schasinglulu 
258*91f16700Schasinglulu 	/* clear powerdown bit for affected cpu */
259*91f16700Schasinglulu 	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
260*91f16700Schasinglulu 	val &= ~(proc->pwrdn_mask);
261*91f16700Schasinglulu 	mmio_write_32(FPD_APU_PWRCTL, val);
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 	bakery_lock_release(&pm_client_secure_lock);
264*91f16700Schasinglulu }
265*91f16700Schasinglulu 
266*91f16700Schasinglulu /**
267*91f16700Schasinglulu  * pm_get_proc() - returns pointer to the proc structure.
268*91f16700Schasinglulu  * @cpuid: id of the cpu whose proc struct pointer should be returned.
269*91f16700Schasinglulu  *
270*91f16700Schasinglulu  * Return: pointer to a proc structure if proc is found, otherwise NULL.
271*91f16700Schasinglulu  *
272*91f16700Schasinglulu  */
273*91f16700Schasinglulu const struct pm_proc *pm_get_proc(uint32_t cpuid)
274*91f16700Schasinglulu {
275*91f16700Schasinglulu 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
276*91f16700Schasinglulu 		return &pm_procs_all[cpuid];
277*91f16700Schasinglulu 	}
278*91f16700Schasinglulu 
279*91f16700Schasinglulu 	return NULL;
280*91f16700Schasinglulu }
281