1 /* 2 * Copyright (c) 2022, Xilinx, Inc. All rights reserved. 3 * Copyright (c) 2022-2025, 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/spinlock.h> 20 #include <lib/utils.h> 21 #include <plat/common/platform.h> 22 23 #include <platform_def.h> 24 #include "def.h" 25 #include <plat_ipi.h> 26 #include "pm_api_sys.h" 27 #include "pm_client.h" 28 29 #define UNDEFINED_CPUID UINT32_MAX 30 31 DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7) 32 33 /* 34 * ARM v8.2, the cache will turn off automatically when cpu 35 * power down. Therefore, there is no doubt to use the spin_lock here. 36 */ 37 static spinlock_t pm_client_secure_lock; 38 static inline void pm_client_lock_get(void) 39 { 40 spin_lock(&pm_client_secure_lock); 41 } 42 43 static inline void pm_client_lock_release(void) 44 { 45 spin_unlock(&pm_client_secure_lock); 46 } 47 48 static const struct pm_ipi apu_ipi = { 49 .local_ipi_id = IPI_LOCAL_ID, 50 .remote_ipi_id = IPI_REMOTE_ID, 51 .buffer_base = IPI_BUFFER_LOCAL_BASE, 52 }; 53 54 /* Order in pm_procs_all array must match cpu ids */ 55 static const struct pm_proc pm_procs_all[] = { 56 { 57 .node_id = PM_DEV_CLUSTER0_ACPU_0, 58 .ipi = &apu_ipi, 59 }, 60 { 61 .node_id = PM_DEV_CLUSTER0_ACPU_1, 62 .ipi = &apu_ipi, 63 }, 64 { 65 .node_id = PM_DEV_CLUSTER1_ACPU_0, 66 .ipi = &apu_ipi, 67 }, 68 { 69 .node_id = PM_DEV_CLUSTER1_ACPU_1, 70 .ipi = &apu_ipi, 71 }, 72 { 73 .node_id = PM_DEV_CLUSTER2_ACPU_0, 74 .ipi = &apu_ipi, 75 }, 76 { 77 .node_id = PM_DEV_CLUSTER2_ACPU_1, 78 .ipi = &apu_ipi, 79 }, 80 { 81 .node_id = PM_DEV_CLUSTER3_ACPU_0, 82 .ipi = &apu_ipi, 83 }, 84 { 85 .node_id = PM_DEV_CLUSTER3_ACPU_1, 86 .ipi = &apu_ipi, 87 }, 88 }; 89 90 const struct pm_proc *primary_proc = &pm_procs_all[0]; 91 92 /** 93 * pm_get_proc() - returns pointer to the proc structure. 94 * @cpuid: id of the cpu whose proc struct pointer should be returned. 95 * 96 * Return: Pointer to a proc structure if proc is found, otherwise NULL. 97 */ 98 const struct pm_proc *pm_get_proc(uint32_t cpuid) 99 { 100 const struct pm_proc *proc = NULL; 101 102 if (cpuid < ARRAY_SIZE(pm_procs_all)) { 103 proc = &pm_procs_all[cpuid]; 104 } else { 105 ERROR("cpuid: %d proc NULL\n", cpuid); 106 } 107 108 return proc; 109 } 110 111 /** 112 * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number. 113 * @irq: Interrupt number. 114 * 115 * Return: PM node index corresponding to the specified interrupt. 116 */ 117 enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq) 118 { 119 enum pm_device_node_idx dev_idx = XPM_NODEIDX_DEV_MIN; 120 121 assert(irq <= IRQ_MAX); 122 123 switch (irq) { 124 case 11: 125 dev_idx = XPM_NODEIDX_DEV_I2C_2; 126 break; 127 case 12: 128 dev_idx = XPM_NODEIDX_DEV_I2C_3; 129 break; 130 case 13: 131 dev_idx = XPM_NODEIDX_DEV_I2C_4; 132 break; 133 case 20: 134 dev_idx = XPM_NODEIDX_DEV_GPIO; 135 break; 136 case 21: 137 dev_idx = XPM_NODEIDX_DEV_I2C_0; 138 break; 139 case 22: 140 dev_idx = XPM_NODEIDX_DEV_I2C_1; 141 break; 142 case 23: 143 dev_idx = XPM_NODEIDX_DEV_SPI_0; 144 break; 145 case 24: 146 dev_idx = XPM_NODEIDX_DEV_SPI_1; 147 break; 148 case 25: 149 dev_idx = XPM_NODEIDX_DEV_UART_0; 150 break; 151 case 26: 152 dev_idx = XPM_NODEIDX_DEV_UART_1; 153 break; 154 case 27: 155 dev_idx = XPM_NODEIDX_DEV_CAN_FD_0; 156 break; 157 case 28: 158 dev_idx = XPM_NODEIDX_DEV_CAN_FD_1; 159 break; 160 case 29: 161 case 30: 162 case 31: 163 case 32: 164 case 33: 165 case 98: 166 dev_idx = XPM_NODEIDX_DEV_USB_0; 167 break; 168 case 34: 169 case 35: 170 case 36: 171 case 37: 172 case 38: 173 case 99: 174 dev_idx = XPM_NODEIDX_DEV_USB_1; 175 break; 176 case 39: 177 case 40: 178 dev_idx = XPM_NODEIDX_DEV_GEM_0; 179 break; 180 case 41: 181 case 42: 182 dev_idx = XPM_NODEIDX_DEV_GEM_1; 183 break; 184 case 43: 185 dev_idx = XPM_NODEIDX_DEV_TTC_0; 186 break; 187 case 44: 188 dev_idx = XPM_NODEIDX_DEV_TTC_1; 189 break; 190 case 45: 191 dev_idx = XPM_NODEIDX_DEV_TTC_2; 192 break; 193 case 46: 194 dev_idx = XPM_NODEIDX_DEV_TTC_3; 195 break; 196 case 47: 197 dev_idx = XPM_NODEIDX_DEV_TTC_4; 198 break; 199 case 48: 200 dev_idx = XPM_NODEIDX_DEV_TTC_5; 201 break; 202 case 49: 203 dev_idx = XPM_NODEIDX_DEV_TTC_6; 204 break; 205 case 50: 206 dev_idx = XPM_NODEIDX_DEV_TTC_7; 207 break; 208 case 72: 209 dev_idx = XPM_NODEIDX_DEV_ADMA_0; 210 break; 211 case 73: 212 dev_idx = XPM_NODEIDX_DEV_ADMA_1; 213 break; 214 case 74: 215 dev_idx = XPM_NODEIDX_DEV_ADMA_2; 216 break; 217 case 75: 218 dev_idx = XPM_NODEIDX_DEV_ADMA_3; 219 break; 220 case 76: 221 dev_idx = XPM_NODEIDX_DEV_ADMA_4; 222 break; 223 case 77: 224 dev_idx = XPM_NODEIDX_DEV_ADMA_5; 225 break; 226 case 78: 227 dev_idx = XPM_NODEIDX_DEV_ADMA_6; 228 break; 229 case 79: 230 dev_idx = XPM_NODEIDX_DEV_ADMA_7; 231 break; 232 case 95: 233 dev_idx = XPM_NODEIDX_DEV_CAN_FD_2; 234 break; 235 case 96: 236 dev_idx = XPM_NODEIDX_DEV_CAN_FD_3; 237 break; 238 case 100: 239 dev_idx = XPM_NODEIDX_DEV_I2C_5; 240 break; 241 case 101: 242 dev_idx = XPM_NODEIDX_DEV_I2C_6; 243 break; 244 case 102: 245 dev_idx = XPM_NODEIDX_DEV_I2C_7; 246 break; 247 case 200: 248 dev_idx = XPM_NODEIDX_DEV_RTC; 249 break; 250 case 218: 251 dev_idx = XPM_NODEIDX_DEV_SDIO_0; 252 break; 253 case 220: 254 dev_idx = XPM_NODEIDX_DEV_SDIO_1; 255 break; 256 default: 257 dev_idx = XPM_NODEIDX_DEV_MIN; 258 break; 259 } 260 261 return dev_idx; 262 } 263 264 /** 265 * pm_client_suspend() - Client-specific suspend actions. This function 266 * perform actions required prior to sending suspend 267 * request. 268 * Actions taken depend on the state system is 269 * suspending to. 270 * @proc: processor which need to suspend. 271 * @state: desired suspend state. 272 */ 273 void pm_client_suspend(const struct pm_proc *proc, uint32_t state) 274 { 275 uint32_t cpu_id = plat_my_core_pos(); 276 uintptr_t val; 277 /* 278 * Get the core index, use it calculate offset for secondary cores 279 * to match with register database 280 */ 281 uint32_t core_index = cpu_id + ((cpu_id / 2U) * 2U); 282 283 pm_client_lock_get(); 284 285 if (state == PM_STATE_SUSPEND_TO_RAM) { 286 pm_client_set_wakeup_sources((uint32_t)proc->node_id); 287 } 288 289 val = read_cpu_pwrctrl_val(); 290 val |= CORE_PWRDN_EN_BIT_MASK; 291 write_cpu_pwrctrl_val(val); 292 293 isb(); 294 295 /* Enable power down interrupt */ 296 mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(core_index), 297 APU_PCIL_CORE_X_IEN_POWER_MASK); 298 /* Enable wake interrupt */ 299 mmio_write_32(APU_PCIL_CORE_X_IEN_WAKE_REG(core_index), 300 APU_PCIL_CORE_X_IEN_WAKE_MASK); 301 302 pm_client_lock_release(); 303 } 304 305 /** 306 * pm_get_cpuid() - get the local cpu ID for a global node ID. 307 * @nid: node id of the processor. 308 * 309 * Return: the cpu ID (starting from 0) for the subsystem. 310 */ 311 static uint32_t pm_get_cpuid(uint32_t nid) 312 { 313 uint32_t ret = (uint32_t) UNDEFINED_CPUID; 314 size_t i; 315 316 for (i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 317 if (pm_procs_all[i].node_id == nid) { 318 ret = (uint32_t)i; 319 break; 320 } 321 } 322 323 return ret; 324 } 325 326 /** 327 * pm_client_wakeup() - Client-specific wakeup actions. 328 * @proc: Processor which need to wakeup. 329 * 330 * This function should contain any PU-specific actions 331 * required for waking up another APU core. 332 */ 333 void pm_client_wakeup(const struct pm_proc *proc) 334 { 335 uint32_t cpuid = pm_get_cpuid(proc->node_id); 336 uintptr_t val; 337 338 if (cpuid != (uint32_t) UNDEFINED_CPUID) { 339 pm_client_lock_get(); 340 341 /* Clear powerdown request */ 342 val = read_cpu_pwrctrl_val(); 343 val &= ~CORE_PWRDN_EN_BIT_MASK; 344 write_cpu_pwrctrl_val(val); 345 346 isb(); 347 348 /* Disabled power down interrupt */ 349 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpuid), 350 APU_PCIL_CORE_X_IDS_POWER_MASK); 351 /* Disable wake interrupt */ 352 mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(cpuid), 353 APU_PCIL_CORE_X_IDS_WAKE_MASK); 354 355 pm_client_lock_release(); 356 } 357 } 358 359 /** 360 * pm_client_abort_suspend() - Client-specific abort-suspend actions. 361 * 362 * This function should contain any PU-specific actions 363 * required for aborting a prior suspend request. 364 */ 365 void pm_client_abort_suspend(void) 366 { 367 uint32_t cpu_id = plat_my_core_pos(); 368 uintptr_t val; 369 370 /* Enable interrupts at processor level (for current cpu) */ 371 gicv3_cpuif_enable(plat_my_core_pos()); 372 373 pm_client_lock_get(); 374 375 /* Clear powerdown request */ 376 val = read_cpu_pwrctrl_val(); 377 val &= ~CORE_PWRDN_EN_BIT_MASK; 378 write_cpu_pwrctrl_val(val); 379 380 isb(); 381 382 /* Disabled power down interrupt */ 383 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id), 384 APU_PCIL_CORE_X_IDS_POWER_MASK); 385 386 pm_client_lock_release(); 387 } 388