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
am62l_pwr_domain_on(u_register_t mpidr)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
am62l_pwr_domain_off(const psci_power_state_t * target_state)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
am62l_pwr_down_domain(const psci_power_state_t * target_state)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
am62l_pwr_domain_on_finish(const psci_power_state_t * target_state)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
am62l_system_reset(void)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
jump_to_atf_func(void * unused)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
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)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