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