1cf48f49fSManish V Badarkhe /* 2cf48f49fSManish V Badarkhe * Copyright (c) 2025, Arm Limited. All rights reserved. 3cf48f49fSManish V Badarkhe * 4cf48f49fSManish V Badarkhe * SPDX-License-Identifier: BSD-3-Clause 5cf48f49fSManish V Badarkhe */ 6cf48f49fSManish V Badarkhe 7b9dee50cSManish V Badarkhe #include <plat/common/platform.h> 8b9dee50cSManish V Badarkhe #include <services/bl31_lfa.h> 9cf48f49fSManish V Badarkhe #include <services/lfa_svc.h> 10b9dee50cSManish V Badarkhe #include <services/rmmd_rmm_lfa.h> 11cf48f49fSManish V Badarkhe #include <smccc_helpers.h> 12cf48f49fSManish V Badarkhe 13b9dee50cSManish V Badarkhe static uint32_t lfa_component_count; 14b9dee50cSManish V Badarkhe static plat_lfa_component_info_t *lfa_components; 15b9dee50cSManish V Badarkhe static struct lfa_component_status current_activation; 16b9dee50cSManish V Badarkhe static bool is_lfa_initialized; 17b9dee50cSManish V Badarkhe 18b9dee50cSManish V Badarkhe void lfa_reset_activation(void) 19b9dee50cSManish V Badarkhe { 20b9dee50cSManish V Badarkhe current_activation.component_id = LFA_INVALID_COMPONENT; 21b9dee50cSManish V Badarkhe current_activation.prime_status = PRIME_NONE; 22b9dee50cSManish V Badarkhe } 23b9dee50cSManish V Badarkhe 24b9dee50cSManish V Badarkhe static bool lfa_initialize_components(void) 25b9dee50cSManish V Badarkhe { 26b9dee50cSManish V Badarkhe lfa_component_count = plat_lfa_get_components(&lfa_components); 27b9dee50cSManish V Badarkhe 28b9dee50cSManish V Badarkhe if (lfa_component_count == 0U || lfa_components == NULL) { 29b9dee50cSManish V Badarkhe /* unlikely to reach here */ 30b9dee50cSManish V Badarkhe ERROR("Invalid LFA component setup: count = 0 or components are NULL"); 31b9dee50cSManish V Badarkhe return false; 32b9dee50cSManish V Badarkhe } 33b9dee50cSManish V Badarkhe 34b9dee50cSManish V Badarkhe return true; 35b9dee50cSManish V Badarkhe } 36b9dee50cSManish V Badarkhe 37*06a6f296SManish V Badarkhe static uint64_t get_fw_activation_flags(uint32_t fw_seq_id) 38*06a6f296SManish V Badarkhe { 39*06a6f296SManish V Badarkhe const plat_lfa_component_info_t *comp = 40*06a6f296SManish V Badarkhe &lfa_components[fw_seq_id]; 41*06a6f296SManish V Badarkhe uint64_t flags = 0ULL; 42*06a6f296SManish V Badarkhe 43*06a6f296SManish V Badarkhe flags |= ((comp->activator == NULL ? 0ULL : 1ULL) 44*06a6f296SManish V Badarkhe << LFA_ACTIVATION_CAPABLE_SHIFT); 45*06a6f296SManish V Badarkhe flags |= (uint64_t)(comp->activation_pending) 46*06a6f296SManish V Badarkhe << LFA_ACTIVATION_PENDING_SHIFT; 47*06a6f296SManish V Badarkhe 48*06a6f296SManish V Badarkhe if (comp->activator != NULL) { 49*06a6f296SManish V Badarkhe flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL) 50*06a6f296SManish V Badarkhe << LFA_MAY_RESET_CPU_SHIFT); 51*06a6f296SManish V Badarkhe flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL) 52*06a6f296SManish V Badarkhe << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT); 53*06a6f296SManish V Badarkhe } 54*06a6f296SManish V Badarkhe 55*06a6f296SManish V Badarkhe return flags; 56*06a6f296SManish V Badarkhe } 57*06a6f296SManish V Badarkhe 58cf48f49fSManish V Badarkhe int lfa_setup(void) 59cf48f49fSManish V Badarkhe { 60b9dee50cSManish V Badarkhe is_lfa_initialized = lfa_initialize_components(); 61b9dee50cSManish V Badarkhe if (!is_lfa_initialized) { 62b9dee50cSManish V Badarkhe return -1; 63b9dee50cSManish V Badarkhe } 64b9dee50cSManish V Badarkhe 65b9dee50cSManish V Badarkhe lfa_reset_activation(); 66b9dee50cSManish V Badarkhe 67b9dee50cSManish V Badarkhe return 0; 68cf48f49fSManish V Badarkhe } 69cf48f49fSManish V Badarkhe 70cf48f49fSManish V Badarkhe uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, 71cf48f49fSManish V Badarkhe u_register_t x3, u_register_t x4, void *cookie, 72cf48f49fSManish V Badarkhe void *handle, u_register_t flags) 73cf48f49fSManish V Badarkhe { 74*06a6f296SManish V Badarkhe uint64_t retx1, retx2; 75*06a6f296SManish V Badarkhe uint8_t *uuid_p; 76*06a6f296SManish V Badarkhe uint32_t fw_seq_id = (uint32_t)x1; 77*06a6f296SManish V Badarkhe 78cf48f49fSManish V Badarkhe /** 79cf48f49fSManish V Badarkhe * TODO: Acquire serialization lock. 80cf48f49fSManish V Badarkhe */ 81b9dee50cSManish V Badarkhe 82b9dee50cSManish V Badarkhe if (!is_lfa_initialized) { 83b9dee50cSManish V Badarkhe return LFA_NOT_SUPPORTED; 84b9dee50cSManish V Badarkhe } 85b9dee50cSManish V Badarkhe 86cf48f49fSManish V Badarkhe switch (smc_fid) { 87cf48f49fSManish V Badarkhe case LFA_VERSION: 88cf48f49fSManish V Badarkhe SMC_RET1(handle, LFA_VERSION_VAL); 89cf48f49fSManish V Badarkhe break; 90cf48f49fSManish V Badarkhe 91cf48f49fSManish V Badarkhe case LFA_FEATURES: 92cf48f49fSManish V Badarkhe SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED); 93cf48f49fSManish V Badarkhe break; 94cf48f49fSManish V Badarkhe 95cf48f49fSManish V Badarkhe case LFA_GET_INFO: 96b9dee50cSManish V Badarkhe /** 97b9dee50cSManish V Badarkhe * The current specification limits this input parameter to be zero for 98b9dee50cSManish V Badarkhe * version 1.0 of LFA 99b9dee50cSManish V Badarkhe */ 100b9dee50cSManish V Badarkhe if (x1 == 0ULL) { 101b9dee50cSManish V Badarkhe SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0); 102b9dee50cSManish V Badarkhe } else { 103b9dee50cSManish V Badarkhe SMC_RET1(handle, LFA_INVALID_PARAMETERS); 104b9dee50cSManish V Badarkhe } 105cf48f49fSManish V Badarkhe break; 106cf48f49fSManish V Badarkhe 107cf48f49fSManish V Badarkhe case LFA_GET_INVENTORY: 108*06a6f296SManish V Badarkhe if (lfa_component_count == 0U) { 109*06a6f296SManish V Badarkhe SMC_RET1(handle, LFA_WRONG_STATE); 110*06a6f296SManish V Badarkhe } 111*06a6f296SManish V Badarkhe 112*06a6f296SManish V Badarkhe /* 113*06a6f296SManish V Badarkhe * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan 114*06a6f296SManish V Badarkhe * platform firmware and create a valid number of firmware components. 115*06a6f296SManish V Badarkhe */ 116*06a6f296SManish V Badarkhe if (fw_seq_id >= lfa_component_count) { 117*06a6f296SManish V Badarkhe SMC_RET1(handle, LFA_INVALID_PARAMETERS); 118*06a6f296SManish V Badarkhe } 119*06a6f296SManish V Badarkhe 120*06a6f296SManish V Badarkhe /* 121*06a6f296SManish V Badarkhe * grab the UUID of asked fw_seq_id and set the return UUID 122*06a6f296SManish V Badarkhe * variables 123*06a6f296SManish V Badarkhe */ 124*06a6f296SManish V Badarkhe uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid; 125*06a6f296SManish V Badarkhe memcpy(&retx1, uuid_p, sizeof(uint64_t)); 126*06a6f296SManish V Badarkhe memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t)); 127*06a6f296SManish V Badarkhe 128*06a6f296SManish V Badarkhe /* 129*06a6f296SManish V Badarkhe * check the given fw_seq_id's update available 130*06a6f296SManish V Badarkhe * and accordingly set the active_pending flag 131*06a6f296SManish V Badarkhe */ 132*06a6f296SManish V Badarkhe lfa_components[fw_seq_id].activation_pending = 133*06a6f296SManish V Badarkhe is_plat_lfa_activation_pending(fw_seq_id); 134*06a6f296SManish V Badarkhe 135*06a6f296SManish V Badarkhe INFO("Component %lu %s live activation:\n", x1, 136*06a6f296SManish V Badarkhe lfa_components[fw_seq_id].activator ? "supports" : 137*06a6f296SManish V Badarkhe "does not support"); 138*06a6f296SManish V Badarkhe 139*06a6f296SManish V Badarkhe if (lfa_components[fw_seq_id].activator != NULL) { 140*06a6f296SManish V Badarkhe INFO("Activation pending: %s\n", 141*06a6f296SManish V Badarkhe lfa_components[fw_seq_id].activation_pending ? "true" : "false"); 142*06a6f296SManish V Badarkhe } 143*06a6f296SManish V Badarkhe 144*06a6f296SManish V Badarkhe INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2); 145*06a6f296SManish V Badarkhe 146*06a6f296SManish V Badarkhe SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id)); 147*06a6f296SManish V Badarkhe 148cf48f49fSManish V Badarkhe break; 149cf48f49fSManish V Badarkhe 150cf48f49fSManish V Badarkhe case LFA_PRIME: 151cf48f49fSManish V Badarkhe break; 152cf48f49fSManish V Badarkhe 153cf48f49fSManish V Badarkhe case LFA_ACTIVATE: 154cf48f49fSManish V Badarkhe break; 155cf48f49fSManish V Badarkhe 156cf48f49fSManish V Badarkhe case LFA_CANCEL: 157cf48f49fSManish V Badarkhe break; 158cf48f49fSManish V Badarkhe 159cf48f49fSManish V Badarkhe default: 160cf48f49fSManish V Badarkhe WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid); 161cf48f49fSManish V Badarkhe SMC_RET1(handle, SMC_UNK); 162cf48f49fSManish V Badarkhe break; /* unreachable */ 163cf48f49fSManish V Badarkhe 164cf48f49fSManish V Badarkhe } 165cf48f49fSManish V Badarkhe 166cf48f49fSManish V Badarkhe SMC_RET1(handle, SMC_UNK); 167cf48f49fSManish V Badarkhe 168cf48f49fSManish V Badarkhe return 0; 169cf48f49fSManish V Badarkhe } 170