xref: /rk3399_ARM-atf/plat/xilinx/versal/pm_service/pm_client.c (revision cff0d54160643e0e082f7541183b3acc4c71602b)
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_ID_APU,
33 	.remote_ipi_id = IPI_ID_PMC,
34 	.buffer_base = IPI_BUFFER_APU_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 enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
60 {
61 	enum pm_device_node_idx dev_idx = XPM_NODEIDX_DEV_MIN;
62 
63 	assert(irq <= IRQ_MAX);
64 
65 	switch (irq) {
66 	case 13:
67 		dev_idx = XPM_NODEIDX_DEV_GPIO;
68 		break;
69 	case 14:
70 		dev_idx = XPM_NODEIDX_DEV_I2C_0;
71 		break;
72 	case 15:
73 		dev_idx = XPM_NODEIDX_DEV_I2C_1;
74 		break;
75 	case 16:
76 		dev_idx = XPM_NODEIDX_DEV_SPI_0;
77 		break;
78 	case 17:
79 		dev_idx = XPM_NODEIDX_DEV_SPI_1;
80 		break;
81 	case 18:
82 		dev_idx = XPM_NODEIDX_DEV_UART_0;
83 		break;
84 	case 19:
85 		dev_idx = XPM_NODEIDX_DEV_UART_1;
86 		break;
87 	case 20:
88 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_0;
89 		break;
90 	case 21:
91 		dev_idx = XPM_NODEIDX_DEV_CAN_FD_1;
92 		break;
93 	case 22:
94 	case 23:
95 	case 24:
96 	case 25:
97 	case 26:
98 		dev_idx = XPM_NODEIDX_DEV_USB_0;
99 		break;
100 	case 37:
101 	case 38:
102 	case 39:
103 		dev_idx = XPM_NODEIDX_DEV_TTC_0;
104 		break;
105 	case 40:
106 	case 41:
107 	case 42:
108 		dev_idx = XPM_NODEIDX_DEV_TTC_1;
109 		break;
110 	case 43:
111 	case 44:
112 	case 45:
113 		dev_idx = XPM_NODEIDX_DEV_TTC_2;
114 		break;
115 	case 46:
116 	case 47:
117 	case 48:
118 		dev_idx = XPM_NODEIDX_DEV_TTC_3;
119 		break;
120 	case 56:
121 	case 57:
122 		dev_idx = XPM_NODEIDX_DEV_GEM_0;
123 		break;
124 	default:
125 		dev_idx = XPM_NODEIDX_DEV_MIN;
126 		break;
127 	}
128 
129 	return dev_idx;
130 }
131 
132 /**
133  * pm_client_suspend() - Client-specific suspend actions
134  *
135  * This function should contain any PU-specific actions
136  * required prior to sending suspend request to PMU
137  * Actions taken depend on the state system is suspending to.
138  */
139 void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
140 {
141 	bakery_lock_get(&pm_client_secure_lock);
142 
143 	if (state == PM_STATE_SUSPEND_TO_RAM) {
144 		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
145 	}
146 
147 	/* Set powerdown request */
148 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
149 		      (uint32_t)proc->pwrdn_mask);
150 
151 	bakery_lock_release(&pm_client_secure_lock);
152 }
153 
154 /**
155  * pm_client_abort_suspend() - Client-specific abort-suspend actions
156  *
157  * This function should contain any PU-specific actions
158  * required for aborting a prior suspend request
159  */
160 void pm_client_abort_suspend(void)
161 {
162 	/* Enable interrupts at processor level (for current cpu) */
163 	gicv3_cpuif_enable(plat_my_core_pos());
164 
165 	bakery_lock_get(&pm_client_secure_lock);
166 
167 	/* Clear powerdown request */
168 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
169 		      ~((uint32_t)primary_proc->pwrdn_mask));
170 
171 	bakery_lock_release(&pm_client_secure_lock);
172 }
173 
174 /**
175  * pm_get_cpuid() - get the local cpu ID for a global node ID
176  * @nid:	node id of the processor
177  *
178  * Return: the cpu ID (starting from 0) for the subsystem
179  */
180 static uint32_t pm_get_cpuid(uint32_t nid)
181 {
182 	for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
183 		if (pm_procs_all[i].node_id == nid) {
184 			return i;
185 		}
186 	}
187 	return UNDEFINED_CPUID;
188 }
189 
190 /**
191  * pm_client_wakeup() - Client-specific wakeup actions
192  *
193  * This function should contain any PU-specific actions
194  * required for waking up another APU core
195  */
196 void pm_client_wakeup(const struct pm_proc *proc)
197 {
198 	uint32_t cpuid = pm_get_cpuid(proc->node_id);
199 
200 	if (cpuid == UNDEFINED_CPUID) {
201 		return;
202 	}
203 
204 	bakery_lock_get(&pm_client_secure_lock);
205 
206 	/* clear powerdown bit for affected cpu */
207 	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
208 	val &= ~(proc->pwrdn_mask);
209 	mmio_write_32(FPD_APU_PWRCTL, val);
210 
211 	bakery_lock_release(&pm_client_secure_lock);
212 }
213 
214 /**
215  * pm_get_proc() - returns pointer to the proc structure
216  * @cpuid:	id of the cpu whose proc struct pointer should be returned
217  *
218  * Return: pointer to a proc structure if proc is found, otherwise NULL
219  */
220 const struct pm_proc *pm_get_proc(uint32_t cpuid)
221 {
222 	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
223 		return &pm_procs_all[cpuid];
224 	}
225 
226 	return NULL;
227 }
228