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 164: 248 dev_idx = XPM_NODEIDX_DEV_MMI_GEM; 249 break; 250 case 200: 251 dev_idx = XPM_NODEIDX_DEV_RTC; 252 break; 253 case 218: 254 dev_idx = XPM_NODEIDX_DEV_SDIO_0; 255 break; 256 case 220: 257 dev_idx = XPM_NODEIDX_DEV_SDIO_1; 258 break; 259 default: 260 dev_idx = XPM_NODEIDX_DEV_MIN; 261 break; 262 } 263 264 return dev_idx; 265 } 266 267 /** 268 * pm_client_suspend() - Client-specific suspend actions. This function 269 * perform actions required prior to sending suspend 270 * request. 271 * Actions taken depend on the state system is 272 * suspending to. 273 * @proc: processor which need to suspend. 274 * @state: desired suspend state. 275 */ 276 void pm_client_suspend(const struct pm_proc *proc, uint32_t state) 277 { 278 uint32_t cpu_id = plat_my_core_pos(); 279 uintptr_t val; 280 /* 281 * Get the core index, use it calculate offset for secondary cores 282 * to match with register database 283 */ 284 uint32_t core_index = cpu_id + ((cpu_id / 2U) * 2U); 285 286 pm_client_lock_get(); 287 288 if (state == PM_STATE_SUSPEND_TO_RAM) { 289 pm_client_set_wakeup_sources((uint32_t)proc->node_id); 290 } 291 292 val = read_cpu_pwrctrl_val(); 293 val |= CORE_PWRDN_EN_BIT_MASK; 294 write_cpu_pwrctrl_val(val); 295 296 isb(); 297 298 /* Enable power down interrupt */ 299 mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(core_index), 300 APU_PCIL_CORE_X_IEN_POWER_MASK); 301 /* Enable wake interrupt */ 302 mmio_write_32(APU_PCIL_CORE_X_IEN_WAKE_REG(core_index), 303 APU_PCIL_CORE_X_IEN_WAKE_MASK); 304 305 pm_client_lock_release(); 306 } 307 308 /** 309 * pm_get_cpuid() - get the local cpu ID for a global node ID. 310 * @nid: node id of the processor. 311 * 312 * Return: the cpu ID (starting from 0) for the subsystem. 313 */ 314 static uint32_t pm_get_cpuid(uint32_t nid) 315 { 316 uint32_t ret = (uint32_t) UNDEFINED_CPUID; 317 size_t i; 318 319 for (i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 320 if (pm_procs_all[i].node_id == nid) { 321 ret = (uint32_t)i; 322 break; 323 } 324 } 325 326 return ret; 327 } 328 329 /** 330 * pm_client_wakeup() - Client-specific wakeup actions. 331 * @proc: Processor which need to wakeup. 332 * 333 * This function should contain any PU-specific actions 334 * required for waking up another APU core. 335 */ 336 void pm_client_wakeup(const struct pm_proc *proc) 337 { 338 uint32_t cpuid = pm_get_cpuid(proc->node_id); 339 uintptr_t val; 340 341 if (cpuid != (uint32_t) UNDEFINED_CPUID) { 342 /* 343 * Get the core index and use it to calculate offset for 344 * disabling power down and wakeup interrupts. 345 * i.e., Convert cpu-id to core_index with the following mapping: 346 * cpu-id -> core_index 347 * 0 -> 0 348 * 1 -> 1 349 * 2 -> 4 350 * 3 -> 5 351 * 4 -> 8 352 * 5 -> 9 353 * 6 -> 12 354 * 7 -> 13 355 * to match with register database. 356 */ 357 uint32_t core_index = cpuid + ((cpuid / 2U) * 2U); 358 359 pm_client_lock_get(); 360 361 /* Clear powerdown request */ 362 val = read_cpu_pwrctrl_val(); 363 val &= ~CORE_PWRDN_EN_BIT_MASK; 364 write_cpu_pwrctrl_val(val); 365 366 isb(); 367 368 /* Disabled power down interrupt */ 369 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(core_index), 370 APU_PCIL_CORE_X_IDS_POWER_MASK); 371 /* Disable wake interrupt */ 372 mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(core_index), 373 APU_PCIL_CORE_X_IDS_WAKE_MASK); 374 375 pm_client_lock_release(); 376 } 377 } 378 379 /** 380 * pm_client_abort_suspend() - Client-specific abort-suspend actions. 381 * 382 * This function should contain any PU-specific actions 383 * required for aborting a prior suspend request. 384 */ 385 void pm_client_abort_suspend(void) 386 { 387 uint32_t cpu_id = plat_my_core_pos(); 388 uintptr_t val; 389 390 /* Enable interrupts at processor level (for current cpu) */ 391 gicv3_cpuif_enable(plat_my_core_pos()); 392 393 pm_client_lock_get(); 394 395 /* Clear powerdown request */ 396 val = read_cpu_pwrctrl_val(); 397 val &= ~CORE_PWRDN_EN_BIT_MASK; 398 write_cpu_pwrctrl_val(val); 399 400 isb(); 401 402 /* Disabled power down interrupt */ 403 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id), 404 APU_PCIL_CORE_X_IDS_POWER_MASK); 405 406 pm_client_lock_release(); 407 } 408