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