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  */
pm_get_proc(uint32_t cpuid)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  */
pm_client_suspend(const struct pm_proc * proc,uint32_t state)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 	mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id),
168 		      APU_PCIL_CORE_X_IEN_POWER_MASK);
169 
170 	bakery_lock_release(&pm_client_secure_lock);
171 }
172 
173 /**
174  * pm_get_cpuid() - get the local cpu ID for a global node ID
175  * @param nid	node id of the processor
176  *
177  * @return the cpu ID (starting from 0) for the subsystem
178  */
pm_get_cpuid(uint32_t nid)179 static uint32_t pm_get_cpuid(uint32_t nid)
180 {
181 	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
182 		if (pm_procs_all[i].node_id == nid) {
183 			return i;
184 		}
185 	}
186 	return UNDEFINED_CPUID;
187 }
188 
189 /**
190  * pm_client_wakeup() - Client-specific wakeup actions
191  *
192  * This function should contain any PU-specific actions
193  * required for waking up another APU core
194  *
195  * @param proc	Processor which need to wakeup
196  */
pm_client_wakeup(const struct pm_proc * proc)197 void pm_client_wakeup(const struct pm_proc *proc)
198 {
199 	uint32_t cpuid = pm_get_cpuid(proc->node_id);
200 
201 	if (cpuid == UNDEFINED_CPUID) {
202 		return;
203 	}
204 
205 	bakery_lock_get(&pm_client_secure_lock);
206 
207 	/* TODO: clear powerdown bit for affected cpu */
208 
209 	bakery_lock_release(&pm_client_secure_lock);
210 }
211 
212 /**
213  * pm_client_abort_suspend() - Client-specific abort-suspend actions
214  *
215  * This function should contain any PU-specific actions
216  * required for aborting a prior suspend request
217  */
pm_client_abort_suspend(void)218 void pm_client_abort_suspend(void)
219 {
220 	uint32_t cpu_id = plat_my_core_pos();
221 	uintptr_t val;
222 
223 	/* Enable interrupts at processor level (for current cpu) */
224 	gicv3_cpuif_enable(plat_my_core_pos());
225 
226 	bakery_lock_get(&pm_client_secure_lock);
227 
228 	/* Clear powerdown request */
229 	val = read_cpu_pwrctrl_val();
230 	val &= ~CORE_PWRDN_EN_BIT_MASK;
231 	write_cpu_pwrctrl_val(val);
232 
233 	isb();
234 
235 	/* Disabled power down interrupt */
236 	mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
237 			APU_PCIL_CORE_X_IDS_POWER_MASK);
238 
239 	bakery_lock_release(&pm_client_secure_lock);
240 }
241