1*1abdc20bSDhruva Gole /* 2*1abdc20bSDhruva Gole * Copyright (c) 2025, Texas Instruments Incorporated - https://www.ti.com/ 3*1abdc20bSDhruva Gole * 4*1abdc20bSDhruva Gole * SPDX-License-Identifier: BSD-3-Clause 5*1abdc20bSDhruva Gole */ 6*1abdc20bSDhruva Gole 7*1abdc20bSDhruva Gole #include <assert.h> 8*1abdc20bSDhruva Gole #include <stdbool.h> 9*1abdc20bSDhruva Gole 10*1abdc20bSDhruva Gole #include <arch_helpers.h> 11*1abdc20bSDhruva Gole #include <common/debug.h> 12*1abdc20bSDhruva Gole #include <drivers/delay_timer.h> 13*1abdc20bSDhruva Gole #include <lib/el3_runtime/cpu_data.h> 14*1abdc20bSDhruva Gole #include <lib/mmio.h> 15*1abdc20bSDhruva Gole #include <lib/psci/psci.h> 16*1abdc20bSDhruva Gole #include <plat/common/platform.h> 17*1abdc20bSDhruva Gole #include <ti_sci.h> 18*1abdc20bSDhruva Gole #include <ti_sci_protocol.h> 19*1abdc20bSDhruva Gole 20*1abdc20bSDhruva Gole #include <k3_gicv3.h> 21*1abdc20bSDhruva Gole #include <platform_def.h> 22*1abdc20bSDhruva Gole 23*1abdc20bSDhruva Gole uintptr_t am62l_sec_entrypoint; 24*1abdc20bSDhruva Gole uintptr_t am62l_sec_entrypoint_glob; 25*1abdc20bSDhruva Gole void __aligned(16) jump_to_atf_func(void *unused); 26*1abdc20bSDhruva Gole 27*1abdc20bSDhruva Gole static int am62l_pwr_domain_on(u_register_t mpidr) 28*1abdc20bSDhruva Gole { 29*1abdc20bSDhruva Gole int32_t core, ret; 30*1abdc20bSDhruva Gole uint8_t proc_id; 31*1abdc20bSDhruva Gole 32*1abdc20bSDhruva Gole core = plat_core_pos_by_mpidr(mpidr); 33*1abdc20bSDhruva Gole if (core < 0) { 34*1abdc20bSDhruva Gole ERROR("Could not get target core id: %d\n", core); 35*1abdc20bSDhruva Gole ret = PSCI_E_INTERN_FAIL; 36*1abdc20bSDhruva Gole } 37*1abdc20bSDhruva Gole 38*1abdc20bSDhruva Gole proc_id = (uint8_t)(PLAT_PROC_START_ID + (uint32_t)core); 39*1abdc20bSDhruva Gole 40*1abdc20bSDhruva Gole ret = ti_sci_proc_request(proc_id); 41*1abdc20bSDhruva Gole if (ret != 0) { 42*1abdc20bSDhruva Gole ERROR("Request for processor ID 0x%x failed: %d\n", 43*1abdc20bSDhruva Gole proc_id, ret); 44*1abdc20bSDhruva Gole ret = PSCI_E_INTERN_FAIL; 45*1abdc20bSDhruva Gole } 46*1abdc20bSDhruva Gole 47*1abdc20bSDhruva Gole if (ret != PSCI_E_INTERN_FAIL) { 48*1abdc20bSDhruva Gole ret = ti_sci_proc_set_boot_cfg(proc_id, am62l_sec_entrypoint, 0, 0); 49*1abdc20bSDhruva Gole if (ret != 0) { 50*1abdc20bSDhruva Gole ERROR("Request to set core boot address failed: %d\n", ret); 51*1abdc20bSDhruva Gole ret = PSCI_E_INTERN_FAIL; 52*1abdc20bSDhruva Gole } 53*1abdc20bSDhruva Gole } 54*1abdc20bSDhruva Gole 55*1abdc20bSDhruva Gole if (ret != PSCI_E_INTERN_FAIL) { 56*1abdc20bSDhruva Gole /* sanity check these are off before starting a core */ 57*1abdc20bSDhruva Gole ret = ti_sci_proc_set_boot_ctrl(proc_id, 58*1abdc20bSDhruva Gole 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ | 59*1abdc20bSDhruva Gole PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS | 60*1abdc20bSDhruva Gole PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM); 61*1abdc20bSDhruva Gole if (ret != 0) { 62*1abdc20bSDhruva Gole ERROR("Request to clear boot config failed: %d\n", ret); 63*1abdc20bSDhruva Gole ret = PSCI_E_INTERN_FAIL; 64*1abdc20bSDhruva Gole } 65*1abdc20bSDhruva Gole } 66*1abdc20bSDhruva Gole 67*1abdc20bSDhruva Gole if (ret != PSCI_E_INTERN_FAIL) { 68*1abdc20bSDhruva Gole /* 69*1abdc20bSDhruva Gole * TODO: Add the actual PM operation call 70*1abdc20bSDhruva Gole * to turn on the core here 71*1abdc20bSDhruva Gole */ 72*1abdc20bSDhruva Gole ret = PSCI_E_SUCCESS; 73*1abdc20bSDhruva Gole } 74*1abdc20bSDhruva Gole 75*1abdc20bSDhruva Gole return ret; 76*1abdc20bSDhruva Gole } 77*1abdc20bSDhruva Gole 78*1abdc20bSDhruva Gole static void am62l_pwr_domain_off(const psci_power_state_t *target_state) 79*1abdc20bSDhruva Gole { 80*1abdc20bSDhruva Gole /* At very least the local core should be powering down */ 81*1abdc20bSDhruva Gole assert(((target_state)->pwr_domain_state[MPIDR_AFFLVL0]) == PLAT_MAX_OFF_STATE); 82*1abdc20bSDhruva Gole 83*1abdc20bSDhruva Gole /* Prevent interrupts from spuriously waking up this cpu */ 84*1abdc20bSDhruva Gole k3_gic_cpuif_disable(); 85*1abdc20bSDhruva Gole 86*1abdc20bSDhruva Gole } 87*1abdc20bSDhruva Gole 88*1abdc20bSDhruva Gole static void am62l_pwr_down_domain(const psci_power_state_t *target_state) 89*1abdc20bSDhruva Gole { 90*1abdc20bSDhruva Gole /* TODO: Add the actual pm operation call to turn off the core */ 91*1abdc20bSDhruva Gole } 92*1abdc20bSDhruva Gole 93*1abdc20bSDhruva Gole void am62l_pwr_domain_on_finish(const psci_power_state_t *target_state) 94*1abdc20bSDhruva Gole { 95*1abdc20bSDhruva Gole k3_gic_pcpu_init(); 96*1abdc20bSDhruva Gole k3_gic_cpuif_enable(); 97*1abdc20bSDhruva Gole } 98*1abdc20bSDhruva Gole 99*1abdc20bSDhruva Gole static void am62l_system_reset(void) 100*1abdc20bSDhruva Gole { 101*1abdc20bSDhruva Gole mmio_write_32(WKUP_CTRL_MMR0_DEVICE_MANAGEMENT_BASE + WKUP_CTRL_MMR0_DEVICE_RESET_OFFSET, 102*1abdc20bSDhruva Gole 0x6); 103*1abdc20bSDhruva Gole 104*1abdc20bSDhruva Gole /* Wait for reset to complete for 500ms before printing error */ 105*1abdc20bSDhruva Gole mdelay(500); 106*1abdc20bSDhruva Gole 107*1abdc20bSDhruva Gole /* Ideally we should not reach here */ 108*1abdc20bSDhruva Gole ERROR("%s: Failed to reset device\n", __func__); 109*1abdc20bSDhruva Gole } 110*1abdc20bSDhruva Gole 111*1abdc20bSDhruva Gole static plat_psci_ops_t am62l_plat_psci_ops = { 112*1abdc20bSDhruva Gole .pwr_domain_on = am62l_pwr_domain_on, 113*1abdc20bSDhruva Gole .pwr_domain_off = am62l_pwr_domain_off, 114*1abdc20bSDhruva Gole .pwr_domain_pwr_down = am62l_pwr_down_domain, 115*1abdc20bSDhruva Gole .pwr_domain_on_finish = am62l_pwr_domain_on_finish, 116*1abdc20bSDhruva Gole .system_reset = am62l_system_reset, 117*1abdc20bSDhruva Gole }; 118*1abdc20bSDhruva Gole 119*1abdc20bSDhruva Gole void __aligned(16) jump_to_atf_func(void *unused) 120*1abdc20bSDhruva Gole { 121*1abdc20bSDhruva Gole /* 122*1abdc20bSDhruva Gole * MISRA Deviation observed: 123*1abdc20bSDhruva Gole * Rule 11.1 (MISRA C:2012) Prohibits conversion performed between a 124*1abdc20bSDhruva Gole * pointer to a function and another incompatible type. 125*1abdc20bSDhruva Gole * This conversion is required for handling secure boot entry points. 126*1abdc20bSDhruva Gole * The conversion is safe as the address is verified before execution. 127*1abdc20bSDhruva Gole */ 128*1abdc20bSDhruva Gole void (*bl31_loc_warm_entry)(void) = (void *)am62l_sec_entrypoint_glob; 129*1abdc20bSDhruva Gole 130*1abdc20bSDhruva Gole bl31_loc_warm_entry(); 131*1abdc20bSDhruva Gole } 132*1abdc20bSDhruva Gole 133*1abdc20bSDhruva Gole int plat_setup_psci_ops(uintptr_t sec_entrypoint, 134*1abdc20bSDhruva Gole const plat_psci_ops_t **psci_ops) 135*1abdc20bSDhruva Gole { 136*1abdc20bSDhruva Gole am62l_sec_entrypoint_glob = sec_entrypoint; 137*1abdc20bSDhruva Gole /* Note that boot vector reg in sec mmr requires 16B aligned start address */ 138*1abdc20bSDhruva Gole am62l_sec_entrypoint = (uint64_t)(void *)&jump_to_atf_func; 139*1abdc20bSDhruva Gole VERBOSE("am62l_sec_entrypoint = 0x%lx\n", am62l_sec_entrypoint); 140*1abdc20bSDhruva Gole 141*1abdc20bSDhruva Gole *psci_ops = &am62l_plat_psci_ops; 142*1abdc20bSDhruva Gole 143*1abdc20bSDhruva Gole return 0; 144*1abdc20bSDhruva Gole } 145