blob: d265bb9b476512b8859d7cdee9fddc1481c08d0a [file] [log] [blame]
/*
* Copyright (c) 2018-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __TFTF_LIB_H__
#define __TFTF_LIB_H__
#ifndef __ASSEMBLY__
#include <arch.h>
#include <arch_helpers.h>
#include <stdbool.h>
#include <stdint.h>
/*
* Possible error codes for signaling the result of a test
* TEST_RESULT_MIN and TEST_RESULT_MAX are only used as bounds in the enum.
*/
typedef enum {
/*
* NA = Not applicable.
* Initial value for a test result.
* Used for CPUs that don't participate in the test.
*/
TEST_RESULT_NA = -1,
TEST_RESULT_MIN = 0,
TEST_RESULT_SKIPPED = TEST_RESULT_MIN,
TEST_RESULT_SUCCESS,
TEST_RESULT_FAIL,
TEST_RESULT_CRASHED,
TEST_RESULT_MAX
} test_result_t;
#define TEST_RESULT_IS_VALID(result) \
((result >= TEST_RESULT_MIN) && (result < TEST_RESULT_MAX))
/*
* PSCI Function Wrappers
*
* SMC calls to PSCI functions
*/
int32_t tftf_psci_cpu_on(u_register_t target_cpu,
uintptr_t entry_point_address,
u_register_t context_id);
int32_t tftf_psci_cpu_off(void);
int32_t tftf_psci_set_suspend_mode(uint32_t mode);
int32_t tftf_psci_affinity_info(u_register_t target_affinity,
uint32_t lowest_affinity_level);
int32_t tftf_psci_node_hw_state(u_register_t target_cpu, uint32_t power_level);
int32_t tftf_get_psci_feature_info(uint32_t psci_func_id);
u_register_t tftf_psci_stat_count(u_register_t target_cpu,
uint32_t power_state);
u_register_t tftf_psci_stat_residency(u_register_t target_cpu,
uint32_t power_state);
/*
* PSCI Helper functions
*/
/*
* Gets the context ID used when calling tftf_psci_cpu_on().
*/
u_register_t tftf_get_cpu_on_ctx_id(unsigned int core_pos);
/*
* Sets the context ID used when calling tftf_psci_cpu_on().
*/
void tftf_set_cpu_on_ctx_id(unsigned int core_pos, u_register_t context_id);
/*
* Gets the PSCI version of Trusted Firmware-A. The version number returned
* is a 32-bit unsigned integer, with the upper 16 bits denoting the major
* revision, and the lower 16 bits denoting the minor revision.
*/
unsigned int tftf_get_psci_version(void);
/*
* Returns 0 if version is not a valid PSCI version supported by TFTF.
* Otherwise it returns a value different of 0.
*/
int tftf_is_valid_psci_version(unsigned int version);
/*
* The function constructs a composite state_id up-to the specified
* affinity level querying the relevant state property from the platform.
* It chooses the first matching state property from the array returned
* by platform. In case the requested affinity level is not supported by
* the platform, then this function uses DUMMY_STATE_ID as the local state
* for that level. This allows the tests to construct composite state-id
* for invalid affinity levels as well. It returns the expected return
* value from CPU SUSPEND call.
*/
int tftf_psci_make_composite_state_id(uint32_t affinity_level,
uint32_t state_type, uint32_t *state_id);
/*
* This function composes the power state parameter in the right format
* needed by PSCI. The detection of the power state format is done during
* cold boot by tftf_detect_psci_pstate_format() function.
*/
uint32_t tftf_make_psci_pstate(uint32_t affinity_level,
uint32_t state_type,
uint32_t state_id);
/*
* Returns 1, if the EL3 software supports PSCI's original format state ID as
* NULL else returns zero
*/
unsigned int tftf_is_psci_state_id_null(void);
/*
* Returns 1, if the EL3 software supports PSCI's original state format else
* returns zero
*/
unsigned int tftf_is_psci_pstate_format_original(void);
/* Functions to wait for a specified number of ms or us */
void waitms(uint64_t ms);
void waitus(uint64_t us);
/*
* SMC calls take a function identifier and up to 7 arguments.
* Additionally, few SMC calls that originate from EL2 leverage the seventh
* argument explicitly. Given that TFTF runs in EL2, we need to be able to
* specify it.
*/
typedef struct {
/* Function identifier. Identifies which function is being invoked. */
uint32_t fid;
u_register_t arg1;
u_register_t arg2;
u_register_t arg3;
u_register_t arg4;
u_register_t arg5;
u_register_t arg6;
u_register_t arg7;
} smc_args;
/* SMC calls can return up to 8 register values */
typedef struct {
u_register_t ret0;
u_register_t ret1;
u_register_t ret2;
u_register_t ret3;
u_register_t ret4;
u_register_t ret5;
u_register_t ret6;
u_register_t ret7;
} smc_ret_values;
/*
* Trigger an SMC call.
*/
smc_ret_values tftf_smc(const smc_args *args);
/*
* Trigger an HVC call.
*/
typedef smc_args hvc_args;
typedef smc_ret_values hvc_ret_values;
hvc_ret_values tftf_hvc(const hvc_args *args);
/*
* Write a formatted string in the test output buffer.
* Just like the standard libc's printf() function, the string produced is under
* the control of a format string that specifies how subsequent arguments are
* converted.
*
* The string will appear in the test report.
* Use mp_printf() instead for volatile debug messages that are not meant to be
* stored into the test report.
* Note: The test output buffer referred here is a temporary buffer stored in
* RAM. This function doesn't write anything into NVM.
*
* Upon successful return, return the number of characters printed (not
* including the final '\0' character). If an output error is encountered,
* a negative value is returned. If the function is not able to print any
* character at all, this is considered as an output error. Note that a partial
* write (i.e. when the string is truncated) is not considered as an output
* error.
*/
__attribute__((format(printf, 1, 2)))
int tftf_testcase_printf(const char *format, ...);
/*
* This function is meant to be used by tests.
* It tells the framework that the test is going to reset the platform.
*
* It the test omits to call this function before resetting, the framework will
* consider the test has crashed upon resumption.
*/
void tftf_notify_reboot(void);
/*
* Returns 0 if the test function is executed for the first time,
* or 1 if the test rebooted the platform and the test function is being
* executed again.
* This function is used for tests that reboot the platform, so that they can
* execute different code paths on 1st execution and subsequent executions.
*/
unsigned int tftf_is_rebooted(void);
static inline unsigned int make_mpid(unsigned int clusterid,
#if PLAT_MAX_PE_PER_CPU > 1
unsigned int coreid,
unsigned int threadid)
#else
unsigned int coreid)
#endif
{
/*
* If MT bit is set then need to shift the affinities and also set the
* MT bit.
*/
if ((read_mpidr_el1() & MPIDR_MT_MASK) != 0)
return MPIDR_MT_MASK |
#if PLAT_MAX_PE_PER_CPU > 1
((threadid & MPIDR_AFFLVL_MASK) << MPIDR_AFF0_SHIFT) |
#endif
((coreid & MPIDR_AFFLVL_MASK) << MPIDR_AFF1_SHIFT) |
((clusterid & MPIDR_AFFLVL_MASK) << MPIDR_AFF2_SHIFT);
else
return ((coreid & MPIDR_AFFLVL_MASK) << MPIDR_AFF0_SHIFT) |
((clusterid & MPIDR_AFFLVL_MASK) << MPIDR_AFF1_SHIFT);
}
#endif /* __ASSEMBLY__ */
#endif /* __TFTF_LIB_H__ */