1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* 3 * Copyright (C) 2024, Charleye <wangkart@aliyun.com> 4 * All rights reserved. 5 */ 6 7 #include <assert.h> 8 #include <platform_def.h> 9 #include <lua_def.h> 10 11 #include <arch_helpers.h> 12 #include <common/debug.h> 13 #include <lib/psci/psci.h> 14 #include <lib/el3_runtime/cpu_data.h> 15 #include <plat/common/platform.h> 16 #include <drivers/arm/gicv3.h> 17 #include <drivers/arm/gic_common.h> 18 #include <lib/el3_runtime/context_mgmt.h> 19 #include <lib/mmio.h> 20 21 /* 22 * The secure entry point to be used on warm reset. 23 */ 24 static unsigned long secure_entrypoint; 25 26 /* Make composite power state parameter till power level 0 */ 27 #if PSCI_EXTENDED_STATE_ID 28 29 #define lua_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 30 (((lvl0_state) << PSTATE_ID_SHIFT) | \ 31 ((type) << PSTATE_TYPE_SHIFT)) 32 #else 33 #define lua_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 34 (((lvl0_state) << PSTATE_ID_SHIFT) | \ 35 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ 36 ((type) << PSTATE_TYPE_SHIFT)) 37 #endif /* PSCI_EXTENDED_STATE_ID */ 38 39 40 #define lua_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ 41 (((lvl1_state) << LUA_LOCAL_PSTATE_WIDTH) | \ 42 lua_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) 43 44 /* 45 * The table storing the valid idle power states. Ensure that the 46 * array entries are populated in ascending order of state-id to 47 * enable us to use binary search during power state validation. 48 * The table must be terminated by a NULL entry. 49 */ 50 static const unsigned int lua_pm_idle_states[] = { 51 /* State-id - 0x01 */ 52 lua_make_pwrstate_lvl1(LUA_LOCAL_STATE_RUN, LUA_LOCAL_STATE_RET, 53 MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY), 54 /* State-id - 0x02 */ 55 lua_make_pwrstate_lvl1(LUA_LOCAL_STATE_RUN, LUA_LOCAL_STATE_OFF, 56 MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN), 57 /* State-id - 0x22 */ 58 lua_make_pwrstate_lvl1(LUA_LOCAL_STATE_OFF, LUA_LOCAL_STATE_OFF, 59 MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN), 60 0, 61 }; 62 63 /** 64 * lua_validate_power_state() - Platform handler to check if power state is valid 65 * 66 * @power_state: power state prepares to go to. 67 * @req_state: power domain level specific local states 68 * 69 * This function is called by the PSCI implementation during the ``CPU_SUSPEND`` 70 * call to validate the ``power_state`` parameter of the PSCI API and if valid, 71 * populate it in ``req_state`` (second argument) array as power domain level 72 * specific local states. If the ``power_state`` is invalid, the platform must 73 * return PSCI_E_INVALID_PARAMS as error, which is propagated back to the 74 * normal world PSCI client. 75 * 76 * Return: PSCI_E_SUCCESS if success, error code otherwise. 77 */ 78 int lua_validate_power_state(unsigned int power_state, 79 psci_power_state_t *req_state) 80 { 81 unsigned int state_id; 82 int i; 83 84 assert(req_state); 85 86 /* 87 * Currently we are using a linear search for finding the matching 88 * entry in the idle power state array. This can be made a binary 89 * search if the number of entries justify the additional complexity. 90 */ 91 for (i = 0; !!lua_pm_idle_states[i]; i++) { 92 if (power_state == lua_pm_idle_states[i]) 93 break; 94 } 95 96 /* Return error if entry not found in the idle state array */ 97 if (!lua_pm_idle_states[i]) 98 return PSCI_E_INVALID_PARAMS; 99 100 i = 0; 101 state_id = psci_get_pstate_id(power_state); 102 103 /* Parse the State ID and populate the state info parameter */ 104 while (state_id) { 105 req_state->pwr_domain_state[i++] = state_id & 106 LUA_LOCAL_PSTATE_MASK; 107 state_id >>= LUA_LOCAL_PSTATE_WIDTH; 108 } 109 110 return PSCI_E_SUCCESS; 111 } 112 113 /** 114 * lua_validate_ns_entrypoint() - Platform handler to check ns_entrypoint 115 * 116 * @ns_entrypoint: entrypoint address to check 117 * 118 * This function need to check if the ns_entrypoint is in non-secure world. 119 * 120 * Return: PSCI_E_SUCCESS if success, error code otherwise. 121 */ 122 static int lua_validate_ns_entrypoint(uintptr_t entrypoint) 123 { 124 /* 125 * Check if the non secure entrypoint lies within the non 126 * secure DRAM. 127 */ 128 if ((entrypoint >= LUA_DRAM_BASE) && 129 (entrypoint < (LUA_DRAM_BASE + LUA_NS_DDR_SIZE))) 130 return PSCI_E_SUCCESS; 131 132 return PSCI_E_INVALID_ADDRESS; 133 } 134 135 /** 136 * lua_cpu_standby() - Put CPU to standy mode 137 * 138 * @cpu_state: local cpu state 139 * 140 * This function will put cpu into idle state, and will return when cpu wakeup. 141 * 142 * Return: void 143 */ 144 void lua_cpu_standby(plat_local_state_t cpu_state) 145 { 146 assert(cpu_state == LUA_LOCAL_STATE_RET); 147 148 /* 149 * Enter standby state 150 * dsb is good practice before using wfi to enter low power states 151 */ 152 dsb(); 153 wfi(); 154 } 155 156 /** 157 * lua_pwr_domain_on() - Power on a cpu. 158 * 159 * @mpidr: mpidr value for this cpu 160 * 161 * This will be call before cpu power on, need to take action to bring cpu on 162 * 163 * Return: PSCI_E_SUCCESS if success, error code otherwise 164 */ 165 static int lua_pwr_domain_on(u_register_t mpidr) 166 { 167 int rc = PSCI_E_SUCCESS; 168 unsigned pos = plat_core_pos_by_mpidr(mpidr); 169 uint64_t *hold_base = (uint64_t *)PLAT_LUA_HOLD_BASE; 170 uint64_t addr = CPU_SYSCTL_BASE + CA55_CORE_SW_RST_OFFSET; 171 uint64_t rvbar_addr = addr + 8; 172 uint32_t low = (uint32_t)secure_entrypoint; 173 uint32_t high = (uint32_t)(secure_entrypoint >> 32); 174 175 assert(pos < PLATFORM_CORE_COUNT); 176 177 hold_base[pos] = PLAT_LUA_HOLD_STATE_GO; 178 sev(); 179 180 mmio_write_32(rvbar_addr + pos * 8, low); 181 mmio_write_32(rvbar_addr + pos * 8 + 4, high); 182 183 mmio_clrbits_32(addr, BIT(pos)); 184 185 return rc; 186 } 187 188 /** 189 * lua_pwr_domain_off() - Power off a cpu. 190 * 191 * @target_state: CPU topological state 192 * 193 * This will be call before cpu power off, need to take action to put cpu off 194 * 195 * Return: void 196 */ 197 static void lua_pwr_domain_off(const psci_power_state_t *target_state) 198 { 199 lua_pwr_gic_off(); 200 } 201 202 /** 203 * lua_pwr_domain_suspend() - Put system into suspend state. 204 * 205 * @target_state: Platform coordinated target local power states 206 * 207 * Perform the platform specific actions to prepare to suspend the calling 208 * CPU and its higher parent power domain levels as indicated by the 209 * ``target_state`` (first argument). It is called by the PSCI ``CPU_SUSPEND`` 210 * API implementation. 211 * 212 * Return: void 213 */ 214 static void lua_pwr_domain_suspend(const psci_power_state_t *target_state) 215 { 216 assert(0); 217 } 218 219 void __dead2 plat_secondary_cold_boot_setup(void); 220 /** 221 * lua_pwr_down_wfi() - Powerdown the CPU 222 * 223 * @target_state: Platform coordinated target local power states 224 * 225 * Perform platform specific actions including the ``wfi`` invocation which 226 * allows the CPU to powerdown. 227 * 228 * Return: void 229 */ 230 static void __dead2 lua_pwr_down_wfi(const psci_power_state_t *target_state) 231 { 232 disable_mmu_el3(); 233 plat_secondary_cold_boot_setup(); 234 } 235 236 /** 237 * lua_pwr_domain_on_finish() - Platform handler when cpu is powered on. 238 * 239 * @target_state: Platform coordinated target local power states 240 * 241 * This function is called by the PSCI implementation after the calling CPU is 242 * powered on and released from reset in response to an earlier PSCI ``CPU_ON`` 243 * call. It performs the platform-specific setup required to initialize enough 244 * state for this CPU to enter the normal world and also provide secure runtime 245 * firmware services. 246 * 247 * Return: void 248 */ 249 static void lua_pwr_domain_on_finish(const psci_power_state_t *target_state) 250 { 251 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 252 LUA_LOCAL_STATE_OFF); 253 254 lua_pwr_gic_on_finish(); 255 } 256 257 /** 258 * lua_pwr_domain_suspend_finish() - Platform handler after wakeup. 259 * 260 * @target_state: Platform coordinated target local power states 261 * 262 * Performs the platform-specific setup required to restore the saved state for 263 * this CPU to resume execution in the normal world and also provide secure 264 * runtime firmware services. This function will need to restore Distributor, 265 * Redistributors or ITS context. 266 * 267 * Return: void 268 */ 269 static void lua_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 270 { 271 assert(0); 272 } 273 274 /** 275 * lua_system_off() - Platform handler to poweroff the system. 276 * 277 * Performs the platform-specific setup to power off the whole system. 278 * Due to we use fake shutdown for J5, this function just while (1) to wfi(). 279 * 280 * Return: void 281 */ 282 static void __dead2 lua_system_off(void) 283 { 284 panic(); 285 } 286 287 /** 288 * lua_system_reset() - Platform handler to reboot the system. 289 * 290 * Performs the platform-specific setup to reboot the whole system. 291 * We need to generated a wdt reset to reset the whole soc. In case of wdt 292 * trigger failed, going to panic(). 293 * 294 * Return: void 295 */ 296 static void __dead2 lua_system_reset(void) 297 { 298 panic(); 299 } 300 301 /** 302 * lua_psci_ops - j6 platform psci ops 303 */ 304 static plat_psci_ops_t lua_psci_ops = { 305 .cpu_standby = lua_cpu_standby, 306 .pwr_domain_on = lua_pwr_domain_on, 307 .pwr_domain_off = lua_pwr_domain_off, 308 .pwr_domain_suspend = lua_pwr_domain_suspend, 309 .pwr_domain_pwr_down_wfi = lua_pwr_down_wfi, 310 .pwr_domain_on_finish = lua_pwr_domain_on_finish, 311 .pwr_domain_suspend_finish = lua_pwr_domain_suspend_finish, 312 .system_off = lua_system_off, 313 .system_reset = lua_system_reset, 314 .validate_power_state = lua_validate_power_state, 315 .validate_ns_entrypoint = lua_validate_ns_entrypoint, 316 }; 317 318 /** 319 * plat_setup_psci_ops() - Platform handler to setup psci ops 320 * 321 * @sec_entrypoint: entry to going to after cpu powered on. 322 * @psci_ops: pointer to store psci ops. 323 * 324 * This function need to initialze 325 * 326 * Return: void. 327 */ 328 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 329 const plat_psci_ops_t **psci_ops) 330 { 331 uintptr_t *mailbox = (void *)PLAT_LUA_TRUSTED_MAILBOX_BASE; 332 333 *mailbox = sec_entrypoint; 334 secure_entrypoint = (unsigned long)sec_entrypoint; 335 336 assert(psci_ops); 337 *psci_ops = &lua_psci_ops; 338 339 return 0; 340 } 341