blob: b14f0f577d221d221452a7f6189731022901e57d [file] [log] [blame]
/*
* Copyright (c) 2025, Texas Instruments Incorporated - https://www.ti.com/
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/el3_runtime/cpu_data.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <plat/common/platform.h>
#include <ti_sci.h>
#include <ti_sci_protocol.h>
#include <k3_gicv3.h>
#include <platform_def.h>
uintptr_t am62l_sec_entrypoint;
uintptr_t am62l_sec_entrypoint_glob;
void __aligned(16) jump_to_atf_func(void *unused);
static int am62l_pwr_domain_on(u_register_t mpidr)
{
int32_t core, ret;
uint8_t proc_id;
core = plat_core_pos_by_mpidr(mpidr);
if (core < 0) {
ERROR("Could not get target core id: %d\n", core);
return PSCI_E_INTERN_FAIL;
}
proc_id = (uint8_t)(PLAT_PROC_START_ID + (uint32_t)core);
ret = ti_sci_proc_request(proc_id);
if (ret != 0) {
ERROR("Request for processor ID 0x%x failed: %d\n",
proc_id, ret);
return PSCI_E_INTERN_FAIL;
}
ret = ti_sci_proc_set_boot_cfg(proc_id, am62l_sec_entrypoint, 0, 0);
if (ret != 0) {
ERROR("Request to set core boot address failed: %d\n", ret);
return PSCI_E_INTERN_FAIL;
}
/* sanity check these are off before starting a core */
ret = ti_sci_proc_set_boot_ctrl(proc_id,
0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ |
PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS |
PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM);
if (ret != 0) {
ERROR("Request to clear boot config failed: %d\n", ret);
return PSCI_E_INTERN_FAIL;
}
/*
* TODO: Add the actual PM operation call
* to turn on the core here
*/
return PSCI_E_SUCCESS;
}
static void am62l_pwr_domain_off(const psci_power_state_t *target_state)
{
/* At very least the local core should be powering down */
assert(((target_state)->pwr_domain_state[MPIDR_AFFLVL0]) == PLAT_MAX_OFF_STATE);
/* Prevent interrupts from spuriously waking up this cpu */
k3_gic_cpuif_disable();
}
static void am62l_pwr_down_domain(const psci_power_state_t *target_state)
{
/* TODO: Add the actual pm operation call to turn off the core */
}
void am62l_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
k3_gic_pcpu_init();
k3_gic_cpuif_enable();
}
static void am62l_system_reset(void)
{
mmio_write_32(WKUP_CTRL_MMR0_DEVICE_MANAGEMENT_BASE + WKUP_CTRL_MMR0_DEVICE_RESET_OFFSET,
0x6);
/* Wait for reset to complete for 500ms before printing error */
mdelay(500);
/* Ideally we should not reach here */
ERROR("%s: Failed to reset device\n", __func__);
}
static plat_psci_ops_t am62l_plat_psci_ops = {
.pwr_domain_on = am62l_pwr_domain_on,
.pwr_domain_off = am62l_pwr_domain_off,
.pwr_domain_pwr_down = am62l_pwr_down_domain,
.pwr_domain_on_finish = am62l_pwr_domain_on_finish,
.system_reset = am62l_system_reset,
};
void __aligned(16) jump_to_atf_func(void *unused)
{
/*
* MISRA Deviation observed:
* Rule 11.1 (MISRA C:2012) Prohibits conversion performed between a
* pointer to a function and another incompatible type.
* This conversion is required for handling secure boot entry points.
* The conversion is safe as the address is verified before execution.
*/
void (*bl31_loc_warm_entry)(void) = (void *)am62l_sec_entrypoint_glob;
bl31_loc_warm_entry();
}
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
am62l_sec_entrypoint_glob = sec_entrypoint;
/* Note that boot vector reg in sec mmr requires 16B aligned start address */
am62l_sec_entrypoint = (uint64_t)(void *)&jump_to_atf_func;
VERBOSE("am62l_sec_entrypoint = 0x%lx\n", am62l_sec_entrypoint);
*psci_ops = &am62l_plat_psci_ops;
return 0;
}