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