GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+79
@@ -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 */
|
||||
+15
@@ -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 */
|
||||
+429
@@ -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
|
||||
* compatiblity 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 */
|
||||
+52
@@ -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
|
||||
+255
@@ -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();
|
||||
}
|
||||
+262
@@ -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);
|
||||
}
|
||||
+511
@@ -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);
|
||||
}
|
||||
+165
@@ -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 */
|
||||
+83
@@ -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();
|
||||
}
|
||||
}
|
||||
+505
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* 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(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;
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
/*
|
||||
* 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;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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 errror 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 RAS_EXTENSION
|
||||
tegra194_ea_handler(ea_reason, syndrome, cookie, handle, flags);
|
||||
#else
|
||||
plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags);
|
||||
#endif
|
||||
}
|
||||
+75
@@ -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);
|
||||
}
|
||||
+449
@@ -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 RAS_EXTENSION
|
||||
/* 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();
|
||||
}
|
||||
+103
@@ -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 RAS_EXTENSION
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+150
@@ -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
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
#
|
||||
# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
include common/fdt_wrappers.mk
|
||||
|
||||
# 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
|
||||
RAS_EXTENSION := 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 (${RAS_EXTENSION},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
|
||||
Reference in New Issue
Block a user