diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
commit | be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b (patch) | |
tree | 779c248fb61c83f65d1f0dc867f2053d76b4e03a /plat/nvidia/tegra/soc/t194 | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.tar.xz arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.zip |
Adding upstream version 2.10.0+dfsg.upstream/2.10.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/nvidia/tegra/soc/t194')
17 files changed, 3758 insertions, 0 deletions
diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h new file mode 100644 index 0000000..ef16980 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MCE_PRIVATE_H +#define MCE_PRIVATE_H + +#include <stdbool.h> +#include <tegra_def.h> + +/******************************************************************************* + * Macros to prepare CSTATE info request + ******************************************************************************/ +/* Description of the parameters for UPDATE_CSTATE_INFO request */ +#define CLUSTER_CSTATE_MASK 0x7U +#define CLUSTER_CSTATE_SHIFT 0X0U +#define CLUSTER_CSTATE_UPDATE_BIT (1U << 7) +#define CCPLEX_CSTATE_MASK 0x7U +#define CCPLEX_CSTATE_SHIFT 8U +#define CCPLEX_CSTATE_UPDATE_BIT (1U << 15) +#define SYSTEM_CSTATE_MASK 0xFU +#define SYSTEM_CSTATE_SHIFT 16U +#define SYSTEM_CSTATE_UPDATE_BIT (1U << 23) +#define CSTATE_WAKE_MASK_UPDATE_BIT (1U << 31) +#define CSTATE_WAKE_MASK_SHIFT 32U +#define CSTATE_WAKE_MASK_CLEAR 0xFFFFFFFFU + +/******************************************************************************* + * Core ID mask (bits 3:0 in the online request) + ******************************************************************************/ +#define MCE_CORE_ID_MASK 0xFU + +/******************************************************************************* + * C-state statistics macros + ******************************************************************************/ +#define MCE_STAT_ID_SHIFT 16U + +/******************************************************************************* + * Security config macros + ******************************************************************************/ +#define STRICT_CHECKING_ENABLED_SET (1UL << 0) +#define STRICT_CHECKING_LOCKED_SET (1UL << 1) + +/* declarations for NVG handler functions */ +uint64_t nvg_get_version(void); +void nvg_set_wake_time(uint32_t wake_time); +void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex, + uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask); +int32_t nvg_set_cstate_stat_query_value(uint64_t data); +uint64_t nvg_get_cstate_stat_query_value(void); +int32_t nvg_is_sc7_allowed(void); +int32_t nvg_online_core(uint32_t core); +int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx); +int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time); +int32_t nvg_roc_clean_cache_trbits(void); +void nvg_enable_strict_checking_mode(void); +void nvg_verify_strict_checking_mode(void); +void nvg_system_shutdown(void); +void nvg_system_reboot(void); +void nvg_clear_hsm_corr_status(void); + +/* declarations for assembly functions */ +void nvg_set_request_data(uint64_t req, uint64_t data); +void nvg_set_request(uint64_t req); +uint64_t nvg_get_result(void); +uint64_t nvg_cache_clean(void); +uint64_t nvg_cache_clean_inval(void); +uint64_t nvg_cache_inval_all(void); + +/* MCE helper functions */ +void mce_enable_strict_checking(void); +void mce_verify_strict_checking(void); +void mce_system_shutdown(void); +void mce_system_reboot(void); +void mce_clear_hsm_corr_status(void); + +#endif /* MCE_PRIVATE_H */ diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/se.h b/plat/nvidia/tegra/soc/t194/drivers/include/se.h new file mode 100644 index 0000000..7de55a7 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/include/se.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SE_H +#define SE_H + +int32_t tegra_se_calculate_save_sha256(uint64_t src_addr, + uint32_t src_len_inbyte); +int32_t tegra_se_suspend(void); +void tegra_se_resume(void); + +#endif /* SE_H */ diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h b/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h new file mode 100644 index 0000000..ca74d2c --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/include/t194_nvg.h @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef T194_NVG_H +#define T194_NVG_H + +#include <lib/utils_def.h> + +/** + * t194_nvg.h - Header for the NVIDIA Generic interface (NVG). + * Official documentation for this interface is included as part + * of the T194 TRM. + */ + +/** + * Current version - Major version increments may break backwards + * compatibility and binary compatibility. Minor version increments + * occur when there is only new functionality. + */ +enum { + TEGRA_NVG_VERSION_MAJOR = U(6), + TEGRA_NVG_VERSION_MINOR = U(7) +}; + +typedef enum { + TEGRA_NVG_CHANNEL_VERSION = U(0), + TEGRA_NVG_CHANNEL_POWER_PERF = U(1), + TEGRA_NVG_CHANNEL_POWER_MODES = U(2), + TEGRA_NVG_CHANNEL_WAKE_TIME = U(3), + TEGRA_NVG_CHANNEL_CSTATE_INFO = U(4), + TEGRA_NVG_CHANNEL_CROSSOVER_C6_LOWER_BOUND = U(5), + TEGRA_NVG_CHANNEL_CROSSOVER_CC6_LOWER_BOUND = U(6), + TEGRA_NVG_CHANNEL_CROSSOVER_CG7_LOWER_BOUND = U(8), + TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_REQUEST = U(10), + TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_VALUE = U(11), + TEGRA_NVG_CHANNEL_NUM_CORES = U(20), + TEGRA_NVG_CHANNEL_UNIQUE_LOGICAL_ID = U(21), + TEGRA_NVG_CHANNEL_LOGICAL_TO_PHYSICAL_MAPPING = U(22), + TEGRA_NVG_CHANNEL_LOGICAL_TO_MPIDR = U(23), + TEGRA_NVG_CHANNEL_SHUTDOWN = U(42), + TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = U(43), + TEGRA_NVG_CHANNEL_ONLINE_CORE = U(44), + TEGRA_NVG_CHANNEL_CC3_CTRL = U(45), + TEGRA_NVG_CHANNEL_CCPLEX_CACHE_CONTROL = U(49), + TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC = U(50), + TEGRA_NVG_CHANNEL_HSM_ERROR_CTRL = U(53), + TEGRA_NVG_CHANNEL_SECURITY_CONFIG = U(54), + TEGRA_NVG_CHANNEL_DEBUG_CONFIG = U(55), + TEGRA_NVG_CHANNEL_DDA_SNOC_MCF = U(56), + TEGRA_NVG_CHANNEL_DDA_MCF_ORD1 = U(57), + TEGRA_NVG_CHANNEL_DDA_MCF_ORD2 = U(58), + TEGRA_NVG_CHANNEL_DDA_MCF_ORD3 = U(59), + TEGRA_NVG_CHANNEL_DDA_MCF_ISO = U(60), + TEGRA_NVG_CHANNEL_DDA_MCF_SISO = U(61), + TEGRA_NVG_CHANNEL_DDA_MCF_NISO = U(62), + TEGRA_NVG_CHANNEL_DDA_MCF_NISO_REMOTE = U(63), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_ISO = U(64), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_SISO = U(65), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_NISO = U(66), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_NISO_REMOTE = U(67), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3FILL = U(68), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3WR = U(69), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_RSP_L3RD_DMA = U(70), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_RSP_MCFRD_DMA = U(71), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_GLOBAL = U(72), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_LL = U(73), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3D = U(74), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_FCM_RD = U(75), + TEGRA_NVG_CHANNEL_DDA_L3CTRL_FCM_WR = U(76), + TEGRA_NVG_CHANNEL_DDA_SNOC_GLOBAL_CTRL = U(77), + TEGRA_NVG_CHANNEL_DDA_SNOC_CLIENT_REQ_CTRL = U(78), + TEGRA_NVG_CHANNEL_DDA_SNOC_CLIENT_REPLENTISH_CTRL = U(79), + TEGRA_NVG_CHANNEL_RT_SAFE_MASK = U(80), + TEGRA_NVG_CHANNEL_RT_WINDOW_US = U(81), + TEGRA_NVG_CHANNEL_RT_FWD_PROGRESS_US = U(82), + + TEGRA_NVG_CHANNEL_LAST_INDEX +} tegra_nvg_channel_id_t; + +typedef enum { + NVG_STAT_QUERY_SC7_ENTRIES = U(1), + NVG_STAT_QUERY_CC6_ENTRIES = U(6), + NVG_STAT_QUERY_CG7_ENTRIES = U(7), + NVG_STAT_QUERY_C6_ENTRIES = U(10), + NVG_STAT_QUERY_C7_ENTRIES = U(14), + NVG_STAT_QUERY_SC7_RESIDENCY_SUM = U(32), + NVG_STAT_QUERY_CC6_RESIDENCY_SUM = U(41), + NVG_STAT_QUERY_CG7_RESIDENCY_SUM = U(46), + NVG_STAT_QUERY_C6_RESIDENCY_SUM = U(51), + NVG_STAT_QUERY_C7_RESIDENCY_SUM = U(56), + NVG_STAT_QUERY_SC7_ENTRY_TIME_SUM = U(60), + NVG_STAT_QUERY_CC6_ENTRY_TIME_SUM = U(61), + NVG_STAT_QUERY_CG7_ENTRY_TIME_SUM = U(62), + NVG_STAT_QUERY_C6_ENTRY_TIME_SUM = U(63), + NVG_STAT_QUERY_C7_ENTRY_TIME_SUM = U(64), + NVG_STAT_QUERY_SC7_EXIT_TIME_SUM = U(70), + NVG_STAT_QUERY_CC6_EXIT_TIME_SUM = U(71), + NVG_STAT_QUERY_CG7_EXIT_TIME_SUM = U(72), + NVG_STAT_QUERY_C6_EXIT_TIME_SUM = U(73), + NVG_STAT_QUERY_C7_EXIT_TIME_SUM = U(74), + NVG_STAT_QUERY_SC7_ENTRY_LAST = U(80), + NVG_STAT_QUERY_CC6_ENTRY_LAST = U(81), + NVG_STAT_QUERY_CG7_ENTRY_LAST = U(82), + NVG_STAT_QUERY_C6_ENTRY_LAST = U(83), + NVG_STAT_QUERY_C7_ENTRY_LAST = U(84), + NVG_STAT_QUERY_SC7_EXIT_LAST = U(90), + NVG_STAT_QUERY_CC6_EXIT_LAST = U(91), + NVG_STAT_QUERY_CG7_EXIT_LAST = U(92), + NVG_STAT_QUERY_C6_EXIT_LAST = U(93), + NVG_STAT_QUERY_C7_EXIT_LAST = U(94) + +} tegra_nvg_stat_query_t; + +typedef enum { + TEGRA_NVG_CORE_C0 = U(0), + TEGRA_NVG_CORE_C1 = U(1), + TEGRA_NVG_CORE_C6 = U(6), + TEGRA_NVG_CORE_C7 = U(7), + TEGRA_NVG_CORE_WARMRSTREQ = U(8) +} tegra_nvg_core_sleep_state_t; + +typedef enum { + TEGRA_NVG_SHUTDOWN = U(0), + TEGRA_NVG_REBOOT = U(1) +} tegra_nvg_shutdown_reboot_state_t; + +typedef enum { + TEGRA_NVG_CLUSTER_CC0 = U(0), + TEGRA_NVG_CLUSTER_AUTO_CC1 = U(1), + TEGRA_NVG_CLUSTER_CC6 = U(6) +} tegra_nvg_cluster_sleep_state_t; + +typedef enum { + TEGRA_NVG_CG_CG0 = U(0), + TEGRA_NVG_CG_CG7 = U(7) +} tegra_nvg_cluster_group_sleep_state_t; + +typedef enum { + TEGRA_NVG_SYSTEM_SC0 = U(0), + TEGRA_NVG_SYSTEM_SC7 = U(7), + TEGRA_NVG_SYSTEM_SC8 = U(8) +} tegra_nvg_system_sleep_state_t; + +// --------------------------------------------------------------------------- +// NVG Data subformats +// --------------------------------------------------------------------------- + +typedef union { + uint64_t flat; + struct nvg_version_channel_t { + uint32_t minor_version : U(32); + uint32_t major_version : U(32); + } bits; +} nvg_version_data_t; + +typedef union { + uint64_t flat; + struct { + uint32_t perf_per_watt : U(1); + uint32_t reserved_31_1 : U(31); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_power_perf_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t low_battery : U(1); + uint32_t reserved_1_1 : U(1); + uint32_t battery_save : U(1); + uint32_t reserved_31_3 : U(29); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_power_modes_channel_t; + +typedef union nvg_channel_1_data_u { + uint64_t flat; + struct nvg_channel_1_data_s { + uint32_t perf_per_watt_mode : U(1); + uint32_t reserved_31_1 : U(31); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_channel_1_data_t; + +typedef union { + uint64_t flat; + struct { + uint32_t gpu_ways : U(5); + uint32_t reserved_7_5 : U(3); + uint32_t gpu_only_ways : U(5); + uint32_t reserved_31_13 : U(19); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_ccplex_cache_control_channel_t; + +typedef union nvg_channel_2_data_u { + uint64_t flat; + struct nvg_channel_2_data_s { + uint32_t reserved_1_0 : U(2); + uint32_t battery_saver_mode : U(1); + uint32_t reserved_31_3 : U(29); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_channel_2_data_t; + +typedef union { + uint64_t flat; + struct { + uint32_t wake_time : U(32); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_wake_time_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t cluster_state : U(3); + uint32_t reserved_6_3 : U(4); + uint32_t update_cluster : U(1); + uint32_t cg_cstate : U(3); + uint32_t reserved_14_11 : U(4); + uint32_t update_cg : U(1); + uint32_t system_cstate : U(4); + uint32_t reserved_22_20 : U(3); + uint32_t update_system : U(1); + uint32_t reserved_30_24 : U(7); + uint32_t update_wake_mask : U(1); + union { + uint32_t flat : U(32); + struct { + uint32_t vfiq : U(1); + uint32_t virq : U(1); + uint32_t fiq : U(1); + uint32_t irq : U(1); + uint32_t serror : U(1); + uint32_t reserved_10_5 : U(6); + uint32_t fiqout : U(1); + uint32_t irqout : U(1); + uint32_t reserved_31_13 : U(19); + } carmel; + } wake_mask; + } bits; +} nvg_cstate_info_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t crossover_value : U(32); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_lower_bound_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t unit_id : U(4); + uint32_t reserved_15_4 : U(12); + uint32_t stat_id : U(16); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_cstate_stat_query_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t num_cores : U(4); + uint32_t reserved_31_4 : U(28); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_num_cores_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t unique_core_id : U(3); + uint32_t reserved_31_3 : U(29); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_unique_logical_id_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t lcore0_pcore_id : U(4); + uint32_t lcore1_pcore_id : U(4); + uint32_t lcore2_pcore_id : U(4); + uint32_t lcore3_pcore_id : U(4); + uint32_t lcore4_pcore_id : U(4); + uint32_t lcore5_pcore_id : U(4); + uint32_t lcore6_pcore_id : U(4); + uint32_t lcore7_pcore_id : U(4); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_logical_to_physical_mappings_channel_t; + +typedef union { + uint64_t flat; + struct nvg_logical_to_mpidr_channel_write_t { + uint32_t lcore_id : U(3); + uint32_t reserved_31_3 : U(29); + uint32_t reserved_63_32 : U(32); + } write; + struct nvg_logical_to_mpidr_channel_read_t { + uint32_t mpidr : U(32); + uint32_t reserved_63_32 : U(32); + } read; +} nvg_logical_to_mpidr_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t is_sc7_allowed : U(1); + uint32_t reserved_31_1 : U(31); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_is_sc7_allowed_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t core_id : U(4); + uint32_t reserved_31_4 : U(28); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_core_online_channel_t; + +typedef union { + uint64_t flat; + struct { + uint32_t freq_req : U(9); + uint32_t reserved_30_9 : U(22); + uint32_t enable : U(1); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_cc3_control_channel_t; + +typedef enum { + TEGRA_NVG_CHANNEL_UPDATE_GSC_ALL = U(0), + TEGRA_NVG_CHANNEL_UPDATE_GSC_NVDEC = U(1), + TEGRA_NVG_CHANNEL_UPDATE_GSC_WPR1 = U(2), + TEGRA_NVG_CHANNEL_UPDATE_GSC_WPR2 = U(3), + TEGRA_NVG_CHANNEL_UPDATE_GSC_TSECA = U(4), + TEGRA_NVG_CHANNEL_UPDATE_GSC_TSECB = U(5), + TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP = U(6), + TEGRA_NVG_CHANNEL_UPDATE_GSC_APE = U(7), + TEGRA_NVG_CHANNEL_UPDATE_GSC_SPE = U(8), + TEGRA_NVG_CHANNEL_UPDATE_GSC_SCE = U(9), + TEGRA_NVG_CHANNEL_UPDATE_GSC_APR = U(10), + TEGRA_NVG_CHANNEL_UPDATE_GSC_TZRAM = U(11), + TEGRA_NVG_CHANNEL_UPDATE_GSC_IPC_SE_TSEC = U(12), + TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_RCE = U(13), + TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_MCE = U(14), + TEGRA_NVG_CHANNEL_UPDATE_GSC_SE_SC7 = U(15), + TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_SPE = U(16), + TEGRA_NVG_CHANNEL_UPDATE_GSC_RCE = U(17), + TEGRA_NVG_CHANNEL_UPDATE_GSC_CPU_TZ_TO_BPMP = U(18), + TEGRA_NVG_CHANNEL_UPDATE_GSC_VM_ENCR1 = U(19), + TEGRA_NVG_CHANNEL_UPDATE_GSC_CPU_NS_TO_BPMP = U(20), + TEGRA_NVG_CHANNEL_UPDATE_GSC_OEM_SC7 = U(21), + TEGRA_NVG_CHANNEL_UPDATE_GSC_IPC_SE_SPE_SCE_BPMP = U(22), + TEGRA_NVG_CHANNEL_UPDATE_GSC_SC7_RESUME_FW = U(23), + TEGRA_NVG_CHANNEL_UPDATE_GSC_CAMERA_TASKLIST = U(24), + TEGRA_NVG_CHANNEL_UPDATE_GSC_XUSB = U(25), + TEGRA_NVG_CHANNEL_UPDATE_GSC_CV = U(26), + TEGRA_NVG_CHANNEL_UPDATE_GSC_VM_ENCR2 = U(27), + TEGRA_NVG_CHANNEL_UPDATE_GSC_HYPERVISOR_SW = U(28), + TEGRA_NVG_CHANNEL_UPDATE_GSC_SMMU_PAGETABLES = U(29), + TEGRA_NVG_CHANNEL_UPDATE_GSC_30 = U(30), + TEGRA_NVG_CHANNEL_UPDATE_GSC_31 = U(31), + TEGRA_NVG_CHANNEL_UPDATE_GSC_TZ_DRAM = U(32), + TEGRA_NVG_CHANNEL_UPDATE_GSC_NVLINK = U(33), + TEGRA_NVG_CHANNEL_UPDATE_GSC_SBS = U(34), + TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR = U(35), + TEGRA_NVG_CHANNEL_UPDATE_GSC_LAST_INDEX +} tegra_nvg_channel_update_gsc_gsc_enum_t; + +typedef union { + uint64_t flat; + struct { + uint32_t gsc_enum : U(16); + uint32_t reserved_31_16 : U(16); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_update_ccplex_gsc_channel_t; + +typedef union { + uint64_t flat; + struct nvg_security_config_channel_t { + uint32_t strict_checking_enabled : U(1); + uint32_t strict_checking_locked : U(1); + uint32_t reserved_31_2 : U(30); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_security_config_t; + +typedef union { + uint64_t flat; + struct nvg_shutdown_channel_t { + uint32_t reboot : U(1); + uint32_t reserved_31_1 : U(31); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_shutdown_t; + +typedef union { + uint64_t flat; + struct nvg_debug_config_channel_t { + uint32_t enter_debug_state_on_mca : U(1); + uint32_t reserved_31_1 : U(31); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_debug_config_t; + +typedef union { + uint64_t flat; + struct { + uint32_t uncorr : U(1); + uint32_t corr : U(1); + uint32_t reserved_31_2 : U(30); + uint32_t reserved_63_32 : U(32); + } bits; +} nvg_hsm_error_ctrl_channel_t; + +extern nvg_debug_config_t nvg_debug_config; + +#endif /* T194_NVG_H */ diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S b/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S new file mode 100644 index 0000000..3c47208 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> + + .globl nvg_set_request_data + .globl nvg_set_request + .globl nvg_get_result + .globl nvg_cache_clean + .globl nvg_cache_clean_inval + .globl nvg_cache_inval_all + +/* void nvg_set_request_data(uint64_t req, uint64_t data) */ +func nvg_set_request_data + msr s3_0_c15_c1_2, x0 + msr s3_0_c15_c1_3, x1 + ret +endfunc nvg_set_request_data + +/* void nvg_set_request(uint64_t req) */ +func nvg_set_request + msr s3_0_c15_c1_2, x0 + ret +endfunc nvg_set_request + +/* uint64_t nvg_get_result(void) */ +func nvg_get_result + mrs x0, s3_0_c15_c1_3 + ret +endfunc nvg_get_result + +/* uint64_t nvg_cache_clean(void) */ +func nvg_cache_clean + mrs x0, s3_0_c15_c3_5 + ret +endfunc nvg_cache_clean + +/* uint64_t nvg_cache_clean_inval(void) */ +func nvg_cache_clean_inval + mrs x0, s3_0_c15_c3_6 + ret +endfunc nvg_cache_clean_inval + +/* uint64_t nvg_cache_inval_all(void) */ +func nvg_cache_inval_all + mrs x0, s3_0_c15_c3_7 + ret +endfunc nvg_cache_inval_all
\ No newline at end of file diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c new file mode 100644 index 0000000..af1c0aa --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <common/bl_common.h> +#include <context.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <common/debug.h> +#include <denver.h> +#include <mce.h> +#include <mce_private.h> +#include <platform_def.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> +#include <t194_nvg.h> +#include <tegra_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +/* Handler to check if MCE firmware is supported */ +static bool mce_firmware_not_supported(void) +{ + bool status; + + /* these platforms do not load MCE firmware */ + status = tegra_platform_is_linsim() || tegra_platform_is_qt() || + tegra_platform_is_virt_dev_kit(); + + return status; +} + +/******************************************************************************* + * Common handler for all MCE commands + ******************************************************************************/ +int32_t mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1, + uint64_t arg2) +{ + int32_t ret = 0; + + switch (cmd) { + case (uint64_t)MCE_CMD_ENTER_CSTATE: + ret = nvg_enter_cstate((uint32_t)arg0, (uint32_t)arg1); + if (ret < 0) { + ERROR("%s: enter_cstate failed(%d)\n", __func__, ret); + } + + break; + + case (uint64_t)MCE_CMD_IS_SC7_ALLOWED: + ret = nvg_is_sc7_allowed(); + if (ret < 0) { + ERROR("%s: is_sc7_allowed failed(%d)\n", __func__, ret); + } + + break; + + case (uint64_t)MCE_CMD_ONLINE_CORE: + ret = nvg_online_core((uint32_t)arg0); + if (ret < 0) { + ERROR("%s: online_core failed(%d)\n", __func__, ret); + } + + break; + + default: + ERROR("unknown MCE command (%" PRIu64 ")\n", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +/******************************************************************************* + * Handler to update carveout values for Video Memory Carveout region + ******************************************************************************/ +int32_t mce_update_gsc_videomem(void) +{ + int32_t ret; + + /* + * MCE firmware is not running on simulation platforms. + */ + if (mce_firmware_not_supported()) { + ret = -EINVAL; + } else { + ret = nvg_update_ccplex_gsc((uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR); + } + + return ret; +} + +/******************************************************************************* + * Handler to update carveout values for TZDRAM aperture + ******************************************************************************/ +int32_t mce_update_gsc_tzdram(void) +{ + int32_t ret; + + /* + * MCE firmware is not running on simulation platforms. + */ + if (mce_firmware_not_supported()) { + ret = -EINVAL; + } else { + ret = nvg_update_ccplex_gsc((uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_TZ_DRAM); + } + + return ret; +} + +/******************************************************************************* + * Handler to issue the UPDATE_CSTATE_INFO request + ******************************************************************************/ +void mce_update_cstate_info(const mce_cstate_info_t *cstate) +{ + /* issue the UPDATE_CSTATE_INFO request */ + nvg_update_cstate_info(cstate->cluster, cstate->ccplex, cstate->system, + cstate->wake_mask, cstate->update_wake_mask); +} + +/******************************************************************************* + * Handler to read the MCE firmware version and check if it is compatible + * with interface header the BL3-1 was compiled against + ******************************************************************************/ +void mce_verify_firmware_version(void) +{ + uint64_t version; + uint32_t major, minor; + + /* + * MCE firmware is not running on simulation platforms. + */ + if (mce_firmware_not_supported()) { + return; + } + + /* + * Read the MCE firmware version and extract the major and minor + * version fields + */ + version = nvg_get_version(); + minor = (uint32_t)version; + major = (uint32_t)(version >> 32); + + INFO("MCE Version - HW=%u:%u, SW=%u:%u\n", major, minor, + TEGRA_NVG_VERSION_MAJOR, TEGRA_NVG_VERSION_MINOR); + + /* + * Verify that the MCE firmware version and the interface header + * match + */ + if (major != (uint32_t)TEGRA_NVG_VERSION_MAJOR) { + ERROR("MCE major version mismatch\n"); + panic(); + } + + if (minor < (uint32_t)TEGRA_NVG_VERSION_MINOR) { + ERROR("MCE minor version mismatch\n"); + panic(); + } +} + +#if ENABLE_STRICT_CHECKING_MODE +/******************************************************************************* + * Handler to enable the strict checking mode + ******************************************************************************/ +void mce_enable_strict_checking(void) +{ + uint64_t sctlr = read_sctlr_el3(); + int32_t ret = 0; + + if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) { + /* + * Step1: TZ-DRAM and TZRAM should be setup before the MMU is + * enabled. + * + * The common code makes sure that TZDRAM/TZRAM are already + * enabled before calling into this handler. If this is not the + * case, the following sequence must be executed before moving + * on to step 2. + * + * tlbialle1is(); + * tlbialle3is(); + * dsbsy(); + * isb(); + * + */ + if ((sctlr & (uint64_t)SCTLR_M_BIT) == (uint64_t)SCTLR_M_BIT) { + tlbialle1is(); + tlbialle3is(); + dsbsy(); + isb(); + } + + /* + * Step2: SCF flush - Clean and invalidate caches and clear the + * TR-bits + */ + ret = nvg_roc_clean_cache_trbits(); + if (ret < 0) { + ERROR("%s: flush cache_trbits failed(%d)\n", __func__, + ret); + return; + } + + /* + * Step3: Issue the SECURITY_CONFIG request to MCE to enable + * strict checking mode. + */ + nvg_enable_strict_checking_mode(); + } +} +void mce_verify_strict_checking(void) +{ + bool is_silicon = tegra_platform_is_silicon(); + bool is_fpga = tegra_platform_is_fpga(); + + if (is_silicon || is_fpga) { + nvg_verify_strict_checking_mode(); + } +} +#endif + +/******************************************************************************* + * Handler to power down the entire system + ******************************************************************************/ +void mce_system_shutdown(void) +{ + nvg_system_shutdown(); +} + +/******************************************************************************* + * Handler to reboot the entire system + ******************************************************************************/ +void mce_system_reboot(void) +{ + nvg_system_reboot(); +} + +/******************************************************************************* + * Handler to clear CCPLEX->HSM correctable RAS error signal. + ******************************************************************************/ +void mce_clear_hsm_corr_status(void) +{ + nvg_clear_hsm_corr_status(); +} diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c new file mode 100644 index 0000000..f76ab14 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <denver.h> +#include <lib/mmio.h> + +#include <mce_private.h> +#include <platform_def.h> +#include <t194_nvg.h> +#include <tegra_private.h> + +#define ID_AFR0_EL1_CACHE_OPS_SHIFT U(12) +#define ID_AFR0_EL1_CACHE_OPS_MASK U(0xF) +/* + * Reports the major and minor version of this interface. + * + * NVGDATA[0:31]: SW(R) Minor Version + * NVGDATA[32:63]: SW(R) Major Version + */ +uint64_t nvg_get_version(void) +{ + nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_VERSION); + + return (uint64_t)nvg_get_result(); +} + +/* + * Set the expected wake time in TSC ticks for the next low-power state the + * core enters. + * + * NVGDATA[0:31]: SW(RW), WAKE_TIME + */ +void nvg_set_wake_time(uint32_t wake_time) +{ + /* time (TSC ticks) until the core is expected to get a wake event */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_WAKE_TIME, (uint64_t)wake_time); +} + +/* + * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and + * SYSTEM_CSTATE values. + * + * NVGDATA[0:2]: SW(RW), CLUSTER_CSTATE + * NVGDATA[7]: SW(W), update cluster flag + * NVGDATA[8:10]: SW(RW), CG_CSTATE + * NVGDATA[15]: SW(W), update ccplex flag + * NVGDATA[16:19]: SW(RW), SYSTEM_CSTATE + * NVGDATA[23]: SW(W), update system flag + * NVGDATA[31]: SW(W), update wake mask flag + * NVGDATA[32:63]: SW(RW), WAKE_MASK + */ +void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex, + uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask) +{ + uint64_t val = 0; + + /* update CLUSTER_CSTATE? */ + if (cluster != 0U) { + val |= ((uint64_t)cluster & CLUSTER_CSTATE_MASK) | + CLUSTER_CSTATE_UPDATE_BIT; + } + + /* update CCPLEX_CSTATE? */ + if (ccplex != 0U) { + val |= (((uint64_t)ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) | + CCPLEX_CSTATE_UPDATE_BIT; + } + + /* update SYSTEM_CSTATE? */ + if (system != 0U) { + val |= (((uint64_t)system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) | + SYSTEM_CSTATE_UPDATE_BIT; + } + + /* update wake mask value? */ + if (update_wake_mask != 0U) { + val |= CSTATE_WAKE_MASK_UPDATE_BIT; + } + + /* set the wake mask */ + val |= ((uint64_t)wake_mask & CSTATE_WAKE_MASK_CLEAR) << CSTATE_WAKE_MASK_SHIFT; + + /* set the updated cstate info */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val); +} + +/* + * Return a non-zero value if the CCPLEX is able to enter SC7 + * + * NVGDATA[0]: SW(R), Is allowed result + */ +int32_t nvg_is_sc7_allowed(void) +{ + /* issue command to check if SC7 is allowed */ + nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED); + + /* 1 = SC7 allowed, 0 = SC7 not allowed */ + return (int32_t)nvg_get_result(); +} + +/* + * Wake an offlined logical core. Note that a core is offlined by entering + * a C-state where the WAKE_MASK is all 0. + * + * NVGDATA[0:3]: SW(W) logical core to online + */ +int32_t nvg_online_core(uint32_t core) +{ + int32_t ret = 0; + + /* sanity check the core ID value */ + if (core > (uint32_t)PLATFORM_CORE_COUNT) { + ERROR("%s: unknown core id (%d)\n", __func__, core); + ret = -EINVAL; + } else { + /* get a core online */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_ONLINE_CORE, + (uint64_t)core & MCE_CORE_ID_MASK); + } + + return ret; +} + +/* + * MC GSC (General Security Carveout) register values are expected to be + * changed by TrustZone ARM code after boot. + * + * NVGDATA[0:15] SW(R) GSC enun + */ +int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx) +{ + int32_t ret = 0; + + /* sanity check GSC ID */ + if (gsc_idx > (uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR) { + ERROR("%s: unknown gsc_idx (%u)\n", __func__, gsc_idx); + ret = -EINVAL; + } else { + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC, + (uint64_t)gsc_idx); + } + + return ret; +} + +/* + * Cache clean and invalidate, clear TR-bit operation for all CCPLEX caches. + */ +int32_t nvg_roc_clean_cache_trbits(void) +{ + int32_t ret = 0; + + /* check if cache flush through mts is supported */ + if (((read_id_afr0_el1() >> ID_AFR0_EL1_CACHE_OPS_SHIFT) & + ID_AFR0_EL1_CACHE_OPS_MASK) == 1U) { + if (nvg_cache_inval_all() == 0U) { + ERROR("%s: failed\n", __func__); + ret = -ENODEV; + } + } else { + ret = -ENOTSUP; + } + + return ret; +} + +/* + * Set the power state for a core + */ +int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time) +{ + int32_t ret = 0; + uint64_t val = 0ULL; + + /* check for allowed power state */ + if ((state != (uint32_t)TEGRA_NVG_CORE_C0) && + (state != (uint32_t)TEGRA_NVG_CORE_C1) && + (state != (uint32_t)TEGRA_NVG_CORE_C6) && + (state != (uint32_t)TEGRA_NVG_CORE_C7)) + { + ERROR("%s: unknown cstate (%u)\n", __func__, state); + ret = -EINVAL; + } else { + /* time (TSC ticks) until the core is expected to get a wake event */ + nvg_set_wake_time(wake_time); + + /* set the core cstate */ + val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK; + write_actlr_el1(val | (uint64_t)state); + } + + return ret; +} + +#if ENABLE_STRICT_CHECKING_MODE +/* + * Enable strict checking mode + * + * NVGDATA[3] strict_check ON + lock + */ +void nvg_enable_strict_checking_mode(void) +{ + uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET | + STRICT_CHECKING_LOCKED_SET); + + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG, params); +} + +void nvg_verify_strict_checking_mode(void) +{ + uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET | + STRICT_CHECKING_LOCKED_SET); + + nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG); + assert(params == (uint64_t)nvg_get_result()); +} +#endif + +/* + * Request a reboot + * + * NVGDATA[0]: reboot command + */ +void nvg_system_reboot(void) +{ + /* issue command for reboot */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN, + (uint64_t)TEGRA_NVG_REBOOT); +} + +/* + * Request a shutdown + * + * NVGDATA[0]: shutdown command + */ +void nvg_system_shutdown(void) +{ + /* issue command for shutdown */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN, + (uint64_t)TEGRA_NVG_SHUTDOWN); +} + +/* + * Request to clear CCPLEX->HSM correctable error signal. + * NVGDATA[1]: A write of 1 clears the CCPLEX->HSM correctable error signal, + * A write of 0 has no effect. + */ +void nvg_clear_hsm_corr_status(void) +{ + nvg_hsm_error_ctrl_channel_t status = { .bits = { .corr = 1U, }, }; + + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_HSM_ERROR_CTRL, status.flat); +} diff --git a/plat/nvidia/tegra/soc/t194/drivers/se/se.c b/plat/nvidia/tegra/soc/t194/drivers/se/se.c new file mode 100644 index 0000000..31b0e26 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/se/se.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> + +#include <arch_helpers.h> +#include <bpmp_ipc.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <se.h> +#include <tegra_platform.h> + +#include "se_private.h" + +/******************************************************************************* + * Constants and Macros + ******************************************************************************/ +#define ERR_STATUS_SW_CLEAR U(0xFFFFFFFF) +#define INT_STATUS_SW_CLEAR U(0xFFFFFFFF) +#define MAX_TIMEOUT_MS U(1000) /* Max. timeout of 1s */ +#define NUM_SE_REGS_TO_SAVE U(4) + +#define BYTES_IN_WORD U(4) +#define SHA256_MAX_HASH_RESULT U(7) +#define SHA256_DST_SIZE U(32) +#define SHA_FIRST_OP U(1) +#define MAX_SHA_ENGINE_CHUNK_SIZE U(0xFFFFFF) +#define SHA256_MSG_LENGTH_ONETIME U(0xFFFF) + +/******************************************************************************* + * Data structure and global variables + ******************************************************************************/ +static uint32_t se_regs[NUM_SE_REGS_TO_SAVE]; + +/* + * Check that SE operation has completed after kickoff. + * + * This function is invoked after an SE operation has been started, + * and it checks the following conditions: + * + * 1. SE_STATUS = IDLE + * 2. AHB bus data transfer is complete. + * 3. SE_ERR_STATUS is clean. + */ +static bool tegra_se_is_operation_complete(void) +{ + uint32_t val = 0, timeout = 0, sha_status, aes_status; + int32_t ret = 0; + bool se_is_busy, txn_has_errors, txn_successful; + + /* + * Poll the status register to check if the operation + * completed. + */ + do { + val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS); + se_is_busy = ((val & CTX_SAVE_AUTO_SE_BUSY) != 0U); + + /* sleep until SE finishes */ + if (se_is_busy) { + mdelay(1); + timeout++; + } + + } while (se_is_busy && (timeout < MAX_TIMEOUT_MS)); + + /* any transaction errors? */ + txn_has_errors = (tegra_se_read_32(SHA_ERR_STATUS) != 0U) || + (tegra_se_read_32(AES0_ERR_STATUS) != 0U); + + /* transaction successful? */ + sha_status = tegra_se_read_32(SHA_INT_STATUS) & SHA_SE_OP_DONE; + aes_status = tegra_se_read_32(AES0_INT_STATUS) & AES0_SE_OP_DONE; + txn_successful = (sha_status == SHA_SE_OP_DONE) && + (aes_status == AES0_SE_OP_DONE); + + if ((timeout == MAX_TIMEOUT_MS) || txn_has_errors || !txn_successful) { + ERROR("%s: Atomic context save operation failed!\n", + __func__); + ret = -ECANCELED; + } + + return (ret == 0); +} + +/* + * Wait for SE engine to be idle and clear any pending interrupts, before + * starting the next SE operation. + */ +static bool tegra_se_is_ready(void) +{ + int32_t ret = 0; + uint32_t val = 0, timeout = 0; + bool se_is_ready; + + /* Wait for previous operation to finish */ + do { + val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS); + se_is_ready = (val == CTX_SAVE_AUTO_SE_READY); + + /* sleep until SE is ready */ + if (!se_is_ready) { + mdelay(1); + timeout++; + } + + } while (!se_is_ready && (timeout < MAX_TIMEOUT_MS)); + + if (timeout == MAX_TIMEOUT_MS) { + ERROR("%s: SE is not ready!\n", __func__); + ret = -ETIMEDOUT; + } + + /* Clear any pending interrupts from previous operation */ + tegra_se_write_32(AES0_INT_STATUS, INT_STATUS_SW_CLEAR); + tegra_se_write_32(AES1_INT_STATUS, INT_STATUS_SW_CLEAR); + tegra_se_write_32(RSA_INT_STATUS, INT_STATUS_SW_CLEAR); + tegra_se_write_32(SHA_INT_STATUS, INT_STATUS_SW_CLEAR); + + /* Clear error status for each engine seen from current port */ + tegra_se_write_32(AES0_ERR_STATUS, ERR_STATUS_SW_CLEAR); + tegra_se_write_32(AES1_ERR_STATUS, ERR_STATUS_SW_CLEAR); + tegra_se_write_32(RSA_ERR_STATUS, ERR_STATUS_SW_CLEAR); + tegra_se_write_32(SHA_ERR_STATUS, ERR_STATUS_SW_CLEAR); + + return (ret == 0); +} + +/* + * During System Suspend, this handler triggers the hardware context + * save operation. + */ +static int32_t tegra_se_save_context(void) +{ + int32_t ret = -ECANCELED; + + /* + * 1. Ensure all SE Driver including RNG1/PKA1 are shut down. + * TSEC/R5s are powergated/idle. All tasks on SE1~SE4, RNG1, + * PKA1 are wrapped up. SE0 is ready for use. + * 2. Clear interrupt/error in SE0 status register. + * 3. Scrub SE0 register to avoid false failure for illegal + * configuration. Probably not needed, dependent on HW + * implementation. + * 4. Check SE is ready for HW CTX_SAVE by polling + * SE_CTX_SAVE_AUTO_STATUS.SE_READY. + * + * Steps 1-4 are executed by tegra_se_is_ready(). + * + * 5. Issue context save command. + * 6. Check SE is busy with CTX_SAVE, the command in step5 was not + * dropped for ongoing traffic in any of SE port/engine. + * 7. Poll SE register or wait for SE APB interrupt for task completion + * a. Polling: Read SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE + * b. Interrupt: After receiving interrupt from SE APB, read + * SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE. + * 8. Check AES0 and SHA ERR_STATUS to ensure no error case. + * 9. Check AES0 and SHA INT_STATUS to ensure operation has successfully + * completed. + * + * Steps 6-9 are executed by tegra_se_is_operation_complete(). + */ + if (tegra_se_is_ready()) { + + /* Issue context save command */ + tegra_se_write_32(AES0_OPERATION, SE_OP_CTX_SAVE); + + /* Wait for operation to finish */ + if (tegra_se_is_operation_complete()) { + ret = 0; + } + } + + return ret; +} + +/* + * Check that SE operation has completed after kickoff + * This function is invoked after an SE operation has been started, + * and it checks the following conditions: + * 1. SE0_INT_STATUS = SE0_OP_DONE + * 2. SE0_STATUS = IDLE + * 3. SE0_ERR_STATUS is clean. + */ +static int32_t tegra_se_sha256_hash_operation_complete(void) +{ + uint32_t val = 0U; + + /* Poll the SE interrupt register to ensure H/W operation complete */ + val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET); + while (SE0_INT_OP_DONE(val) == SE0_INT_OP_DONE_CLEAR) { + val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET); + if (SE0_INT_OP_DONE(val) != SE0_INT_OP_DONE_CLEAR) { + break; + } + } + + /* Poll the SE status idle to ensure H/W operation complete */ + val = tegra_se_read_32(SE0_SHA_STATUS_0); + while (val != SE0_SHA_STATUS_IDLE) { + val = tegra_se_read_32(SE0_SHA_STATUS_0); + if (val == SE0_SHA_STATUS_IDLE) { + break; + } + } + + /* Ensure that no errors are thrown during operation */ + val = tegra_se_read_32(SE0_ERR_STATUS_REG_OFFSET); + if (val != 0U) { + ERROR("%s: error during SE operation! 0x%x", __func__, + val); + return -ENOTSUP; + } + + return 0; +} + +/* + * Security engine primitive normal operations + */ +static int32_t tegra_se_start_normal_operation(uint64_t src_addr, + uint32_t nbytes, uint32_t last_buf, uint32_t src_len_inbytes) +{ + uint32_t val = 0U; + uint32_t src_in_lo; + uint32_t src_in_msb; + uint32_t src_in_hi; + int32_t ret = 0; + + if ((src_addr == 0ULL) || (nbytes == 0U)) + return -EINVAL; + + src_in_lo = (uint32_t)src_addr; + src_in_msb = (uint32_t)((src_addr >> 32U) & 0xFFU); + src_in_hi = ((src_in_msb << SE0_IN_HI_ADDR_HI_0_MSB_SHIFT) | + (nbytes & MAX_SHA_ENGINE_CHUNK_SIZE)); + + /* set SRC_IN_ADDR_LO and SRC_IN_ADDR_HI*/ + tegra_se_write_32(SE0_IN_ADDR, src_in_lo); + tegra_se_write_32(SE0_IN_HI_ADDR_HI, src_in_hi); + + val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET); + if (val > 0U) { + tegra_se_write_32(SE0_INT_STATUS_REG_OFFSET, 0x0U); + } + + /* Enable SHA interrupt for SE0 Operation */ + tegra_se_write_32(SE0_SHA_INT_ENABLE, 0x1aU); + + /* flush to DRAM for SE to use the updated contents */ + flush_dcache_range(src_addr, src_len_inbytes); + + /* Start SHA256 operation */ + if (last_buf == 1U) { + tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START | + SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD); + } else { + tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START); + } + + return ret; +} + +static int32_t tegra_se_calculate_sha256_hash(uint64_t src_addr, + uint32_t src_len_inbyte) +{ + uint32_t val, last_buf, i; + int32_t ret = 0; + uint32_t operations; + uint64_t src_len_inbits; + uint32_t len_bits_msb; + uint32_t len_bits_lsb; + uint32_t number_of_operations, max_bytes, bytes_left, remaining_bytes; + + if (src_len_inbyte > MAX_SHA_ENGINE_CHUNK_SIZE) { + ERROR("SHA input chunk size too big: 0x%x\n", src_len_inbyte); + return -EINVAL; + } + + if (src_addr == 0ULL) { + return -EINVAL; + } + + /* number of bytes per operation */ + max_bytes = (SHA256_HASH_SIZE_BYTES * SHA256_MSG_LENGTH_ONETIME); + + src_len_inbits = (uint32_t)(src_len_inbyte * 8U); + len_bits_msb = (uint32_t)(src_len_inbits >> 32U); + len_bits_lsb = (uint32_t)src_len_inbits; + + /* program SE0_CONFIG for SHA256 operation */ + val = (uint32_t)(SE0_CONFIG_ENC_ALG_SHA | SE0_CONFIG_ENC_MODE_SHA256 | + SE0_CONFIG_DEC_ALG_NOP | SE0_CONFIG_DST_HASHREG); + tegra_se_write_32(SE0_SHA_CONFIG, val); + + /* set SE0_SHA_MSG_LENGTH registers */ + tegra_se_write_32(SE0_SHA_MSG_LENGTH_0, len_bits_lsb); + tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb); + tegra_se_write_32(SE0_SHA_MSG_LENGTH_1, len_bits_msb); + + /* zero out unused SE0_SHA_MSG_LENGTH and SE0_SHA_MSG_LEFT */ + tegra_se_write_32(SE0_SHA_MSG_LENGTH_2, 0U); + tegra_se_write_32(SE0_SHA_MSG_LENGTH_3, 0U); + tegra_se_write_32(SE0_SHA_MSG_LEFT_1, 0U); + tegra_se_write_32(SE0_SHA_MSG_LEFT_2, 0U); + tegra_se_write_32(SE0_SHA_MSG_LEFT_3, 0U); + + number_of_operations = (src_len_inbyte / max_bytes); + remaining_bytes = (src_len_inbyte % max_bytes); + if (remaining_bytes > 0U) { + number_of_operations += 1U; + } + + /* + * 1. Operations == 1: program SE0_SHA_TASK register to initiate SHA256 + * hash generation by setting + * 1(SE0_SHA_CONFIG_HW_INIT_HASH) to SE0_SHA_TASK + * and start SHA256-normal operation. + * 2. 1 < Operations < number_of_operations: program SE0_SHA_TASK to + * 0(SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE) to load + * intermediate SHA256 digest result from + * HASH_RESULT register to continue SHA256 + * generation and start SHA256-normal operation. + * 3. Operations == number_of_operations: continue with step 2 and set + * max_bytes to bytes_left to process final + * hash-result generation and start SHA256-normal + * operation. + */ + bytes_left = src_len_inbyte; + for (operations = 1U; operations <= number_of_operations; + operations++) { + if (operations == SHA_FIRST_OP) { + val = SE0_SHA_CONFIG_HW_INIT_HASH; + } else { + /* Load intermediate SHA digest result to + * SHA:HASH_RESULT(0..7) to continue the SHA + * calculation and tell the SHA engine to use it. + */ + for (i = 0U; (i / BYTES_IN_WORD) <= + SHA256_MAX_HASH_RESULT; i += BYTES_IN_WORD) { + val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + + i); + tegra_se_write_32(SE0_SHA_HASH_RESULT_0 + i, + val); + } + val = SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE; + if (len_bits_lsb <= (max_bytes * 8U)) { + len_bits_lsb = (remaining_bytes * 8U); + } else { + len_bits_lsb -= (max_bytes * 8U); + } + tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb); + } + tegra_se_write_32(SE0_SHA_TASK_CONFIG, val); + + max_bytes = (SHA256_HASH_SIZE_BYTES * + SHA256_MSG_LENGTH_ONETIME); + if (bytes_left < max_bytes) { + max_bytes = bytes_left; + last_buf = 1U; + } else { + bytes_left = bytes_left - max_bytes; + last_buf = 0U; + } + /* start operation */ + ret = tegra_se_start_normal_operation(src_addr, max_bytes, + last_buf, src_len_inbyte); + if (ret != 0) { + ERROR("Error during SE operation! 0x%x", ret); + return -EINVAL; + } + } + + return ret; +} + +static int32_t tegra_se_save_sha256_pmc_scratch(void) +{ + uint32_t val = 0U, hash_offset = 0U, scratch_offset = 0U; + int32_t ret; + + /* Check SE0 operation status */ + ret = tegra_se_sha256_hash_operation_complete(); + if (ret != 0) { + ERROR("SE operation complete Failed! 0x%x", ret); + return ret; + } + + for (scratch_offset = SECURE_SCRATCH_TZDRAM_SHA256_HASH_START; + scratch_offset <= SECURE_SCRATCH_TZDRAM_SHA256_HASH_END; + scratch_offset += BYTES_IN_WORD) { + val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + hash_offset); + mmio_write_32((uint32_t)(TEGRA_SCRATCH_BASE + scratch_offset), + val); + hash_offset += BYTES_IN_WORD; + } + return 0; +} + +/* + * Handler to generate SHA256 and save HASH-result to pmc-scratch register + */ +int32_t tegra_se_calculate_save_sha256(uint64_t src_addr, + uint32_t src_len_inbyte) +{ + uint32_t security; + int32_t val = 0; + + /* Set SE_SOFT_SETTINGS=SE_SECURE to prevent NS process to change SE + * registers. + */ + security = tegra_se_read_32(SE0_SECURITY); + tegra_se_write_32(SE0_SECURITY, security | SE0_SECURITY_SE_SOFT_SETTING); + + /* Bootrom enable IN_ID bit in SE0_SHA_GSCID_0 register during SC7-exit, causing + * SE0 ignores SE0 operation, and therefore failure of 2nd iteration of SC7 cycle. + */ + tegra_se_write_32(SE0_SHA_GSCID_0, 0x0U); + + /* Calculate SHA256 of BL31 */ + val = tegra_se_calculate_sha256_hash(src_addr, src_len_inbyte); + if (val != 0) { + ERROR("%s: SHA256 generation failed\n", __func__); + return val; + } + + /* + * Reset SE_SECURE to previous value. + */ + tegra_se_write_32(SE0_SECURITY, security); + + /* copy sha256_dst to PMC Scratch register */ + val = tegra_se_save_sha256_pmc_scratch(); + if (val != 0) { + ERROR("%s: SE0 status Error.\n", __func__); + } + + return val; +} + +/* + * Handler to power down the SE hardware blocks - SE, RNG1 and PKA1. This + * needs to be called only during System Suspend. + */ +int32_t tegra_se_suspend(void) +{ + int32_t ret = 0; + + /* initialise communication channel with BPMP */ + assert(tegra_bpmp_ipc_init() == 0); + + /* Enable SE clock before SE context save */ + ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE); + assert(ret == 0); + + /* save SE registers */ + se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[1] = mmio_read_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL); + se_regs[2] = mmio_read_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[3] = mmio_read_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT); + + /* Save SE context. The BootROM restores it during System Resume */ + ret = tegra_se_save_context(); + if (ret != 0) { + ERROR("%s: context save failed (%d)\n", __func__, ret); + } + + /* Disable SE clock after SE context save */ + ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE); + assert(ret == 0); + + return ret; +} + +/* + * Handler to power up the SE hardware block(s) during System Resume. + */ +void tegra_se_resume(void) +{ + int32_t ret = 0; + + /* initialise communication channel with BPMP */ + assert(tegra_bpmp_ipc_init() == 0); + + /* Enable SE clock before SE context restore */ + ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE); + assert(ret == 0); + + /* + * When TZ takes over after System Resume, TZ should first reconfigure + * SE_MUTEX_WATCHDOG_NS_LIMIT, PKA1_MUTEX_WATCHDOG_NS_LIMIT, + * RNG1_MUTEX_WATCHDOG_NS_LIMIT and SE_ENTROPY_SRC_AGE_CTRL before + * other operations. + */ + mmio_write_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT, se_regs[0]); + mmio_write_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL, se_regs[1]); + mmio_write_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[2]); + mmio_write_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[3]); + + /* Disable SE clock after SE context restore */ + ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE); + assert(ret == 0); +} diff --git a/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h new file mode 100644 index 0000000..fc118aa --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SE_PRIVATE_H +#define SE_PRIVATE_H + +#include <lib/utils_def.h> +#include <tegra_def.h> + +/* SE0 security register */ +#define SE0_SECURITY U(0x18) +#define SE0_SECURITY_SE_SOFT_SETTING (((uint32_t)1) << 16U) + +/* SE0 SHA GSCID register */ +#define SE0_SHA_GSCID_0 U(0x100) + +/* SE0 config register */ +#define SE0_SHA_CONFIG U(0x104) +#define SE0_SHA_TASK_CONFIG U(0x108) +#define SE0_SHA_CONFIG_HW_INIT_HASH (((uint32_t)1) << 0U) +#define SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE U(0) + +#define SE0_CONFIG_ENC_ALG_SHIFT U(12) +#define SE0_CONFIG_ENC_ALG_SHA \ + (((uint32_t)3) << SE0_CONFIG_ENC_ALG_SHIFT) +#define SE0_CONFIG_DEC_ALG_SHIFT U(8) +#define SE0_CONFIG_DEC_ALG_NOP \ + (((uint32_t)0) << SE0_CONFIG_DEC_ALG_SHIFT) +#define SE0_CONFIG_DST_SHIFT U(2) +#define SE0_CONFIG_DST_HASHREG \ + (((uint32_t)1) << SE0_CONFIG_DST_SHIFT) +#define SHA256_HASH_SIZE_BYTES U(256) + +#define SE0_CONFIG_ENC_MODE_SHIFT U(24) +#define SE0_CONFIG_ENC_MODE_SHA256 \ + (((uint32_t)5) << SE0_CONFIG_ENC_MODE_SHIFT) + +/* SHA input message length */ +#define SE0_IN_ADDR U(0x10c) +#define SE0_IN_HI_ADDR_HI U(0x110) +#define SE0_IN_HI_ADDR_HI_0_MSB_SHIFT U(24) + +/* SHA input message length */ +#define SE0_SHA_MSG_LENGTH_0 U(0x11c) +#define SE0_SHA_MSG_LENGTH_1 U(0x120) +#define SE0_SHA_MSG_LENGTH_2 U(0x124) +#define SE0_SHA_MSG_LENGTH_3 U(0x128) + +/* SHA input message left */ +#define SE0_SHA_MSG_LEFT_0 U(0x12c) +#define SE0_SHA_MSG_LEFT_1 U(0x130) +#define SE0_SHA_MSG_LEFT_2 U(0x134) +#define SE0_SHA_MSG_LEFT_3 U(0x138) + +/* SE HASH-RESULT */ +#define SE0_SHA_HASH_RESULT_0 U(0x13c) + +/* SE OPERATION */ +#define SE0_OPERATION_REG_OFFSET U(0x17c) +#define SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT U(16) +#define SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD \ + ((uint32_t)0x1 << SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT) +#define SE0_OPERATION_SHIFT U(0) +#define SE0_OP_START \ + (((uint32_t)0x1) << SE0_OPERATION_SHIFT) + +/* SE Interrupt */ +#define SE0_SHA_INT_ENABLE U(0x180) + +#define SE0_INT_STATUS_REG_OFFSET U(0x184) +#define SE0_INT_OP_DONE_SHIFT U(4) +#define SE0_INT_OP_DONE_CLEAR \ + (((uint32_t)0U) << SE0_INT_OP_DONE_SHIFT) +#define SE0_INT_OP_DONE(x) \ + ((x) & (((uint32_t)0x1U) << SE0_INT_OP_DONE_SHIFT)) + +/* SE SHA Status */ +#define SE0_SHA_STATUS_0 U(0x188) +#define SE0_SHA_STATUS_IDLE U(0) + +/* SE error status */ +#define SE0_ERR_STATUS_REG_OFFSET U(0x18c) +#define SE0_ERR_STATUS_CLEAR U(0) + +/* SE error status */ +#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_START SECURE_SCRATCH_RSV68_LO +#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_END SECURE_SCRATCH_RSV71_HI + +/* SE0_INT_ENABLE_0 */ +#define SE0_INT_ENABLE U(0x88) +#define SE0_DISABLE_ALL_INT U(0x0) + +/* SE0_INT_STATUS_0 */ +#define SE0_INT_STATUS U(0x8C) +#define SE0_CLEAR_ALL_INT_STATUS U(0x3F) + +/* SE0_SHA_INT_STATUS_0 */ +#define SHA_INT_STATUS U(0x184) +#define SHA_SE_OP_DONE (U(1) << 4) + +/* SE0_SHA_ERR_STATUS_0 */ +#define SHA_ERR_STATUS U(0x18C) + +/* SE0_AES0_INT_STATUS_0 */ +#define AES0_INT_STATUS U(0x2F0) +#define AES0_SE_OP_DONE (U(1) << 4) + +/* SE0_AES0_ERR_STATUS_0 */ +#define AES0_ERR_STATUS U(0x2F8) + +/* SE0_AES1_INT_STATUS_0 */ +#define AES1_INT_STATUS U(0x4F0) + +/* SE0_AES1_ERR_STATUS_0 */ +#define AES1_ERR_STATUS U(0x4F8) + +/* SE0_RSA_INT_STATUS_0 */ +#define RSA_INT_STATUS U(0x758) + +/* SE0_RSA_ERR_STATUS_0 */ +#define RSA_ERR_STATUS U(0x760) + +/* SE0_AES0_OPERATION_0 */ +#define AES0_OPERATION U(0x238) +#define OP_MASK_BITS U(0x7) +#define SE_OP_CTX_SAVE U(0x3) + +/* SE0_AES0_CTX_SAVE_CONFIG_0 */ +#define CTX_SAVE_CONFIG U(0x2D4) + +/* SE0_AES0_CTX_SAVE_AUTO_STATUS_0 */ +#define CTX_SAVE_AUTO_STATUS U(0x300) +#define CTX_SAVE_AUTO_SE_READY U(0xFF) +#define CTX_SAVE_AUTO_SE_BUSY (U(0x1) << 31) + +/* SE0_AES0_CTX_SAVE_AUTO_CTRL_0 */ +#define CTX_SAVE_AUTO_CTRL U(0x304) +#define SE_CTX_SAVE_AUTO_EN (U(0x1) << 0) +#define SE_CTX_SAVE_AUTO_LOCK_EN (U(0x1) << 1) + +/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_0 */ +#define CTX_SAVE_AUTO_START_ADDR U(0x308) + +/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_HI_0 */ +#define CTX_SAVE_AUTO_START_ADDR_HI U(0x30C) + +/******************************************************************************* + * Inline functions definition + ******************************************************************************/ + +static inline uint32_t tegra_se_read_32(uint32_t offset) +{ + return mmio_read_32((uint32_t)(TEGRA_SE0_BASE + offset)); +} + +static inline void tegra_se_write_32(uint32_t offset, uint32_t val) +{ + mmio_write_32((uint32_t)(TEGRA_SE0_BASE + offset), val); +} + +#endif /* SE_PRIVATE_H */ diff --git a/plat/nvidia/tegra/soc/t194/plat_memctrl.c b/plat/nvidia/tegra/soc/t194/plat_memctrl.c new file mode 100644 index 0000000..9ddcacf --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_memctrl.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <common/bl_common.h> +#include <mce.h> +#include <memctrl_v2.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +/******************************************************************************* + * Array to hold MC context for Tegra194 + ******************************************************************************/ +static __attribute__((aligned(16))) mc_regs_t tegra194_mc_context[] = { + _START_OF_TABLE_, + mc_smmu_bypass_cfg, /* TBU settings */ + _END_OF_TABLE_, +}; + +/******************************************************************************* + * Handler to return the pointer to the MC's context struct + ******************************************************************************/ +mc_regs_t *plat_memctrl_get_sys_suspend_ctx(void) +{ + /* index of _END_OF_TABLE_ */ + tegra194_mc_context[0].val = (uint32_t)ARRAY_SIZE(tegra194_mc_context) - 1U; + + return tegra194_mc_context; +} + +/******************************************************************************* + * Handler to restore platform specific settings to the memory controller + ******************************************************************************/ +void plat_memctrl_restore(void) +{ + UNUSED_FUNC_NOP(); /* do nothing */ +} + +/******************************************************************************* + * Handler to program platform specific settings to the memory controller + ******************************************************************************/ +void plat_memctrl_setup(void) +{ + UNUSED_FUNC_NOP(); /* do nothing */ +} + +/******************************************************************************* + * Handler to program the scratch registers with TZDRAM settings for the + * resume firmware + ******************************************************************************/ +void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes) +{ + uint32_t sec_reg_ctrl = tegra_mc_read_32(MC_SECURITY_CFG_REG_CTRL_0); + uint32_t phys_base_lo = (uint32_t)phys_base & 0xFFF00000; + uint32_t phys_base_hi = (uint32_t)(phys_base >> 32); + + /* + * Check TZDRAM carveout register access status. Setup TZDRAM fence + * only if access is enabled. + */ + if ((sec_reg_ctrl & SECURITY_CFG_WRITE_ACCESS_BIT) == + SECURITY_CFG_WRITE_ACCESS_ENABLE) { + + /* + * Setup the Memory controller to allow only secure accesses to + * the TZDRAM carveout + */ + INFO("Configuring TrustZone DRAM Memory Carveout\n"); + + tegra_mc_write_32(MC_SECURITY_CFG0_0, phys_base_lo); + tegra_mc_write_32(MC_SECURITY_CFG3_0, phys_base_hi); + tegra_mc_write_32(MC_SECURITY_CFG1_0, (uint32_t)(size_in_bytes >> 20)); + + /* + * MCE propagates the security configuration values across the + * CCPLEX. + */ + (void)mce_update_gsc_tzdram(); + } +} diff --git a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c new file mode 100644 index 0000000..83d815a --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <assert.h> +#include <stdbool.h> +#include <string.h> + +#include <arch_helpers.h> +#include <bpmp_ipc.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <context.h> +#include <drivers/delay_timer.h> +#include <denver.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/psci/psci.h> +#include <mce.h> +#include <mce_private.h> +#include <memctrl_v2.h> +#include <plat/common/platform.h> +#include <se.h> +#include <smmu.h> +#include <t194_nvg.h> +#include <tegra194_private.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +extern uint32_t __tegra194_cpu_reset_handler_data, + __tegra194_cpu_reset_handler_end; + +/* TZDRAM offset for saving SMMU context */ +#define TEGRA194_SMMU_CTX_OFFSET 16U + +/* state id mask */ +#define TEGRA194_STATE_ID_MASK 0xFU +/* constants to get power state's wake time */ +#define TEGRA194_WAKE_TIME_MASK 0x0FFFFFF0U +#define TEGRA194_WAKE_TIME_SHIFT 4U +/* default core wake mask for CPU_SUSPEND */ +#define TEGRA194_CORE_WAKE_MASK 0x180cU + +static struct t19x_psci_percpu_data { + uint32_t wake_time; +} __aligned(CACHE_WRITEBACK_GRANULE) t19x_percpu_data[PLATFORM_CORE_COUNT]; + +int32_t tegra_soc_validate_power_state(uint32_t power_state, + psci_power_state_t *req_state) +{ + uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) & + TEGRA194_STATE_ID_MASK; + uint32_t cpu = plat_my_core_pos(); + int32_t ret = PSCI_E_SUCCESS; + + /* save the core wake time (in TSC ticks)*/ + t19x_percpu_data[cpu].wake_time = (power_state & TEGRA194_WAKE_TIME_MASK) + << TEGRA194_WAKE_TIME_SHIFT; + + /* + * Clean t19x_percpu_data[cpu] to DRAM. This needs to be done to ensure + * that the correct value is read in tegra_soc_pwr_domain_suspend(), + * which is called with caches disabled. It is possible to read a stale + * value from DRAM in that function, because the L2 cache is not flushed + * unless the cluster is entering CC6/CC7. + */ + clean_dcache_range((uint64_t)&t19x_percpu_data[cpu], + sizeof(t19x_percpu_data[cpu])); + + /* Sanity check the requested state id */ + switch (state_id) { + case PSTATE_ID_CORE_IDLE: + + if (psci_get_pstate_type(power_state) != PSTATE_TYPE_STANDBY) { + ret = PSCI_E_INVALID_PARAMS; + break; + } + + /* Core idle request */ + req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; + req_state->pwr_domain_state[MPIDR_AFFLVL1] = PSCI_LOCAL_STATE_RUN; + break; + + default: + ERROR("%s: unsupported state id (%d)\n", __func__, state_id); + ret = PSCI_E_INVALID_PARAMS; + break; + } + + return ret; +} + +int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state) +{ + uint32_t cpu = plat_my_core_pos(); + mce_cstate_info_t cstate_info = { 0 }; + + /* Program default wake mask */ + cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + + /* Enter CPU idle */ + (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, + (uint64_t)TEGRA_NVG_CORE_C6, + t19x_percpu_data[cpu].wake_time, + 0U); + + return PSCI_E_SUCCESS; +} + +int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + const plat_local_state_t *pwr_domain_state; + uint8_t stateid_afflvl2; + plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint64_t mc_ctx_base; + uint32_t val; + mce_cstate_info_t sc7_cstate_info = { + .cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6, + .ccplex = (uint32_t)TEGRA_NVG_CG_CG7, + .system = (uint32_t)TEGRA_NVG_SYSTEM_SC7, + .system_state_force = 1U, + .update_wake_mask = 1U, + }; + int32_t ret = 0; + + /* get the state ID */ + pwr_domain_state = target_state->pwr_domain_state; + stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & + TEGRA194_STATE_ID_MASK; + + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + + /* save 'Secure Boot' Processor Feature Config Register */ + val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG); + mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val); + + /* save MC context */ + mc_ctx_base = params_from_bl2->tzdram_base + + tegra194_get_mc_ctx_offset(); + tegra_mc_save_context((uintptr_t)mc_ctx_base); + + /* + * Suspend SE, RNG1 and PKA1 only on silcon and fpga, + * since VDK does not support atomic se ctx save + */ + if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) { + ret = tegra_se_suspend(); + assert(ret == 0); + } + + /* Prepare for system suspend */ + mce_update_cstate_info(&sc7_cstate_info); + + do { + val = (uint32_t)mce_command_handler( + (uint32_t)MCE_CMD_IS_SC7_ALLOWED, + (uint32_t)TEGRA_NVG_CORE_C7, + MCE_CORE_SLEEP_TIME_INFINITE, + 0U); + } while (val == 0U); + + /* Instruct the MCE to enter system suspend state */ + ret = mce_command_handler( + (uint64_t)MCE_CMD_ENTER_CSTATE, + (uint64_t)TEGRA_NVG_CORE_C7, + MCE_CORE_SLEEP_TIME_INFINITE, + 0U); + assert(ret == 0); + + /* set system suspend state for house-keeping */ + tegra194_set_system_suspend_entry(); + } + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Helper function to check if this is the last ON CPU in the cluster + ******************************************************************************/ +static bool tegra_last_on_cpu_in_cluster(const plat_local_state_t *states, + uint32_t ncpu) +{ + plat_local_state_t target; + bool last_on_cpu = true; + uint32_t num_cpus = ncpu, pos = 0; + + do { + target = states[pos]; + if (target != PLAT_MAX_OFF_STATE) { + last_on_cpu = false; + } + --num_cpus; + pos++; + } while (num_cpus != 0U); + + return last_on_cpu; +} + +/******************************************************************************* + * Helper function to get target power state for the cluster + ******************************************************************************/ +static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states, + uint32_t ncpu) +{ + uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK; + plat_local_state_t target = states[core_pos]; + mce_cstate_info_t cstate_info = { 0 }; + + /* CPU off */ + if (target == PLAT_MAX_OFF_STATE) { + + /* Enable cluster powerdn from last CPU in the cluster */ + if (tegra_last_on_cpu_in_cluster(states, ncpu)) { + + /* Enable CC6 state and turn off wake mask */ + cstate_info.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6; + cstate_info.ccplex = (uint32_t)TEGRA_NVG_CG_CG7; + cstate_info.system_state_force = 1; + cstate_info.update_wake_mask = 1U; + mce_update_cstate_info(&cstate_info); + + } else { + + /* Turn off wake_mask */ + cstate_info.update_wake_mask = 1U; + mce_update_cstate_info(&cstate_info); + target = PSCI_LOCAL_STATE_RUN; + } + } + + return target; +} + +/******************************************************************************* + * Platform handler to calculate the proper target power level at the + * specified affinity level + ******************************************************************************/ +plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl, + const plat_local_state_t *states, + uint32_t ncpu) +{ + plat_local_state_t target = PSCI_LOCAL_STATE_RUN; + uint32_t cpu = plat_my_core_pos(); + + /* System Suspend */ + if ((lvl == (uint32_t)MPIDR_AFFLVL2) && (states[cpu] == PSTATE_ID_SOC_POWERDN)) { + target = PSTATE_ID_SOC_POWERDN; + } + + /* CPU off, CPU suspend */ + if (lvl == (uint32_t)MPIDR_AFFLVL1) { + target = tegra_get_afflvl1_pwr_state(states, ncpu); + } + + /* target cluster/system state */ + return target; +} + +int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) +{ + const plat_local_state_t *pwr_domain_state = + target_state->pwr_domain_state; + plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & + TEGRA194_STATE_ID_MASK; + uint64_t src_len_in_bytes = (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE; + uint64_t val; + int32_t ret = PSCI_E_SUCCESS; + + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + val = params_from_bl2->tzdram_base + + tegra194_get_cpu_reset_handler_size(); + + /* initialise communication channel with BPMP */ + ret = tegra_bpmp_ipc_init(); + assert(ret == 0); + + /* Enable SE clock before SE context save */ + ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE); + assert(ret == 0); + + /* + * It is very unlikely that the BL31 image would be + * bigger than 2^32 bytes + */ + assert(src_len_in_bytes < UINT32_MAX); + + if (tegra_se_calculate_save_sha256(BL31_BASE, + (uint32_t)src_len_in_bytes) != 0) { + ERROR("Hash calculation failed. Reboot\n"); + (void)tegra_soc_prepare_system_reset(); + } + + /* + * The TZRAM loses power when we enter system suspend. To + * allow graceful exit from system suspend, we need to copy + * BL3-1 over to TZDRAM. + */ + val = params_from_bl2->tzdram_base + + tegra194_get_cpu_reset_handler_size(); + memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE, + src_len_in_bytes); + + /* Disable SE clock after SE context save */ + ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE); + assert(ret == 0); + } + + return ret; +} + +int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state) +{ + return PSCI_E_NOT_SUPPORTED; +} + +int32_t tegra_soc_pwr_domain_on(u_register_t mpidr) +{ + uint64_t target_cpu = mpidr & MPIDR_CPU_MASK; + uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >> + MPIDR_AFFINITY_BITS; + int32_t ret = 0; + + if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) { + ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr); + return PSCI_E_NOT_PRESENT; + } + + /* construct the target CPU # */ + target_cpu += (target_cluster << 1U); + + ret = mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U); + if (ret < 0) { + return PSCI_E_DENIED; + } + + return PSCI_E_SUCCESS; +} + +int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint8_t enable_ccplex_lock_step = params_from_bl2->enable_ccplex_lock_step; + uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; + cpu_context_t *ctx = cm_get_context(NON_SECURE); + uint64_t actlr_elx; + + /* + * Reset power state info for CPUs when onlining, we set + * deepest power when offlining a core but that may not be + * requested by non-secure sw which controls idle states. It + * will re-init this info from non-secure software when the + * core come online. + */ + actlr_elx = read_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1)); + actlr_elx &= ~DENVER_CPU_PMSTATE_MASK; + actlr_elx |= DENVER_CPU_PMSTATE_C1; + write_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx)); + + /* + * Check if we are exiting from deep sleep and restore SE + * context if we are. + */ + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + +#if ENABLE_STRICT_CHECKING_MODE + /* + * Enable strict checking after programming the GSC for + * enabling TZSRAM and TZDRAM + */ + mce_enable_strict_checking(); +#endif + + /* Init SMMU */ + tegra_smmu_init(); + + /* Resume SE, RNG1 and PKA1 */ + tegra_se_resume(); + + /* + * Program XUSB STREAMIDs + * ====================== + * T19x XUSB has support for XUSB virtualization. It will + * have one physical function (PF) and four Virtual functions + * (VF) + * + * There were below two SIDs for XUSB until T186. + * 1) #define TEGRA_SID_XUSB_HOST 0x1bU + * 2) #define TEGRA_SID_XUSB_DEV 0x1cU + * + * We have below four new SIDs added for VF(s) + * 3) #define TEGRA_SID_XUSB_VF0 0x5dU + * 4) #define TEGRA_SID_XUSB_VF1 0x5eU + * 5) #define TEGRA_SID_XUSB_VF2 0x5fU + * 6) #define TEGRA_SID_XUSB_VF3 0x60U + * + * When virtualization is enabled then we have to disable SID + * override and program above SIDs in below newly added SID + * registers in XUSB PADCTL MMIO space. These registers are + * TZ protected and so need to be done in ATF. + * + * a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU) + * b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU) + * c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U) + * d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U) + * e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U) + * f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU) + * + * This change disables SID override and programs XUSB SIDs + * in above registers to support both virtualization and + * non-virtualization platforms + */ + if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) { + + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_HOST); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_0) == TEGRA_SID_XUSB_VF0); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_1) == TEGRA_SID_XUSB_VF1); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_2) == TEGRA_SID_XUSB_VF2); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_3) == TEGRA_SID_XUSB_VF3); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_DEV_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_DEV); + } + } + + /* + * Enable dual execution optimized translations for all ELx. + */ + if (enable_ccplex_lock_step != 0U) { + actlr_elx = read_actlr_el3(); + actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL3; + write_actlr_el3(actlr_elx); + + actlr_elx = read_actlr_el2(); + actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL2; + write_actlr_el2(actlr_elx); + + actlr_elx = read_actlr_el1(); + actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL1; + write_actlr_el1(actlr_elx); + } + + return PSCI_E_SUCCESS; +} + +int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state) +{ + /* Do not power off the boot CPU */ + if (plat_is_my_cpu_primary()) { + return PSCI_E_DENIED; + } + + return PSCI_E_SUCCESS; +} + +int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) +{ + uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + int32_t ret = 0; + + (void)target_state; + + /* Disable Denver's DCO operations */ + if (impl == DENVER_IMPL) { + denver_disable_dco(); + } + + /* Turn off CPU */ + ret = mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, + (uint64_t)TEGRA_NVG_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U); + assert(ret == 0); + + return PSCI_E_SUCCESS; +} + +__dead2 void tegra_soc_prepare_system_off(void) +{ + /* System power off */ + mce_system_shutdown(); + + wfi(); + + /* wait for the system to power down */ + for (;;) { + ; + } +} + +int32_t tegra_soc_prepare_system_reset(void) +{ + /* System reboot */ + mce_system_reboot(); + + return PSCI_E_SUCCESS; +} diff --git a/plat/nvidia/tegra/soc/t194/plat_ras.c b/plat/nvidia/tegra/soc/t194/plat_ras.c new file mode 100644 index 0000000..841d70b --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_ras.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <inttypes.h> +#include <stdbool.h> +#include <stdint.h> + +#include <common/debug.h> +#include <lib/bakery_lock.h> +#include <lib/cassert.h> +#include <lib/extensions/ras.h> +#include <lib/utils_def.h> +#include <services/sdei.h> + +#include <plat/common/platform.h> +#include <platform_def.h> +#include <tegra194_ras_private.h> +#include <tegra_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +/* + * ERR<n>FR bits[63:32], it indicates supported RAS errors which can be enabled + * by setting corresponding bits in ERR<n>CTLR + */ +#define ERR_FR_EN_BITS_MASK 0xFFFFFFFF00000000ULL + +/* + * Number of RAS errors will be cleared per 'tegra194_ras_corrected_err_clear' + * function call. + */ +#define RAS_ERRORS_PER_CALL 8 + +/* + * the max possible RAS node index value. + */ +#define RAS_NODE_INDEX_MAX 0x1FFFFFFFU + +/* bakery lock for platform RAS handler. */ +static DEFINE_BAKERY_LOCK(ras_handler_lock); +#define ras_lock() bakery_lock_get(&ras_handler_lock) +#define ras_unlock() bakery_lock_release(&ras_handler_lock) + +/* + * Function to handle an External Abort received at EL3. + * This function is invoked by RAS framework. + */ +static void tegra194_ea_handler(unsigned int ea_reason, uint64_t syndrome, + void *cookie, void *handle, uint64_t flags) +{ + int32_t ret; + + ras_lock(); + + ERROR("MPIDR 0x%lx: exception reason=%u syndrome=0x%" PRIx64 "\n", + read_mpidr(), ea_reason, syndrome); + + /* Call RAS EA handler */ + ret = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags); + if (ret != 0) { + ERROR("RAS error handled!\n"); + ret = sdei_dispatch_event(TEGRA_SDEI_EP_EVENT_0 + + plat_my_core_pos()); + if (ret != 0) + ERROR("sdei_dispatch_event returned %d\n", ret); + } else { + ERROR("Not a RAS error!\n"); + } + + ras_unlock(); +} + +/* + * Function to enable all supported RAS error report. + * + * Uncorrected errors are set to report as External abort (SError) + * Corrected errors are set to report as interrupt. + */ +void tegra194_ras_enable(void) +{ + VERBOSE("%s\n", __func__); + + /* skip RAS enablement if not a silicon platform. */ + if (!tegra_platform_is_silicon()) { + return; + } + + /* + * Iterate for each group(num_idx ERRSELRs starting from idx_start) + * use normal for loop instead of for_each_err_record_info to get rid + * of MISRA noise.. + */ + for (uint32_t i = 0U; i < err_record_mappings.num_err_records; i++) { + + const struct err_record_info *info = &err_record_mappings.err_records[i]; + + uint32_t idx_start = info->sysreg.idx_start; + uint32_t num_idx = info->sysreg.num_idx; + const struct ras_aux_data *aux_data = (const struct ras_aux_data *)info->aux_data; + + assert(aux_data != NULL); + + for (uint32_t j = 0; j < num_idx; j++) { + + /* ERR<n>CTLR register value. */ + uint64_t err_ctrl = 0ULL; + /* all supported errors for this node. */ + uint64_t err_fr; + /* uncorrectable errors */ + uint64_t uncorr_errs; + /* correctable errors */ + uint64_t corr_errs; + + /* + * Catch error if something wrong with the RAS aux data + * record table. + */ + assert(aux_data[j].err_ctrl != NULL); + + /* + * Write to ERRSELR_EL1 to select the RAS error node. + * Always program this at first to select corresponding + * RAS node before any other RAS register r/w. + */ + ser_sys_select_record(idx_start + j); + + err_fr = read_erxfr_el1() & ERR_FR_EN_BITS_MASK; + uncorr_errs = aux_data[j].err_ctrl(); + corr_errs = ~uncorr_errs & err_fr; + + /* enable error reporting */ + ERR_CTLR_ENABLE_FIELD(err_ctrl, ED); + + /* enable SError reporting for uncorrectable errors */ + if ((uncorr_errs & err_fr) != 0ULL) { + ERR_CTLR_ENABLE_FIELD(err_ctrl, UE); + } + + /* generate interrupt for corrected errors. */ + if (corr_errs != 0ULL) { + ERR_CTLR_ENABLE_FIELD(err_ctrl, CFI); + } + + /* enable the supported errors */ + err_ctrl |= err_fr; + + VERBOSE("errselr_el1:0x%x, erxfr:0x%" PRIx64 ", err_ctrl:0x%" PRIx64 "\n", + idx_start + j, err_fr, err_ctrl); + + /* enable specified errors, or set to 0 if no supported error */ + write_erxctlr_el1(err_ctrl); + } + } +} + +/* + * Function to clear RAS ERR<n>STATUS for corrected RAS error. + * + * This function clears number of 'RAS_ERRORS_PER_CALL' RAS errors at most. + * 'cookie' - in/out cookie parameter to specify/store last visited RAS + * error record index. it is set to '0' to indicate no more RAS + * error record to clear. + */ +void tegra194_ras_corrected_err_clear(uint64_t *cookie) +{ + /* + * 'last_node' and 'last_idx' represent last visited RAS node index from + * previous function call. they are set to 0 when first smc call is made + * or all RAS error are visited by followed multipile smc calls. + */ + union prev_record { + struct record { + uint32_t last_node; + uint32_t last_idx; + } rec; + uint64_t value; + } prev; + + uint64_t clear_ce_status = 0ULL; + int32_t nerrs_per_call = RAS_ERRORS_PER_CALL; + uint32_t i; + + if (cookie == NULL) { + return; + } + + prev.value = *cookie; + + if ((prev.rec.last_node >= RAS_NODE_INDEX_MAX) || + (prev.rec.last_idx >= RAS_NODE_INDEX_MAX)) { + return; + } + + ERR_STATUS_SET_FIELD(clear_ce_status, AV, 0x1UL); + ERR_STATUS_SET_FIELD(clear_ce_status, V, 0x1UL); + ERR_STATUS_SET_FIELD(clear_ce_status, OF, 0x1UL); + ERR_STATUS_SET_FIELD(clear_ce_status, MV, 0x1UL); + ERR_STATUS_SET_FIELD(clear_ce_status, CE, 0x3UL); + + + for (i = prev.rec.last_node; i < err_record_mappings.num_err_records; i++) { + + const struct err_record_info *info = &err_record_mappings.err_records[i]; + uint32_t idx_start = info->sysreg.idx_start; + uint32_t num_idx = info->sysreg.num_idx; + + uint32_t j; + + j = (i == prev.rec.last_node && prev.value != 0UL) ? + (prev.rec.last_idx + 1U) : 0U; + + for (; j < num_idx; j++) { + + uint64_t status; + uint32_t err_idx = idx_start + j; + + if (err_idx >= RAS_NODE_INDEX_MAX) { + return; + } + + write_errselr_el1(err_idx); + status = read_erxstatus_el1(); + + if (ERR_STATUS_GET_FIELD(status, CE) != 0U) { + write_erxstatus_el1(clear_ce_status); + } + + --nerrs_per_call; + + /* only clear 'nerrs_per_call' errors each time. */ + if (nerrs_per_call <= 0) { + prev.rec.last_idx = j; + prev.rec.last_node = i; + /* save last visited error record index + * into cookie. + */ + *cookie = prev.value; + + return; + } + } + } + + /* + * finish if all ras error records are checked or provided index is out + * of range. + */ + *cookie = 0ULL; +} + +/* Function to probe an error from error record group. */ +static int32_t tegra194_ras_record_probe(const struct err_record_info *info, + int *probe_data) +{ + /* Skip probing if not a silicon platform */ + if (!tegra_platform_is_silicon()) { + return 0; + } + + return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx, probe_data); +} + +/* Function to handle error from one given node */ +static int32_t tegra194_ras_node_handler(uint32_t errselr, const char *name, + const struct ras_error *errors, uint64_t status) +{ + bool found = false; + uint32_t ierr = (uint32_t)ERR_STATUS_GET_FIELD(status, IERR); + uint32_t serr = (uint32_t)ERR_STATUS_GET_FIELD(status, SERR); + uint64_t val = 0; + + /* not a valid error. */ + if (ERR_STATUS_GET_FIELD(status, V) == 0U) { + return 0; + } + + ERR_STATUS_SET_FIELD(val, V, 1); + + /* keep the log print same as linux arm64_ras driver. */ + ERROR("**************************************\n"); + ERROR("RAS Error in %s, ERRSELR_EL1=0x%x:\n", name, errselr); + ERROR("\tStatus = 0x%" PRIx64 "\n", status); + + /* Print uncorrectable error information. */ + if (ERR_STATUS_GET_FIELD(status, UE) != 0U) { + + ERR_STATUS_SET_FIELD(val, UE, 1); + ERR_STATUS_SET_FIELD(val, UET, 1); + + /* IERR to error message */ + for (uint32_t i = 0; errors[i].error_msg != NULL; i++) { + if (ierr == errors[i].error_code) { + ERROR("\tIERR = %s: 0x%x\n", + errors[i].error_msg, ierr); + + found = true; + break; + } + } + + if (!found) { + ERROR("\tUnknown IERR: 0x%x\n", ierr); + } + + ERROR("SERR = %s: 0x%x\n", ras_serr_to_str(serr), serr); + + /* Overflow, multiple errors have been detected. */ + if (ERR_STATUS_GET_FIELD(status, OF) != 0U) { + ERROR("\tOverflow (there may be more errors) - " + "Uncorrectable\n"); + ERR_STATUS_SET_FIELD(val, OF, 1); + } + + ERROR("\tUncorrectable (this is fatal)\n"); + + /* Miscellaneous Register Valid. */ + if (ERR_STATUS_GET_FIELD(status, MV) != 0U) { + ERROR("\tMISC0 = 0x%lx\n", read_erxmisc0_el1()); + ERROR("\tMISC1 = 0x%lx\n", read_erxmisc1_el1()); + ERR_STATUS_SET_FIELD(val, MV, 1); + } + + /* Address Valid. */ + if (ERR_STATUS_GET_FIELD(status, AV) != 0U) { + ERROR("\tADDR = 0x%lx\n", read_erxaddr_el1()); + ERR_STATUS_SET_FIELD(val, AV, 1); + } + + /* Deferred error */ + if (ERR_STATUS_GET_FIELD(status, DE) != 0U) { + ERROR("\tDeferred error\n"); + ERR_STATUS_SET_FIELD(val, DE, 1); + } + + } else { + /* For corrected error, simply clear it. */ + VERBOSE("corrected RAS error is cleared: ERRSELR_EL1:0x%x, " + "IERR:0x%x, SERR:0x%x\n", errselr, ierr, serr); + ERR_STATUS_SET_FIELD(val, CE, 1); + } + + ERROR("**************************************\n"); + + /* Write to clear reported errors. */ + write_erxstatus_el1(val); + + /* error handled */ + return 0; +} + +/* Function to handle one error node from an error record group. */ +static int32_t tegra194_ras_record_handler(const struct err_record_info *info, + int probe_data, const struct err_handler_data *const data __unused) +{ + uint32_t num_idx = info->sysreg.num_idx; + uint32_t idx_start = info->sysreg.idx_start; + const struct ras_aux_data *aux_data = info->aux_data; + const struct ras_error *errors; + uint32_t offset; + const char *node_name; + + uint64_t status = 0ULL; + + VERBOSE("%s\n", __func__); + + assert(probe_data >= 0); + assert((uint32_t)probe_data < num_idx); + + offset = (uint32_t)probe_data; + errors = aux_data[offset].error_records; + node_name = aux_data[offset].name; + + assert(errors != NULL); + + /* Write to ERRSELR_EL1 to select the error record */ + ser_sys_select_record(idx_start + offset); + + /* Retrieve status register from the error record */ + status = read_erxstatus_el1(); + + return tegra194_ras_node_handler(idx_start + offset, node_name, + errors, status); +} + + +/* Instantiate RAS nodes */ +PER_CORE_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE) +PER_CLUSTER_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE) +SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE) +CCPLEX_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE) + +/* Instantiate RAS node groups */ +static struct ras_aux_data per_core_ras_group[] = { + PER_CORE_RAS_GROUP_NODES +}; +CASSERT(ARRAY_SIZE(per_core_ras_group) < RAS_NODE_INDEX_MAX, + assert_max_per_core_ras_group_size); + +static struct ras_aux_data per_cluster_ras_group[] = { + PER_CLUSTER_RAS_GROUP_NODES +}; +CASSERT(ARRAY_SIZE(per_cluster_ras_group) < RAS_NODE_INDEX_MAX, + assert_max_per_cluster_ras_group_size); + +static struct ras_aux_data scf_l3_ras_group[] = { + SCF_L3_BANK_RAS_GROUP_NODES +}; +CASSERT(ARRAY_SIZE(scf_l3_ras_group) < RAS_NODE_INDEX_MAX, + assert_max_scf_l3_ras_group_size); + +static struct ras_aux_data ccplex_ras_group[] = { + CCPLEX_RAS_GROUP_NODES +}; +CASSERT(ARRAY_SIZE(ccplex_ras_group) < RAS_NODE_INDEX_MAX, + assert_max_ccplex_ras_group_size); + +/* + * We have same probe and handler for each error record group, use a macro to + * simply the record definition. + */ +#define ADD_ONE_ERR_GROUP(errselr_start, group) \ + ERR_RECORD_SYSREG_V1((errselr_start), (uint32_t)ARRAY_SIZE((group)), \ + &tegra194_ras_record_probe, \ + &tegra194_ras_record_handler, (group)) + +/* RAS error record group information */ +static struct err_record_info carmel_ras_records[] = { + /* + * Per core ras error records + * ERRSELR starts from 0*256 + Logical_CPU_ID*16 + 0 to + * 0*256 + Logical_CPU_ID*16 + 5 for each group. + * 8 cores/groups, 6 * 8 nodes in total. + */ + ADD_ONE_ERR_GROUP(0x000, per_core_ras_group), + ADD_ONE_ERR_GROUP(0x010, per_core_ras_group), + ADD_ONE_ERR_GROUP(0x020, per_core_ras_group), + ADD_ONE_ERR_GROUP(0x030, per_core_ras_group), + ADD_ONE_ERR_GROUP(0x040, per_core_ras_group), + ADD_ONE_ERR_GROUP(0x050, per_core_ras_group), + ADD_ONE_ERR_GROUP(0x060, per_core_ras_group), + ADD_ONE_ERR_GROUP(0x070, per_core_ras_group), + + /* + * Per cluster ras error records + * ERRSELR starts from 2*256 + Logical_Cluster_ID*16 + 0 to + * 2*256 + Logical_Cluster_ID*16 + 3. + * 4 clusters/groups, 3 * 4 nodes in total. + */ + ADD_ONE_ERR_GROUP(0x200, per_cluster_ras_group), + ADD_ONE_ERR_GROUP(0x210, per_cluster_ras_group), + ADD_ONE_ERR_GROUP(0x220, per_cluster_ras_group), + ADD_ONE_ERR_GROUP(0x230, per_cluster_ras_group), + + /* + * SCF L3_Bank ras error records + * ERRSELR: 3*256 + L3_Bank_ID, L3_Bank_ID: 0-3 + * 1 groups, 4 nodes in total. + */ + ADD_ONE_ERR_GROUP(0x300, scf_l3_ras_group), + + /* + * CCPLEX ras error records + * ERRSELR: 4*256 + Unit_ID, Unit_ID: 0 - 4 + * 1 groups, 5 nodes in total. + */ + ADD_ONE_ERR_GROUP(0x400, ccplex_ras_group), +}; + +CASSERT(ARRAY_SIZE(carmel_ras_records) < RAS_NODE_INDEX_MAX, + assert_max_carmel_ras_records_size); + +REGISTER_ERR_RECORD_INFO(carmel_ras_records); + +/* dummy RAS interrupt */ +static struct ras_interrupt carmel_ras_interrupts[] = {}; +REGISTER_RAS_INTERRUPTS(carmel_ras_interrupts); + +/******************************************************************************* + * RAS handler for the platform + ******************************************************************************/ +void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, + void *handle, uint64_t flags) +{ +#if ENABLE_FEAT_RAS + tegra194_ea_handler(ea_reason, syndrome, cookie, handle, flags); +#else + plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags); +#endif +} diff --git a/plat/nvidia/tegra/soc/t194/plat_secondary.c b/plat/nvidia/tegra/soc/t194/plat_secondary.c new file mode 100644 index 0000000..1cb14ad --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_secondary.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <string.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <lib/mmio.h> + +#include <mce.h> +#include <tegra194_private.h> +#include <tegra_def.h> +#include <tegra_private.h> + +extern uint64_t tegra_bl31_phys_base; + +#define MISCREG_AA64_RST_LOW 0x2004U +#define MISCREG_AA64_RST_HIGH 0x2008U + +#define CPU_RESET_MODE_AA64 1U + +/******************************************************************************* + * Setup secondary CPU vectors + ******************************************************************************/ +void plat_secondary_setup(void) +{ + uint32_t addr_low, addr_high; + plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint64_t cpu_reset_handler_base, cpu_reset_handler_size, tzdram_addr; + uint64_t src_len_bytes = BL_END - tegra_bl31_phys_base; + + INFO("Setting up secondary CPU boot\n"); + + tzdram_addr = params_from_bl2->tzdram_base + + tegra194_get_cpu_reset_handler_size(); + + /* + * The BL31 code resides in the TZSRAM which loses state + * when we enter System Suspend. Copy the wakeup trampoline + * code to TZDRAM to help us exit from System Suspend. + */ + cpu_reset_handler_base = tegra194_get_cpu_reset_handler_base(); + cpu_reset_handler_size = tegra194_get_cpu_reset_handler_size(); + memcpy((void *)((uintptr_t)params_from_bl2->tzdram_base), + (void *)((uintptr_t)cpu_reset_handler_base), + cpu_reset_handler_size); + + /* TZDRAM base will be used as the "resume" address */ + addr_low = (uint32_t)params_from_bl2->tzdram_base | CPU_RESET_MODE_AA64; + addr_high = (uint32_t)((params_from_bl2->tzdram_base >> 32U) & 0x7ffU); + + /* write lower 32 bits first, then the upper 11 bits */ + mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW, addr_low); + assert(mmio_read_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW) == addr_low); + mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH, addr_high); + assert(mmio_read_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH) == addr_high); + + /* save reset vector to be used during SYSTEM_SUSPEND exit */ + mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO, + addr_low); + assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO) == addr_low); + mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI, + addr_high); + assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI) == addr_high); + mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_LO, + (uint32_t)tzdram_addr); + assert(mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_LO) == (uint32_t)tzdram_addr); + mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_HI, + (uint32_t)src_len_bytes); + assert(mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_HI) == (uint32_t)src_len_bytes); +} diff --git a/plat/nvidia/tegra/soc/t194/plat_setup.c b/plat/nvidia/tegra/soc/t194/plat_setup.c new file mode 100644 index 0000000..6850330 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_setup.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl31/bl31.h> +#include <common/bl_common.h> +#include <common/interrupt_props.h> +#include <drivers/console.h> +#include <context.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <cortex_a57.h> +#include <common/debug.h> +#include <denver.h> +#include <drivers/arm/gic_common.h> +#include <drivers/arm/gicv2.h> +#include <bl31/interrupt_mgmt.h> +#include <mce.h> +#include <mce_private.h> +#include <memctrl.h> +#include <plat/common/platform.h> +#include <smmu.h> +#include <spe.h> +#include <tegra_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> +#include <lib/xlat_tables/xlat_tables_v2.h> + +/* ID for spe-console */ +#define TEGRA_CONSOLE_SPE_ID 0xFE + +/******************************************************************************* + * Structure to store the SCR addresses and its expected settings. + ******************************************************************************* + */ +typedef struct { + uint32_t scr_addr; + uint32_t scr_val; +} scr_settings_t; + +static const scr_settings_t t194_scr_settings[] = { + { SCRATCH_RSV68_SCR, SCRATCH_RSV68_SCR_VAL }, + { SCRATCH_RSV71_SCR, SCRATCH_RSV71_SCR_VAL }, + { SCRATCH_RSV72_SCR, SCRATCH_RSV72_SCR_VAL }, + { SCRATCH_RSV75_SCR, SCRATCH_RSV75_SCR_VAL }, + { SCRATCH_RSV81_SCR, SCRATCH_RSV81_SCR_VAL }, + { SCRATCH_RSV97_SCR, SCRATCH_RSV97_SCR_VAL }, + { SCRATCH_RSV99_SCR, SCRATCH_RSV99_SCR_VAL }, + { SCRATCH_RSV109_SCR, SCRATCH_RSV109_SCR_VAL }, + { MISCREG_SCR_SCRTZWELCK, MISCREG_SCR_SCRTZWELCK_VAL } +}; + +/******************************************************************************* + * The Tegra power domain tree has a single system level power domain i.e. a + * single root node. The first entry in the power domain descriptor specifies + * the number of power domains at the highest power level. + ******************************************************************************* + */ +static const uint8_t tegra_power_domain_tree_desc[] = { + /* No of root nodes */ + 1, + /* No of clusters */ + PLATFORM_CLUSTER_COUNT, + /* No of CPU cores - cluster0 */ + PLATFORM_MAX_CPUS_PER_CLUSTER, + /* No of CPU cores - cluster1 */ + PLATFORM_MAX_CPUS_PER_CLUSTER, + /* No of CPU cores - cluster2 */ + PLATFORM_MAX_CPUS_PER_CLUSTER, + /* No of CPU cores - cluster3 */ + PLATFORM_MAX_CPUS_PER_CLUSTER +}; + +/******************************************************************************* + * This function returns the Tegra default topology tree information. + ******************************************************************************/ +const uint8_t *plat_get_power_domain_tree_desc(void) +{ + return tegra_power_domain_tree_desc; +} + +/* + * Table of regions to map using the MMU. + */ +static const mmap_region_t tegra_mmap[] = { + MAP_REGION_FLAT(TEGRA_MISC_BASE, 0x4000U, /* 16KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_GPCDMA_BASE, 0x10000U, /* 64KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x8000U, /* 32KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_MC_BASE, 0x8000U, /* 32KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), +#if !ENABLE_CONSOLE_SPE + MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000U, /* 128KB - UART A, B*/ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000U, /* 128KB - UART C, G */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000U, /* 192KB - UART D, E, F */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), +#endif + MAP_REGION_FLAT(TEGRA_XUSB_PADCTL_BASE, 0x2000U, /* 8KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x1000, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_GICC_BASE, 0x1000, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x1000U, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x1000U, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x1000U, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_HSP_DBELL_BASE, 0x1000U, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), +#if ENABLE_CONSOLE_SPE + MAP_REGION_FLAT(TEGRA_CONSOLE_SPE_BASE, 0x1000U, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), +#endif + MAP_REGION_FLAT(TEGRA_TMRUS_BASE, TEGRA_TMRUS_SIZE, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x1000U, /* 4KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_SMMU2_BASE, 0x800000U, /* 8MB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_SMMU1_BASE, 0x800000U, /* 8MB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_SMMU0_BASE, 0x800000U, /* 8MB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_BPMP_IPC_TX_PHYS_BASE, 0x10000U, /* 64KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000U, /* 64KB */ + (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE), + {0} +}; + +/******************************************************************************* + * Set up the pagetables as per the platform memory map & initialize the MMU + ******************************************************************************/ +const mmap_region_t *plat_get_mmio_map(void) +{ + /* MMIO space */ + return tegra_mmap; +} + +/******************************************************************************* + * Handler to get the System Counter Frequency + ******************************************************************************/ +uint32_t plat_get_syscnt_freq2(void) +{ + return 31250000; +} + +#if !ENABLE_CONSOLE_SPE +/******************************************************************************* + * Maximum supported UART controllers + ******************************************************************************/ +#define TEGRA194_MAX_UART_PORTS 7 + +/******************************************************************************* + * This variable holds the UART port base addresses + ******************************************************************************/ +static uint32_t tegra194_uart_addresses[TEGRA194_MAX_UART_PORTS + 1] = { + 0, /* undefined - treated as an error case */ + TEGRA_UARTA_BASE, + TEGRA_UARTB_BASE, + TEGRA_UARTC_BASE, + TEGRA_UARTD_BASE, + TEGRA_UARTE_BASE, + TEGRA_UARTF_BASE, + TEGRA_UARTG_BASE +}; +#endif + +/******************************************************************************* + * Enable console corresponding to the console ID + ******************************************************************************/ +void plat_enable_console(int32_t id) +{ + uint32_t console_clock = 0U; + +#if ENABLE_CONSOLE_SPE + static console_t spe_console; + + if (id == TEGRA_CONSOLE_SPE_ID) { + (void)console_spe_register(TEGRA_CONSOLE_SPE_BASE, + console_clock, + TEGRA_CONSOLE_BAUDRATE, + &spe_console); + console_set_scope(&spe_console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); + } +#else + static console_t uart_console; + + if ((id > 0) && (id < TEGRA194_MAX_UART_PORTS)) { + /* + * Reference clock used by the FPGAs is a lot slower. + */ + if (tegra_platform_is_fpga()) { + console_clock = TEGRA_BOOT_UART_CLK_13_MHZ; + } else { + console_clock = TEGRA_BOOT_UART_CLK_408_MHZ; + } + + (void)console_16550_register(tegra194_uart_addresses[id], + console_clock, + TEGRA_CONSOLE_BAUDRATE, + &uart_console); + console_set_scope(&uart_console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); + } +#endif +} + +/******************************************************************************* + * Verify SCR settings + ******************************************************************************/ +static inline bool tegra194_is_scr_valid(void) +{ + uint32_t scr_val; + bool ret = true; + + for (uint8_t i = 0U; i < ARRAY_SIZE(t194_scr_settings); i++) { + scr_val = mmio_read_32((uintptr_t)t194_scr_settings[i].scr_addr); + if (scr_val != t194_scr_settings[i].scr_val) { + ERROR("Mismatch at SCR addr = 0x%x\n", t194_scr_settings[i].scr_addr); + ret = false; + } + } + return ret; +} + +/******************************************************************************* + * Handler for early platform setup + ******************************************************************************/ +void plat_early_platform_setup(void) +{ + const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint8_t enable_ccplex_lock_step = params_from_bl2->enable_ccplex_lock_step; + uint64_t actlr_elx; + + /* Verify chip id is t194 */ + assert(tegra_chipid_is_t194()); + + /* Verify SCR settings */ + if (tegra_platform_is_silicon()) { + assert(tegra194_is_scr_valid()); + } + + /* sanity check MCE firmware compatibility */ + mce_verify_firmware_version(); + +#if ENABLE_FEAT_RAS + /* Enable Uncorrectable RAS error */ + tegra194_ras_enable(); +#endif + + /* + * Program XUSB STREAMIDs + * ====================== + * T19x XUSB has support for XUSB virtualization. It will have one + * physical function (PF) and four Virtual function (VF) + * + * There were below two SIDs for XUSB until T186. + * 1) #define TEGRA_SID_XUSB_HOST 0x1bU + * 2) #define TEGRA_SID_XUSB_DEV 0x1cU + * + * We have below four new SIDs added for VF(s) + * 3) #define TEGRA_SID_XUSB_VF0 0x5dU + * 4) #define TEGRA_SID_XUSB_VF1 0x5eU + * 5) #define TEGRA_SID_XUSB_VF2 0x5fU + * 6) #define TEGRA_SID_XUSB_VF3 0x60U + * + * When virtualization is enabled then we have to disable SID override + * and program above SIDs in below newly added SID registers in XUSB + * PADCTL MMIO space. These registers are TZ protected and so need to + * be done in ATF. + * a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU) + * b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU) + * c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U) + * d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U) + * e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U) + * f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU) + * + * This change disables SID override and programs XUSB SIDs in + * above registers to support both virtualization and + * non-virtualization platforms + */ + if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) { + + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_HOST); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_0) == TEGRA_SID_XUSB_VF0); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_1) == TEGRA_SID_XUSB_VF1); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_2) == TEGRA_SID_XUSB_VF2); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_HOST_AXI_STREAMID_VF_3) == TEGRA_SID_XUSB_VF3); + mmio_write_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV); + assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE + + XUSB_PADCTL_DEV_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_DEV); + } + + /* + * Enable dual execution optimized translations for all ELx. + */ + if (enable_ccplex_lock_step != 0U) { + actlr_elx = read_actlr_el3(); + actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL3; + write_actlr_el3(actlr_elx); + /* check if the bit is actually set */ + assert((read_actlr_el3() & DENVER_CPU_ENABLE_DUAL_EXEC_EL3) != 0ULL); + + actlr_elx = read_actlr_el2(); + actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL2; + write_actlr_el2(actlr_elx); + /* check if the bit is actually set */ + assert((read_actlr_el2() & DENVER_CPU_ENABLE_DUAL_EXEC_EL2) != 0ULL); + + actlr_elx = read_actlr_el1(); + actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL1; + write_actlr_el1(actlr_elx); + /* check if the bit is actually set */ + assert((read_actlr_el1() & DENVER_CPU_ENABLE_DUAL_EXEC_EL1) != 0ULL); + } +} + +/* Secure IRQs for Tegra194 */ +static const interrupt_prop_t tegra194_interrupt_props[] = { + INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI, + GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(TEGRA194_TOP_WDT_IRQ, PLAT_TEGRA_WDT_PRIO, + GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE) +}; + +/******************************************************************************* + * Initialize the GIC and SGIs + ******************************************************************************/ +void plat_gic_setup(void) +{ + tegra_gic_setup(tegra194_interrupt_props, ARRAY_SIZE(tegra194_interrupt_props)); + tegra_gic_init(); + + /* + * Initialize the FIQ handler + */ + tegra_fiq_handler_setup(); +} + +/******************************************************************************* + * Return pointer to the BL31 params from previous bootloader + ******************************************************************************/ +struct tegra_bl31_params *plat_get_bl31_params(void) +{ + uint64_t val; + + val = (mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_HI_ADDR) & + SCRATCH_BL31_PARAMS_HI_ADDR_MASK) >> SCRATCH_BL31_PARAMS_HI_ADDR_SHIFT; + val <<= 32; + val |= mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_LO_ADDR); + + return (struct tegra_bl31_params *)(uintptr_t)val; +} + +/******************************************************************************* + * Return pointer to the BL31 platform params from previous bootloader + ******************************************************************************/ +plat_params_from_bl2_t *plat_get_bl31_plat_params(void) +{ + uint64_t val; + + val = (mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_HI_ADDR) & + SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_MASK) >> SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_SHIFT; + val <<= 32; + val |= mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_LO_ADDR); + + return (plat_params_from_bl2_t *)(uintptr_t)val; +} + +/******************************************************************************* + * Handler for late platform setup + ******************************************************************************/ +void plat_late_platform_setup(void) +{ +#if ENABLE_STRICT_CHECKING_MODE + /* + * Enable strict checking after programming the GSC for + * enabling TZSRAM and TZDRAM + */ + mce_enable_strict_checking(); + mce_verify_strict_checking(); +#endif +} + +/******************************************************************************* + * Handler to indicate support for System Suspend + ******************************************************************************/ +bool plat_supports_system_suspend(void) +{ + return true; +} + +/******************************************************************************* + * Platform specific runtime setup. + ******************************************************************************/ +void plat_runtime_setup(void) +{ + /* + * During cold boot, it is observed that the arbitration + * bit is set in the Memory controller leading to false + * error interrupts in the non-secure world. To avoid + * this, clean the interrupt status register before + * booting into the non-secure world + */ + tegra_memctrl_clear_pending_interrupts(); + + /* + * During boot, USB3 and flash media (SDMMC/SATA) devices need + * access to IRAM. Because these clients connect to the MC and + * do not have a direct path to the IRAM, the MC implements AHB + * redirection during boot to allow path to IRAM. In this mode + * accesses to a programmed memory address aperture are directed + * to the AHB bus, allowing access to the IRAM. This mode must be + * disabled before we jump to the non-secure world. + */ + tegra_memctrl_disable_ahb_redirection(); + + /* + * Verify the integrity of the previously configured SMMU(s) settings + */ + tegra_smmu_verify(); +} diff --git a/plat/nvidia/tegra/soc/t194/plat_sip_calls.c b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c new file mode 100644 index 0000000..6e42e64 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <common/bl_common.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <common/debug.h> +#include <errno.h> +#include <mce.h> +#include <mce_private.h> +#include <memctrl.h> +#include <common/runtime_svc.h> +#include <tegra_private.h> +#include <tegra_platform.h> +#include <smmu.h> +#include <stdbool.h> + +/******************************************************************************* + * Tegra194 SiP SMCs + ******************************************************************************/ +#define TEGRA_SIP_GET_SMMU_PER 0xC200FF00U +#define TEGRA_SIP_CLEAR_RAS_CORRECTED_ERRORS 0xC200FF01U + +/******************************************************************************* + * This function is responsible for handling all T194 SiP calls + ******************************************************************************/ +int32_t plat_sip_handler(uint32_t smc_fid, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + const void *cookie, + void *handle, + uint64_t flags) +{ + int32_t ret = 0; + uint32_t i, smmu_per[6] = {0}; + uint32_t num_smmu_devices = plat_get_num_smmu_devices(); + uint64_t per[3] = {0ULL}; + + (void)x1; + (void)x4; + (void)cookie; + (void)flags; + + switch (smc_fid) { + case TEGRA_SIP_GET_SMMU_PER: + + /* make sure we dont go past the array length */ + assert(num_smmu_devices <= ARRAY_SIZE(smmu_per)); + + /* read all supported SMMU_PER records */ + for (i = 0U; i < num_smmu_devices; i++) { + smmu_per[i] = tegra_smmu_read_32(i, SMMU_GSR0_PER); + } + + /* pack results into 3 64bit variables. */ + per[0] = smmu_per[0] | ((uint64_t)smmu_per[1] << 32U); + per[1] = smmu_per[2] | ((uint64_t)smmu_per[3] << 32U); + per[2] = smmu_per[4] | ((uint64_t)smmu_per[5] << 32U); + + /* provide the results via X1-X3 CPU registers */ + write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, per[0]); + write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X2, per[1]); + write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X3, per[2]); + + break; + +#if ENABLE_FEAT_RAS + case TEGRA_SIP_CLEAR_RAS_CORRECTED_ERRORS: + { + /* + * clear all RAS error records for corrected errors at first. + * x1 shall be 0 for first SMC call after FHI is asserted. + * */ + uint64_t local_x1 = x1; + + tegra194_ras_corrected_err_clear(&local_x1); + if (local_x1 == 0ULL) { + /* clear HSM corrected error status after all corrected + * RAS errors are cleared. + */ + mce_clear_hsm_corr_status(); + } + + write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, local_x1); + + break; + } +#endif + + default: + ret = -ENOTSUP; + break; + } + + return ret; +} diff --git a/plat/nvidia/tegra/soc/t194/plat_smmu.c b/plat/nvidia/tegra/soc/t194/plat_smmu.c new file mode 100644 index 0000000..710d5c5 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_smmu.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/bl_common.h> +#include <common/debug.h> +#include <smmu.h> +#include <tegra_def.h> + +#define BOARD_SYSTEM_FPGA_BASE U(1) +#define BASE_CONFIG_SMMU_DEVICES U(2) +#define MAX_NUM_SMMU_DEVICES U(3) + +static uint32_t tegra_misc_read_32(uint32_t off) +{ + return mmio_read_32((uintptr_t)TEGRA_MISC_BASE + off); +} + +/******************************************************************************* + * Handler to return the support SMMU devices number + ******************************************************************************/ +uint32_t plat_get_num_smmu_devices(void) +{ + uint32_t ret_num = MAX_NUM_SMMU_DEVICES; + uint32_t board_revid = ((tegra_misc_read_32(MISCREG_EMU_REVID) >> + BOARD_SHIFT_BITS) & BOARD_MASK_BITS); + + if (board_revid == BOARD_SYSTEM_FPGA_BASE) { + ret_num = BASE_CONFIG_SMMU_DEVICES; + } + + return ret_num; +} diff --git a/plat/nvidia/tegra/soc/t194/plat_trampoline.S b/plat/nvidia/tegra/soc/t194/plat_trampoline.S new file mode 100644 index 0000000..0ff5407 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_trampoline.S @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <plat/common/common_def.h> +#include <memctrl_v2.h> +#include <tegra_def.h> + +#define TEGRA194_STATE_SYSTEM_SUSPEND 0x5C7 +#define TEGRA194_STATE_SYSTEM_RESUME 0x600D +#define TEGRA194_MC_CTX_SIZE 0xFB + + .align 4 + .globl tegra194_cpu_reset_handler + +/* CPU reset handler routine */ +func tegra194_cpu_reset_handler + /* check if we are exiting system suspend state */ + adr x0, __tegra194_system_suspend_state + ldr x1, [x0] + mov x2, #TEGRA194_STATE_SYSTEM_SUSPEND + lsl x2, x2, #16 + add x2, x2, #TEGRA194_STATE_SYSTEM_SUSPEND + cmp x1, x2 + bne boot_cpu + + /* set system resume state */ + mov x1, #TEGRA194_STATE_SYSTEM_RESUME + lsl x1, x1, #16 + mov x2, #TEGRA194_STATE_SYSTEM_RESUME + add x1, x1, x2 + str x1, [x0] + dsb sy + + /* prepare to relocate to TZSRAM */ + mov x0, #BL31_BASE + adr x1, __tegra194_cpu_reset_handler_end + adr x2, __tegra194_cpu_reset_handler_data + ldr x2, [x2, #8] + + /* memcpy16 */ +m_loop16: + cmp x2, #16 + b.lt m_loop1 + ldp x3, x4, [x1], #16 + stp x3, x4, [x0], #16 + sub x2, x2, #16 + b m_loop16 + /* copy byte per byte */ +m_loop1: + cbz x2, boot_cpu + ldrb w3, [x1], #1 + strb w3, [x0], #1 + subs x2, x2, #1 + b.ne m_loop1 + + /* + * Synchronization barriers to make sure that memory is flushed out + * before we start execution in SysRAM. + */ + dsb sy + isb + +boot_cpu: + adr x0, __tegra194_cpu_reset_handler_data + ldr x0, [x0] + br x0 +endfunc tegra194_cpu_reset_handler + + /* + * Tegra194 reset data (offset 0x0 - 0x2490) + * + * 0x0000: secure world's entrypoint + * 0x0008: BL31 size (RO + RW) + * 0x0010: MC context start + * 0x2490: MC context end + */ + + .align 4 + .type __tegra194_cpu_reset_handler_data, %object + .globl __tegra194_cpu_reset_handler_data +__tegra194_cpu_reset_handler_data: + .quad tegra_secure_entrypoint + .quad __BL31_END__ - BL31_BASE + .globl __tegra194_system_suspend_state +__tegra194_system_suspend_state: + .quad 0 + + .align 4 +__tegra194_mc_context: + .rept TEGRA194_MC_CTX_SIZE + .quad 0 + .endr + .size __tegra194_cpu_reset_handler_data, \ + . - __tegra194_cpu_reset_handler_data + + .align 4 + .globl __tegra194_cpu_reset_handler_end +__tegra194_cpu_reset_handler_end: + + .globl tegra194_get_cpu_reset_handler_size + .globl tegra194_get_cpu_reset_handler_base + .globl tegra194_get_mc_ctx_offset + .globl tegra194_set_system_suspend_entry + +/* return size of the CPU reset handler */ +func tegra194_get_cpu_reset_handler_size + adr x0, __tegra194_cpu_reset_handler_end + adr x1, tegra194_cpu_reset_handler + sub x0, x0, x1 + ret +endfunc tegra194_get_cpu_reset_handler_size + +/* return the start address of the CPU reset handler */ +func tegra194_get_cpu_reset_handler_base + adr x0, tegra194_cpu_reset_handler + ret +endfunc tegra194_get_cpu_reset_handler_base + +/* return the size of the MC context */ +func tegra194_get_mc_ctx_offset + adr x0, __tegra194_mc_context + adr x1, tegra194_cpu_reset_handler + sub x0, x0, x1 + ret +endfunc tegra194_get_mc_ctx_offset + +/* set system suspend state before SC7 entry */ +func tegra194_set_system_suspend_entry + mov x0, #TEGRA_MC_BASE + mov x3, #MC_SECURITY_CFG3_0 + ldr w1, [x0, x3] + lsl x1, x1, #32 + mov x3, #MC_SECURITY_CFG0_0 + ldr w2, [x0, x3] + orr x3, x1, x2 /* TZDRAM base */ + adr x0, __tegra194_system_suspend_state + adr x1, tegra194_cpu_reset_handler + sub x2, x0, x1 /* offset in TZDRAM */ + mov x0, #TEGRA194_STATE_SYSTEM_SUSPEND + lsl x0, x0, #16 + add x0, x0, #TEGRA194_STATE_SYSTEM_SUSPEND + str x0, [x3, x2] /* set value in TZDRAM */ + dsb sy + ret +endfunc tegra194_set_system_suspend_entry diff --git a/plat/nvidia/tegra/soc/t194/platform_t194.mk b/plat/nvidia/tegra/soc/t194/platform_t194.mk new file mode 100644 index 0000000..e6e0b5e --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/platform_t194.mk @@ -0,0 +1,88 @@ +# +# Copyright (c) 2019-2023, NVIDIA CORPORATION. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include common/fdt_wrappers.mk + +ARM_ARCH_MAJOR := 8 +ARM_ARCH_MINOR := 2 + +# platform configs +ENABLE_CONSOLE_SPE := 1 +$(eval $(call add_define,ENABLE_CONSOLE_SPE)) + +ENABLE_STRICT_CHECKING_MODE := 1 +$(eval $(call add_define,ENABLE_STRICT_CHECKING_MODE)) + +USE_GPC_DMA := 1 +$(eval $(call add_define,USE_GPC_DMA)) + +RESET_TO_BL31 := 1 + +PROGRAMMABLE_RESET_ADDRESS := 1 + +COLD_BOOT_SINGLE_CPU := 1 + +# platform settings +TZDRAM_BASE := 0x40000000 +$(eval $(call add_define,TZDRAM_BASE)) + +MAX_XLAT_TABLES := 25 +$(eval $(call add_define,MAX_XLAT_TABLES)) + +MAX_MMAP_REGIONS := 30 +$(eval $(call add_define,MAX_MMAP_REGIONS)) + +# enable RAS handling +HANDLE_EA_EL3_FIRST_NS := 1 +ENABLE_FEAT_RAS := 1 + +# platform files +PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t194 \ + -I${SOC_DIR}/drivers/include + +BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \ + drivers/ti/uart/aarch64/16550_console.S \ + lib/cpus/aarch64/denver.S \ + ${TEGRA_DRIVERS}/bpmp_ipc/intf.c \ + ${TEGRA_DRIVERS}/bpmp_ipc/ivc.c \ + ${TEGRA_DRIVERS}/memctrl/memctrl_v2.c \ + ${TEGRA_DRIVERS}/smmu/smmu.c \ + ${SOC_DIR}/drivers/mce/mce.c \ + ${SOC_DIR}/drivers/mce/nvg.c \ + ${SOC_DIR}/drivers/mce/aarch64/nvg_helpers.S \ + ${SOC_DIR}/drivers/se/se.c \ + ${SOC_DIR}/plat_memctrl.c \ + ${SOC_DIR}/plat_psci_handlers.c \ + ${SOC_DIR}/plat_setup.c \ + ${SOC_DIR}/plat_secondary.c \ + ${SOC_DIR}/plat_sip_calls.c \ + ${SOC_DIR}/plat_smmu.c \ + ${SOC_DIR}/plat_trampoline.S + +ifeq (${USE_GPC_DMA}, 1) +BL31_SOURCES += ${TEGRA_DRIVERS}/gpcdma/gpcdma.c +endif + +ifeq (${ENABLE_CONSOLE_SPE},1) +BL31_SOURCES += ${TEGRA_DRIVERS}/spe/shared_console.S +endif + +# RAS sources +ifeq (${ENABLE_FEAT_RAS}-${HANDLE_EA_EL3_FIRST_NS},1-1) +BL31_SOURCES += lib/extensions/ras/std_err_record.c \ + lib/extensions/ras/ras_common.c \ + ${SOC_DIR}/plat_ras.c +endif + +# SPM dispatcher +ifeq (${SPD},spmd) +include lib/libfdt/libfdt.mk +# sources to support spmd +BL31_SOURCES += plat/common/plat_spmd_manifest.c \ + ${LIBFDT_SRCS} + +BL31_SOURCES += ${FDT_WRAPPERS_SOURCES} +endif |