11abdc20bSDhruva Gole /* 21abdc20bSDhruva Gole * Copyright (c) 2025, Texas Instruments Incorporated - https://www.ti.com/ 31abdc20bSDhruva Gole * 41abdc20bSDhruva Gole * SPDX-License-Identifier: BSD-3-Clause 51abdc20bSDhruva Gole */ 61abdc20bSDhruva Gole 71abdc20bSDhruva Gole #include <assert.h> 81abdc20bSDhruva Gole #include <stdbool.h> 91abdc20bSDhruva Gole 101abdc20bSDhruva Gole #include <arch_helpers.h> 111abdc20bSDhruva Gole #include <common/debug.h> 121abdc20bSDhruva Gole #include <drivers/delay_timer.h> 131abdc20bSDhruva Gole #include <lib/el3_runtime/cpu_data.h> 141abdc20bSDhruva Gole #include <lib/mmio.h> 151abdc20bSDhruva Gole #include <lib/psci/psci.h> 161abdc20bSDhruva Gole #include <plat/common/platform.h> 171abdc20bSDhruva Gole #include <ti_sci.h> 181abdc20bSDhruva Gole #include <ti_sci_protocol.h> 191abdc20bSDhruva Gole 201abdc20bSDhruva Gole #include <k3_gicv3.h> 211abdc20bSDhruva Gole #include <platform_def.h> 221abdc20bSDhruva Gole 231abdc20bSDhruva Gole uintptr_t am62l_sec_entrypoint; 241abdc20bSDhruva Gole uintptr_t am62l_sec_entrypoint_glob; 251abdc20bSDhruva Gole void __aligned(16) jump_to_atf_func(void *unused); 261abdc20bSDhruva Gole 271abdc20bSDhruva Gole static int am62l_pwr_domain_on(u_register_t mpidr) 281abdc20bSDhruva Gole { 291abdc20bSDhruva Gole int32_t core, ret; 301abdc20bSDhruva Gole uint8_t proc_id; 311abdc20bSDhruva Gole 321abdc20bSDhruva Gole core = plat_core_pos_by_mpidr(mpidr); 331abdc20bSDhruva Gole if (core < 0) { 341abdc20bSDhruva Gole ERROR("Could not get target core id: %d\n", core); 3532302b44SDhruva Gole return PSCI_E_INTERN_FAIL; 361abdc20bSDhruva Gole } 371abdc20bSDhruva Gole 381abdc20bSDhruva Gole proc_id = (uint8_t)(PLAT_PROC_START_ID + (uint32_t)core); 391abdc20bSDhruva Gole 401abdc20bSDhruva Gole ret = ti_sci_proc_request(proc_id); 411abdc20bSDhruva Gole if (ret != 0) { 421abdc20bSDhruva Gole ERROR("Request for processor ID 0x%x failed: %d\n", 431abdc20bSDhruva Gole proc_id, ret); 4432302b44SDhruva Gole return PSCI_E_INTERN_FAIL; 451abdc20bSDhruva Gole } 461abdc20bSDhruva Gole 471abdc20bSDhruva Gole ret = ti_sci_proc_set_boot_cfg(proc_id, am62l_sec_entrypoint, 0, 0); 481abdc20bSDhruva Gole if (ret != 0) { 491abdc20bSDhruva Gole ERROR("Request to set core boot address failed: %d\n", ret); 5032302b44SDhruva Gole return PSCI_E_INTERN_FAIL; 511abdc20bSDhruva Gole } 521abdc20bSDhruva Gole 531abdc20bSDhruva Gole /* sanity check these are off before starting a core */ 541abdc20bSDhruva Gole ret = ti_sci_proc_set_boot_ctrl(proc_id, 551abdc20bSDhruva Gole 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ | 561abdc20bSDhruva Gole PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS | 571abdc20bSDhruva Gole PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM); 581abdc20bSDhruva Gole if (ret != 0) { 591abdc20bSDhruva Gole ERROR("Request to clear boot config failed: %d\n", ret); 6032302b44SDhruva Gole return PSCI_E_INTERN_FAIL; 611abdc20bSDhruva Gole } 621abdc20bSDhruva Gole 631abdc20bSDhruva Gole /* 641abdc20bSDhruva Gole * TODO: Add the actual PM operation call 651abdc20bSDhruva Gole * to turn on the core here 661abdc20bSDhruva Gole */ 6732302b44SDhruva Gole return PSCI_E_SUCCESS; 681abdc20bSDhruva Gole } 691abdc20bSDhruva Gole 701abdc20bSDhruva Gole static void am62l_pwr_domain_off(const psci_power_state_t *target_state) 711abdc20bSDhruva Gole { 721abdc20bSDhruva Gole /* At very least the local core should be powering down */ 731abdc20bSDhruva Gole assert(((target_state)->pwr_domain_state[MPIDR_AFFLVL0]) == PLAT_MAX_OFF_STATE); 741abdc20bSDhruva Gole 751abdc20bSDhruva Gole /* Prevent interrupts from spuriously waking up this cpu */ 761abdc20bSDhruva Gole k3_gic_cpuif_disable(); 771abdc20bSDhruva Gole 781abdc20bSDhruva Gole } 791abdc20bSDhruva Gole 801abdc20bSDhruva Gole static void am62l_pwr_down_domain(const psci_power_state_t *target_state) 811abdc20bSDhruva Gole { 821abdc20bSDhruva Gole /* TODO: Add the actual pm operation call to turn off the core */ 831abdc20bSDhruva Gole } 841abdc20bSDhruva Gole 851abdc20bSDhruva Gole void am62l_pwr_domain_on_finish(const psci_power_state_t *target_state) 861abdc20bSDhruva Gole { 871abdc20bSDhruva Gole k3_gic_pcpu_init(); 881abdc20bSDhruva Gole k3_gic_cpuif_enable(); 891abdc20bSDhruva Gole } 901abdc20bSDhruva Gole 911abdc20bSDhruva Gole static void am62l_system_reset(void) 921abdc20bSDhruva Gole { 93*8853eba6SDhruva Gole mmio_write_32(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR0_DEVICE_RESET_OFFSET, 941abdc20bSDhruva Gole 0x6); 951abdc20bSDhruva Gole 961abdc20bSDhruva Gole /* Wait for reset to complete for 500ms before printing error */ 971abdc20bSDhruva Gole mdelay(500); 981abdc20bSDhruva Gole 991abdc20bSDhruva Gole /* Ideally we should not reach here */ 1001abdc20bSDhruva Gole ERROR("%s: Failed to reset device\n", __func__); 1011abdc20bSDhruva Gole } 1021abdc20bSDhruva Gole 1031abdc20bSDhruva Gole static plat_psci_ops_t am62l_plat_psci_ops = { 1041abdc20bSDhruva Gole .pwr_domain_on = am62l_pwr_domain_on, 1051abdc20bSDhruva Gole .pwr_domain_off = am62l_pwr_domain_off, 1061abdc20bSDhruva Gole .pwr_domain_pwr_down = am62l_pwr_down_domain, 1071abdc20bSDhruva Gole .pwr_domain_on_finish = am62l_pwr_domain_on_finish, 1081abdc20bSDhruva Gole .system_reset = am62l_system_reset, 1091abdc20bSDhruva Gole }; 1101abdc20bSDhruva Gole 1111abdc20bSDhruva Gole void __aligned(16) jump_to_atf_func(void *unused) 1121abdc20bSDhruva Gole { 1131abdc20bSDhruva Gole /* 1141abdc20bSDhruva Gole * MISRA Deviation observed: 1151abdc20bSDhruva Gole * Rule 11.1 (MISRA C:2012) Prohibits conversion performed between a 1161abdc20bSDhruva Gole * pointer to a function and another incompatible type. 1171abdc20bSDhruva Gole * This conversion is required for handling secure boot entry points. 1181abdc20bSDhruva Gole * The conversion is safe as the address is verified before execution. 1191abdc20bSDhruva Gole */ 1201abdc20bSDhruva Gole void (*bl31_loc_warm_entry)(void) = (void *)am62l_sec_entrypoint_glob; 1211abdc20bSDhruva Gole 1221abdc20bSDhruva Gole bl31_loc_warm_entry(); 1231abdc20bSDhruva Gole } 1241abdc20bSDhruva Gole 1251abdc20bSDhruva Gole int plat_setup_psci_ops(uintptr_t sec_entrypoint, 1261abdc20bSDhruva Gole const plat_psci_ops_t **psci_ops) 1271abdc20bSDhruva Gole { 1281abdc20bSDhruva Gole am62l_sec_entrypoint_glob = sec_entrypoint; 1291abdc20bSDhruva Gole /* Note that boot vector reg in sec mmr requires 16B aligned start address */ 1301abdc20bSDhruva Gole am62l_sec_entrypoint = (uint64_t)(void *)&jump_to_atf_func; 1311abdc20bSDhruva Gole VERBOSE("am62l_sec_entrypoint = 0x%lx\n", am62l_sec_entrypoint); 1321abdc20bSDhruva Gole 1331abdc20bSDhruva Gole *psci_ops = &am62l_plat_psci_ops; 1341abdc20bSDhruva Gole 1351abdc20bSDhruva Gole return 0; 1361abdc20bSDhruva Gole } 137