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 */ 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 */ 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 /* Clear power down interrupt status before enabling */ 168 mmio_write_32(APU_PCIL_CORE_X_ISR_POWER_REG(cpu_id), 169 APU_PCIL_CORE_X_ISR_POWER_MASK); 170 /* Enable power down interrupt */ 171 mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id), 172 APU_PCIL_CORE_X_IEN_POWER_MASK); 173 /* Clear wakeup interrupt status before enabling */ 174 mmio_write_32(APU_PCIL_CORE_X_ISR_WAKE_REG(cpu_id), 175 APU_PCIL_CORE_X_ISR_WAKE_MASK); 176 /* Enable wake interrupt */ 177 mmio_write_32(APU_PCIL_CORE_X_IEN_WAKE_REG(cpu_id), 178 APU_PCIL_CORE_X_IEN_WAKE_MASK); 179 180 bakery_lock_release(&pm_client_secure_lock); 181 } 182 183 /** 184 * pm_get_cpuid() - get the local cpu ID for a global node ID 185 * @param nid node id of the processor 186 * 187 * @return the cpu ID (starting from 0) for the subsystem 188 */ 189 static uint32_t pm_get_cpuid(uint32_t nid) 190 { 191 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 192 if (pm_procs_all[i].node_id == nid) { 193 return i; 194 } 195 } 196 return UNDEFINED_CPUID; 197 } 198 199 /** 200 * pm_client_wakeup() - Client-specific wakeup actions 201 * 202 * This function should contain any PU-specific actions 203 * required for waking up another APU core 204 * 205 * @param proc Processor which need to wakeup 206 */ 207 void pm_client_wakeup(const struct pm_proc *proc) 208 { 209 uint32_t cpuid = pm_get_cpuid(proc->node_id); 210 uintptr_t val; 211 212 if (cpuid == UNDEFINED_CPUID) { 213 return; 214 } 215 216 bakery_lock_get(&pm_client_secure_lock); 217 218 /* Clear powerdown request */ 219 val = read_cpu_pwrctrl_val(); 220 val &= ~CORE_PWRDN_EN_BIT_MASK; 221 write_cpu_pwrctrl_val(val); 222 223 isb(); 224 225 /* Disabled power down interrupt */ 226 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpuid), 227 APU_PCIL_CORE_X_IDS_POWER_MASK); 228 /* Clear wakeup interrupt status before disabling */ 229 mmio_write_32(APU_PCIL_CORE_X_ISR_WAKE_REG(cpuid), 230 APU_PCIL_CORE_X_ISR_WAKE_MASK); 231 /* Disable wake interrupt */ 232 mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(cpuid), 233 APU_PCIL_CORE_X_IDS_WAKE_MASK); 234 235 bakery_lock_release(&pm_client_secure_lock); 236 } 237 238 /** 239 * pm_client_abort_suspend() - Client-specific abort-suspend actions 240 * 241 * This function should contain any PU-specific actions 242 * required for aborting a prior suspend request 243 */ 244 void pm_client_abort_suspend(void) 245 { 246 uint32_t cpu_id = plat_my_core_pos(); 247 uintptr_t val; 248 249 /* Enable interrupts at processor level (for current cpu) */ 250 gicv3_cpuif_enable(plat_my_core_pos()); 251 252 bakery_lock_get(&pm_client_secure_lock); 253 254 /* Clear powerdown request */ 255 val = read_cpu_pwrctrl_val(); 256 val &= ~CORE_PWRDN_EN_BIT_MASK; 257 write_cpu_pwrctrl_val(val); 258 259 isb(); 260 261 /* Disabled power down interrupt */ 262 mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id), 263 APU_PCIL_CORE_X_IDS_POWER_MASK); 264 265 bakery_lock_release(&pm_client_secure_lock); 266 } 267