Dhruva Gole | f95904f | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 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); |
Dhruva Gole | fd0e369 | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 35 | return PSCI_E_INTERN_FAIL; |
Dhruva Gole | f95904f | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 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); |
Dhruva Gole | fd0e369 | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 44 | return PSCI_E_INTERN_FAIL; |
Dhruva Gole | f95904f | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 45 | } |
| 46 | |
Dhruva Gole | fd0e369 | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 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; |
Dhruva Gole | f95904f | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 51 | } |
| 52 | |
Dhruva Gole | fd0e369 | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 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; |
Dhruva Gole | f95904f | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 61 | } |
| 62 | |
Dhruva Gole | fd0e369 | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 63 | /* |
| 64 | * TODO: Add the actual PM operation call |
| 65 | * to turn on the core here |
| 66 | */ |
| 67 | return PSCI_E_SUCCESS; |
Dhruva Gole | f95904f | 2025-03-24 13:05:23 +0530 | [diff] [blame] | 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_DEVICE_MANAGEMENT_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 | } |