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