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