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 return 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 return PSCI_E_INTERN_FAIL; 45 } 46 47 ret = ti_sci_proc_set_boot_cfg(proc_id, am62l_sec_entrypoint, 0, 0); 48 if (ret != 0) { 49 ERROR("Request to set core boot address failed: %d\n", ret); 50 return PSCI_E_INTERN_FAIL; 51 } 52 53 /* sanity check these are off before starting a core */ 54 ret = ti_sci_proc_set_boot_ctrl(proc_id, 55 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ | 56 PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS | 57 PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM); 58 if (ret != 0) { 59 ERROR("Request to clear boot config failed: %d\n", ret); 60 return PSCI_E_INTERN_FAIL; 61 } 62 63 /* 64 * TODO: Add the actual PM operation call 65 * to turn on the core here 66 */ 67 return PSCI_E_SUCCESS; 68 } 69 70 static void am62l_pwr_domain_off(const psci_power_state_t *target_state) 71 { 72 /* At very least the local core should be powering down */ 73 assert(((target_state)->pwr_domain_state[MPIDR_AFFLVL0]) == PLAT_MAX_OFF_STATE); 74 75 /* Prevent interrupts from spuriously waking up this cpu */ 76 k3_gic_cpuif_disable(); 77 78 } 79 80 static void am62l_pwr_down_domain(const psci_power_state_t *target_state) 81 { 82 /* TODO: Add the actual pm operation call to turn off the core */ 83 } 84 85 void am62l_pwr_domain_on_finish(const psci_power_state_t *target_state) 86 { 87 k3_gic_pcpu_init(); 88 k3_gic_cpuif_enable(); 89 } 90 91 static void am62l_system_reset(void) 92 { 93 mmio_write_32(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR0_DEVICE_RESET_OFFSET, 94 0x6); 95 96 /* Wait for reset to complete for 500ms before printing error */ 97 mdelay(500); 98 99 /* Ideally we should not reach here */ 100 ERROR("%s: Failed to reset device\n", __func__); 101 } 102 103 static plat_psci_ops_t am62l_plat_psci_ops = { 104 .pwr_domain_on = am62l_pwr_domain_on, 105 .pwr_domain_off = am62l_pwr_domain_off, 106 .pwr_domain_pwr_down = am62l_pwr_down_domain, 107 .pwr_domain_on_finish = am62l_pwr_domain_on_finish, 108 .system_reset = am62l_system_reset, 109 }; 110 111 void __aligned(16) jump_to_atf_func(void *unused) 112 { 113 /* 114 * MISRA Deviation observed: 115 * Rule 11.1 (MISRA C:2012) Prohibits conversion performed between a 116 * pointer to a function and another incompatible type. 117 * This conversion is required for handling secure boot entry points. 118 * The conversion is safe as the address is verified before execution. 119 */ 120 void (*bl31_loc_warm_entry)(void) = (void *)am62l_sec_entrypoint_glob; 121 122 bl31_loc_warm_entry(); 123 } 124 125 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 126 const plat_psci_ops_t **psci_ops) 127 { 128 am62l_sec_entrypoint_glob = sec_entrypoint; 129 /* Note that boot vector reg in sec mmr requires 16B aligned start address */ 130 am62l_sec_entrypoint = (uint64_t)(void *)&jump_to_atf_func; 131 VERBOSE("am62l_sec_entrypoint = 0x%lx\n", am62l_sec_entrypoint); 132 133 *psci_ops = &am62l_plat_psci_ops; 134 135 return 0; 136 } 137