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