diff options
Diffstat (limited to 'plat/nvidia/tegra/soc/t186')
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h | 260 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h | 437 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S | 31 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/mce/ari.c | 564 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/mce/mce.c | 476 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c | 256 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/se/se.c | 277 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/drivers/se/se_private.h | 100 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_memctrl.c | 700 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_psci_handlers.c | 472 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_secondary.c | 41 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_setup.c | 397 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_sip_calls.c | 159 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_smmu.c | 22 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/plat_trampoline.S | 41 | ||||
-rw-r--r-- | plat/nvidia/tegra/soc/t186/platform_t186.mk | 77 |
16 files changed, 4310 insertions, 0 deletions
diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h b/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h new file mode 100644 index 0000000..203f61a --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MCE_PRIVATE_H +#define MCE_PRIVATE_H + +#include <lib/mmio.h> + +#include <tegra_def.h> + +/******************************************************************************* + * Macros to prepare CSTATE info request + ******************************************************************************/ +/* Description of the parameters for UPDATE_CSTATE_INFO request */ +#define CLUSTER_CSTATE_MASK ULL(0x7) +#define CLUSTER_CSTATE_SHIFT U(0) +#define CLUSTER_CSTATE_UPDATE_BIT (ULL(1) << 7) +#define CCPLEX_CSTATE_MASK ULL(0x3) +#define CCPLEX_CSTATE_SHIFT ULL(8) +#define CCPLEX_CSTATE_UPDATE_BIT (ULL(1) << 15) +#define SYSTEM_CSTATE_MASK ULL(0xF) +#define SYSTEM_CSTATE_SHIFT ULL(16) +#define SYSTEM_CSTATE_FORCE_UPDATE_SHIFT ULL(22) +#define SYSTEM_CSTATE_FORCE_UPDATE_BIT (ULL(1) << 22) +#define SYSTEM_CSTATE_UPDATE_BIT (ULL(1) << 23) +#define CSTATE_WAKE_MASK_UPDATE_BIT (ULL(1) << 31) +#define CSTATE_WAKE_MASK_SHIFT ULL(32) +#define CSTATE_WAKE_MASK_CLEAR U(0xFFFFFFFF) + +/******************************************************************************* + * Auto-CC3 control macros + ******************************************************************************/ +#define MCE_AUTO_CC3_FREQ_MASK U(0x1FF) +#define MCE_AUTO_CC3_FREQ_SHIFT U(0) +#define MCE_AUTO_CC3_VTG_MASK U(0x7F) +#define MCE_AUTO_CC3_VTG_SHIFT U(16) +#define MCE_AUTO_CC3_ENABLE_BIT (U(1) << 31) + +/******************************************************************************* + * Macros for the 'IS_SC7_ALLOWED' command + ******************************************************************************/ +#define MCE_SC7_ALLOWED_MASK U(0x7) +#define MCE_SC7_WAKE_TIME_SHIFT U(32) + +/******************************************************************************* + * Macros for 'read/write ctats' commands + ******************************************************************************/ +#define MCE_CSTATE_STATS_TYPE_SHIFT ULL(32) +#define MCE_CSTATE_WRITE_DATA_LO_MASK U(0xF) + +/******************************************************************************* + * Macros for 'update crossover threshold' command + ******************************************************************************/ +#define MCE_CROSSOVER_THRESHOLD_TIME_SHIFT U(32) + +/******************************************************************************* + * MCA argument macros + ******************************************************************************/ +#define MCA_ARG_ERROR_MASK U(0xFF) +#define MCA_ARG_FINISH_SHIFT U(24) +#define MCA_ARG_FINISH_MASK U(0xFF) + +/******************************************************************************* + * Uncore PERFMON ARI macros + ******************************************************************************/ +#define UNCORE_PERFMON_CMD_READ U(0) +#define UNCORE_PERFMON_CMD_WRITE U(1) + +#define UNCORE_PERFMON_CMD_MASK U(0xFF) +#define UNCORE_PERFMON_UNIT_GRP_MASK U(0xF) +#define UNCORE_PERFMON_SELECTOR_MASK U(0xF) +#define UNCORE_PERFMON_REG_MASK U(0xFF) +#define UNCORE_PERFMON_CTR_MASK U(0xFF) +#define UNCORE_PERFMON_RESP_STATUS_MASK U(0xFF) + +/******************************************************************************* + * Structure populated by arch specific code to export routines which perform + * common low level MCE functions + ******************************************************************************/ +typedef struct arch_mce_ops { + /* + * This ARI request sets up the MCE to start execution on assertion + * of STANDBYWFI, update the core power state and expected wake time, + * then determine the proper power state to enter. + */ + int32_t (*enter_cstate)(uint32_t ari_base, uint32_t state, + uint32_t wake_time); + /* + * This ARI request allows updating of the CLUSTER_CSTATE, + * CCPLEX_CSTATE, and SYSTEM_CSTATE register values. + */ + int32_t (*update_cstate_info)(uint32_t ari_base, + uint32_t cluster, + uint32_t ccplex, + uint32_t system, + uint8_t sys_state_force, + uint32_t wake_mask, + uint8_t update_wake_mask); + /* + * This ARI request allows updating of power state crossover + * threshold times. An index value specifies which crossover + * state is being updated. + */ + int32_t (*update_crossover_time)(uint32_t ari_base, + uint32_t type, + uint32_t time); + /* + * This ARI request allows read access to statistical information + * related to power states. + */ + uint64_t (*read_cstate_stats)(uint32_t ari_base, + uint32_t state); + /* + * This ARI request allows write access to statistical information + * related to power states. + */ + int32_t (*write_cstate_stats)(uint32_t ari_base, + uint32_t state, + uint32_t stats); + /* + * This ARI request allows the CPU to understand the features + * supported by the MCE firmware. + */ + uint64_t (*call_enum_misc)(uint32_t ari_base, uint32_t cmd, + uint32_t data); + /* + * This ARI request allows querying the CCPLEX to determine if + * the CCx state is allowed given a target core C-state and wake + * time. If the CCx state is allowed, the response indicates CCx + * must be entered. If the CCx state is not allowed, the response + * indicates CC6/CC7 can't be entered + */ + int32_t (*is_ccx_allowed)(uint32_t ari_base, uint32_t state, + uint32_t wake_time); + /* + * This ARI request allows querying the CCPLEX to determine if + * the SC7 state is allowed given a target core C-state and wake + * time. If the SC7 state is allowed, all cores but the associated + * core are offlined (WAKE_EVENTS are set to 0) and the response + * indicates SC7 must be entered. If the SC7 state is not allowed, + * the response indicates SC7 can't be entered + */ + int32_t (*is_sc7_allowed)(uint32_t ari_base, uint32_t state, + uint32_t wake_time); + /* + * This ARI request allows a core to bring another offlined core + * back online to the C0 state. Note that a core is offlined by + * entering a C-state where the WAKE_MASK is all 0. + */ + int32_t (*online_core)(uint32_t ari_base, uint32_t cpuid); + /* + * This ARI request allows the CPU to enable/disable Auto-CC3 idle + * state. + */ + int32_t (*cc3_ctrl)(uint32_t ari_base, + uint32_t freq, + uint32_t volt, + uint8_t enable); + /* + * This ARI request allows updating the reset vector register for + * D15 and A57 CPUs. + */ + int32_t (*update_reset_vector)(uint32_t ari_base); + /* + * This ARI request instructs the ROC to flush A57 data caches in + * order to maintain coherency with the Denver cluster. + */ + int32_t (*roc_flush_cache)(uint32_t ari_base); + /* + * This ARI request instructs the ROC to flush A57 data caches along + * with the caches covering ARM code in order to maintain coherency + * with the Denver cluster. + */ + int32_t (*roc_flush_cache_trbits)(uint32_t ari_base); + /* + * This ARI request instructs the ROC to clean A57 data caches along + * with the caches covering ARM code in order to maintain coherency + * with the Denver cluster. + */ + int32_t (*roc_clean_cache)(uint32_t ari_base); + /* + * This ARI request reads/writes the Machine Check Arch. (MCA) + * registers. + */ + uint64_t (*read_write_mca)(uint32_t ari_base, + uint64_t cmd, + uint64_t *data); + /* + * Some MC GSC (General Security Carveout) register values are + * expected to be changed by TrustZone secure ARM code after boot. + * Since there is no hardware mechanism for the CCPLEX to know + * that an MC GSC register has changed to allow it to update its + * own internal GSC register, there needs to be a mechanism that + * can be used by ARM code to cause the CCPLEX to update its GSC + * register value. This ARI request allows updating the GSC register + * value for a certain carveout in the CCPLEX. + */ + int32_t (*update_ccplex_gsc)(uint32_t ari_base, uint32_t gsc_idx); + /* + * This ARI request instructs the CCPLEX to either shutdown or + * reset the entire system + */ + void (*enter_ccplex_state)(uint32_t ari_base, uint32_t state_idx); + /* + * This ARI request reads/writes data from/to Uncore PERFMON + * registers + */ + int32_t (*read_write_uncore_perfmon)(uint32_t ari_base, + uint64_t req, uint64_t *data); + /* + * This ARI implements ARI_MISC_CCPLEX commands. This can be + * used to enable/disable coresight clock gating. + */ + void (*misc_ccplex)(uint32_t ari_base, uint32_t index, + uint32_t value); +} arch_mce_ops_t; + +/* declarations for ARI/NVG handler functions */ +int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, + uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, + uint8_t update_wake_mask); +int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time); +uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state); +int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats); +uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data); +int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int32_t ari_online_core(uint32_t ari_base, uint32_t core); +int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable); +int32_t ari_reset_vector_update(uint32_t ari_base); +int32_t ari_roc_flush_cache_trbits(uint32_t ari_base); +int32_t ari_roc_flush_cache(uint32_t ari_base); +int32_t ari_roc_clean_cache(uint32_t ari_base); +uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data); +int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx); +void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx); +int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, + uint64_t req, uint64_t *data); +void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value); + +int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, + uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, + uint8_t update_wake_mask); +int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time); +uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state); +int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats); +int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int32_t nvg_online_core(uint32_t ari_base, uint32_t core); +int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable); + +extern void nvg_set_request_data(uint64_t req, uint64_t data); +extern void nvg_set_request(uint64_t req); +extern uint64_t nvg_get_result(void); +#endif /* MCE_PRIVATE_H */ diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h b/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h new file mode 100644 index 0000000..ecfb3f4 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef T18X_ARI_H +#define T18X_ARI_H + +/* + * ---------------------------------------------------------------------------- + * t18x_ari.h + * + * Global ARI definitions. + * ---------------------------------------------------------------------------- + */ + +enum { + TEGRA_ARI_VERSION_MAJOR = 3U, + TEGRA_ARI_VERSION_MINOR = 1U, +}; + +typedef enum { + /* indexes below get the core lock */ + TEGRA_ARI_MISC = 0U, + /* index 1 is deprecated */ + /* index 2 is deprecated */ + /* index 3 is deprecated */ + TEGRA_ARI_ONLINE_CORE = 4U, + + /* indexes below need cluster lock */ + TEGRA_ARI_MISC_CLUSTER = 41U, + TEGRA_ARI_IS_CCX_ALLOWED = 42U, + TEGRA_ARI_CC3_CTRL = 43U, + + /* indexes below need ccplex lock */ + TEGRA_ARI_ENTER_CSTATE = 80U, + TEGRA_ARI_UPDATE_CSTATE_INFO = 81U, + TEGRA_ARI_IS_SC7_ALLOWED = 82U, + /* index 83 is deprecated */ + TEGRA_ARI_PERFMON = 84U, + TEGRA_ARI_UPDATE_CCPLEX_GSC = 85U, + /* index 86 is depracated */ + /* index 87 is deprecated */ + TEGRA_ARI_ROC_FLUSH_CACHE_ONLY = 88U, + TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS = 89U, + TEGRA_ARI_MISC_CCPLEX = 90U, + TEGRA_ARI_MCA = 91U, + TEGRA_ARI_UPDATE_CROSSOVER = 92U, + TEGRA_ARI_CSTATE_STATS = 93U, + TEGRA_ARI_WRITE_CSTATE_STATS = 94U, + TEGRA_ARI_COPY_MISCREG_AA64_RST = 95U, + TEGRA_ARI_ROC_CLEAN_CACHE_ONLY = 96U, +} tegra_ari_req_id_t; + +typedef enum { + TEGRA_ARI_MISC_ECHO = 0U, + TEGRA_ARI_MISC_VERSION = 1U, + TEGRA_ARI_MISC_FEATURE_LEAF_0 = 2U, +} tegra_ari_misc_index_t; + +typedef enum { + TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF = 0U, + TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT = 1U, + TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL = 2U, + TEGRA_ARI_MISC_CCPLEX_EDBGREQ = 3U, +} tegra_ari_misc_ccplex_index_t; + +typedef enum { + TEGRA_ARI_CORE_C0 = 0U, + TEGRA_ARI_CORE_C1 = 1U, + TEGRA_ARI_CORE_C6 = 6U, + TEGRA_ARI_CORE_C7 = 7U, + TEGRA_ARI_CORE_WARMRSTREQ = 8U, +} tegra_ari_core_sleep_state_t; + +typedef enum { + TEGRA_ARI_CLUSTER_CC0 = 0U, + TEGRA_ARI_CLUSTER_CC1 = 1U, + TEGRA_ARI_CLUSTER_CC6 = 6U, + TEGRA_ARI_CLUSTER_CC7 = 7U, +} tegra_ari_cluster_sleep_state_t; + +typedef enum { + TEGRA_ARI_CCPLEX_CCP0 = 0U, + TEGRA_ARI_CCPLEX_CCP1 = 1U, + TEGRA_ARI_CCPLEX_CCP3 = 3U, /* obsoleted */ +} tegra_ari_ccplex_sleep_state_t; + +typedef enum { + TEGRA_ARI_SYSTEM_SC0 = 0U, + TEGRA_ARI_SYSTEM_SC1 = 1U, /* obsoleted */ + TEGRA_ARI_SYSTEM_SC2 = 2U, /* obsoleted */ + TEGRA_ARI_SYSTEM_SC3 = 3U, /* obsoleted */ + TEGRA_ARI_SYSTEM_SC4 = 4U, /* obsoleted */ + TEGRA_ARI_SYSTEM_SC7 = 7U, + TEGRA_ARI_SYSTEM_SC8 = 8U, +} tegra_ari_system_sleep_state_t; + +typedef enum { + TEGRA_ARI_CROSSOVER_C1_C6 = 0U, + TEGRA_ARI_CROSSOVER_CC1_CC6 = 1U, + TEGRA_ARI_CROSSOVER_CC1_CC7 = 2U, + TEGRA_ARI_CROSSOVER_CCP1_CCP3 = 3U, /* obsoleted */ + TEGRA_ARI_CROSSOVER_CCP3_SC2 = 4U, /* obsoleted */ + TEGRA_ARI_CROSSOVER_CCP3_SC3 = 5U, /* obsoleted */ + TEGRA_ARI_CROSSOVER_CCP3_SC4 = 6U, /* obsoleted */ + TEGRA_ARI_CROSSOVER_CCP3_SC7 = 7U, /* obsoleted */ + TEGRA_ARI_CROSSOVER_SC0_SC7 = 7U, + TEGRA_ARI_CROSSOVER_CCP3_SC1 = 8U, /* obsoleted */ +} tegra_ari_crossover_index_t; + +typedef enum { + TEGRA_ARI_CSTATE_STATS_CLEAR = 0U, + TEGRA_ARI_CSTATE_STATS_SC7_ENTRIES = 1U, + TEGRA_ARI_CSTATE_STATS_SC4_ENTRIES, /* obsoleted */ + TEGRA_ARI_CSTATE_STATS_SC3_ENTRIES, /* obsoleted */ + TEGRA_ARI_CSTATE_STATS_SC2_ENTRIES, /* obsoleted */ + TEGRA_ARI_CSTATE_STATS_CCP3_ENTRIES, /* obsoleted */ + TEGRA_ARI_CSTATE_STATS_A57_CC6_ENTRIES, + TEGRA_ARI_CSTATE_STATS_A57_CC7_ENTRIES, + TEGRA_ARI_CSTATE_STATS_D15_CC6_ENTRIES, + TEGRA_ARI_CSTATE_STATS_D15_CC7_ENTRIES, + TEGRA_ARI_CSTATE_STATS_D15_0_C6_ENTRIES, + TEGRA_ARI_CSTATE_STATS_D15_1_C6_ENTRIES, + TEGRA_ARI_CSTATE_STATS_D15_0_C7_ENTRIES = 14U, + TEGRA_ARI_CSTATE_STATS_D15_1_C7_ENTRIES, + TEGRA_ARI_CSTATE_STATS_A57_0_C7_ENTRIES = 18U, + TEGRA_ARI_CSTATE_STATS_A57_1_C7_ENTRIES, + TEGRA_ARI_CSTATE_STATS_A57_2_C7_ENTRIES, + TEGRA_ARI_CSTATE_STATS_A57_3_C7_ENTRIES, + TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0, + TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1, + TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 26U, + TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1, + TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2, + TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3, +} tegra_ari_cstate_stats_index_t; + +typedef enum { + TEGRA_ARI_GSC_ALL = 0U, + TEGRA_ARI_GSC_BPMP = 6U, + TEGRA_ARI_GSC_APE = 7U, + TEGRA_ARI_GSC_SPE = 8U, + TEGRA_ARI_GSC_SCE = 9U, + TEGRA_ARI_GSC_APR = 10U, + TEGRA_ARI_GSC_TZRAM = 11U, + TEGRA_ARI_GSC_SE = 12U, + TEGRA_ARI_GSC_BPMP_TO_SPE = 16U, + TEGRA_ARI_GSC_SPE_TO_BPMP = 17U, + TEGRA_ARI_GSC_CPU_TZ_TO_BPMP = 18U, + TEGRA_ARI_GSC_BPMP_TO_CPU_TZ = 19U, + TEGRA_ARI_GSC_CPU_NS_TO_BPMP = 20U, + TEGRA_ARI_GSC_BPMP_TO_CPU_NS = 21U, + TEGRA_ARI_GSC_IPC_SE_SPE_SCE_BPMP = 22U, + TEGRA_ARI_GSC_SC7_RESUME_FW = 23U, + TEGRA_ARI_GSC_TZ_DRAM_IDX = 34U, + TEGRA_ARI_GSC_VPR_IDX = 35U, +} tegra_ari_gsc_index_t; + +/* This macro will produce enums for __name##_LSB, __name##_MSB and __name##_MSK */ +#define TEGRA_ARI_ENUM_MASK_LSB_MSB(__name, __lsb, __msb) __name##_LSB = __lsb, __name##_MSB = __msb + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE, 0U, 2U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE_PRESENT, 7U, 7U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE, 8U, 9U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE_PRESENT, 15U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE, 16U, 19U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__IGNORE_CROSSOVERS, 22U, 22U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE_PRESENT, 23U, 23U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__WAKE_MASK_PRESENT, 31U, 31U), +} tegra_ari_update_cstate_info_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL__EN, 0U, 0U), +} tegra_ari_misc_ccplex_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_FREQ, 0U, 8U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_VOLT, 16U, 23U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__ENABLE, 31U, 31U), +} tegra_ari_cc3_ctrl_bitmasks_t; + +typedef enum { + TEGRA_ARI_MCA_NOP = 0U, + TEGRA_ARI_MCA_READ_SERR = 1U, + TEGRA_ARI_MCA_WRITE_SERR = 2U, + TEGRA_ARI_MCA_CLEAR_SERR = 4U, + TEGRA_ARI_MCA_REPORT_SERR = 5U, + TEGRA_ARI_MCA_READ_INTSTS = 6U, + TEGRA_ARI_MCA_WRITE_INTSTS = 7U, + TEGRA_ARI_MCA_READ_PREBOOT_SERR = 8U, +} tegra_ari_mca_commands_t; + +typedef enum { + TEGRA_ARI_MCA_RD_WR_DPMU = 0U, + TEGRA_ARI_MCA_RD_WR_IOB = 1U, + TEGRA_ARI_MCA_RD_WR_MCB = 2U, + TEGRA_ARI_MCA_RD_WR_CCE = 3U, + TEGRA_ARI_MCA_RD_WR_CQX = 4U, + TEGRA_ARI_MCA_RD_WR_CTU = 5U, + TEGRA_ARI_MCA_RD_WR_JSR_MTS = 7U, + TEGRA_ARI_MCA_RD_BANK_INFO = 0x0fU, + TEGRA_ARI_MCA_RD_BANK_TEMPLATE = 0x10U, + TEGRA_ARI_MCA_RD_WR_SECURE_ACCESS_REGISTER = 0x11U, + TEGRA_ARI_MCA_RD_WR_GLOBAL_CONFIG_REGISTER = 0x12U, +} tegra_ari_mca_rd_wr_indexes_t; + +typedef enum { + TEGRA_ARI_MCA_RD_WR_ASERRX_CTRL = 0U, + TEGRA_ARI_MCA_RD_WR_ASERRX_STATUS = 1U, + TEGRA_ARI_MCA_RD_WR_ASERRX_ADDR = 2U, + TEGRA_ARI_MCA_RD_WR_ASERRX_MISC1 = 3U, + TEGRA_ARI_MCA_RD_WR_ASERRX_MISC2 = 4U, +} tegra_ari_mca_read_asserx_subindexes_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_SETTING_ENABLES_NS_PERMITTED, 0U, 0U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_READING_STATUS_NS_PERMITTED, 1U, 1U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_PENDING_MCA_ERRORS_NS_PERMITTED, 2U, 2U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_CLEARING_MCA_INTERRUPTS_NS_PERMITTED, 3U, 3U), +} tegra_ari_mca_secure_register_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_SERR_ERR_CODE, 0U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM_ERR, 16U, 16U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_CRAB_ERR, 17U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_RD_WR_N, 18U, 18U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UCODE_ERR, 19U, 19U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM, 20U, 23U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_AV, 58U, 58U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_MV, 59U, 59U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_EN, 60U, 60U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UC, 61U, 61U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_OVF, 62U, 62U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_VAL, 63U, 63U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_ADDR, 0U, 41U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_UCODE_ERRCD, 42U, 52U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_PWM_ERR, 0U, 0U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_CRAB_ERR, 1U, 1U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_UCODE_ERR, 3U, 3U), +} tegra_ari_mca_aserr0_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_SERR_ERR_CODE, 0U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MSI_ERR, 16U, 16U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_IHI_ERR, 17U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CRI_ERR, 18U, 18U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MMCRAB_ERR, 19U, 19U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CSI_ERR, 20U, 20U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RD_WR_N, 21U, 21U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_REQ_ERRT, 22U, 23U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RESP_ERRT, 24U, 25U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AV, 58U, 58U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MV, 59U, 59U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_EN, 60U, 60U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_UC, 61U, 61U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_OVF, 62U, 62U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_VAL, 63U, 63U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AXI_ID, 0U, 7U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_ID, 8U, 27U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CID, 28U, 31U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CMD, 32U, 35U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MSI_ERR, 0U, 0U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_IHI_ERR, 1U, 1U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CRI_ERR, 2U, 2U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MMCRAB_ERR, 3U, 3U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CSI_ERR, 4U, 4U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_MISC_ADDR, 0U, 41U), +} tegra_ari_mca_aserr1_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SERR_ERR_CODE, 0U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MC_ERR, 16U, 16U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SYSRAM_ERR, 17U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_CLIENT_ID, 18U, 19U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_AV, 58U, 58U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MV, 59U, 59U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_EN, 60U, 60U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_UC, 61U, 61U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_OVF, 62U, 62U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_VAL, 63U, 63U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ID, 0U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_CMD, 18U, 21U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ADDR, 22U, 53U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_CTRL_EN_MC_ERR, 0U, 0U), +} tegra_ari_mca_aserr2_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_SERR_ERR_CODE, 0U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_TO_ERR, 16U, 16U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_STAT_ERR, 17U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_DST_ERR, 18U, 18U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UNC_ERR, 19U, 19U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MH_ERR, 20U, 20U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PERR, 21U, 21U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PSN_ERR, 22U, 22U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_AV, 58U, 58U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MV, 59U, 59U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_EN, 60U, 60U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UC, 61U, 61U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_OVF, 62U, 62U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_VAL, 63U, 63U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_CMD, 0U, 5U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_ADDR, 6U, 47U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TO, 0U, 0U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_DIV4, 1U, 1U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TLIMIT, 2U, 11U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_PSN_ERR_CORR_MSK, 12U, 25U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_MORE_INFO, 0U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TO_INFO, 18U, 43U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_SRC, 44U, 45U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TID, 46U, 52U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_TO_ERR, 0U, 0U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_STAT_ERR, 1U, 1U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_DST_ERR, 2U, 2U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_UNC_ERR, 3U, 3U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_MH_ERR, 4U, 4U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PERR, 5U, 5U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PSN_ERR, 6U, 19U), +} tegra_ari_mca_aserr3_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SERR_ERR_CODE, 0U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SRC_ERR, 16U, 16U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_DST_ERR, 17U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_REQ_ERR, 18U, 18U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_RSP_ERR, 19U, 19U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_AV, 58U, 58U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_MV, 59U, 59U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_EN, 60U, 60U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_UC, 61U, 61U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_OVF, 62U, 62U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_VAL, 63U, 63U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_CTRL_EN_CPE_ERR, 0U, 0U), +} tegra_ari_mca_aserr4_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_SERR_ERR_CODE, 0U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_CTUPAR, 16U, 16U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MULTI, 17U, 17U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_AV, 58U, 58U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MV, 59U, 59U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_EN, 60U, 60U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_UC, 61U, 61U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_OVF, 62U, 62U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_VAL, 63U, 63U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_SRC, 0U, 7U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ID, 8U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_DATA, 16U, 26U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_CMD, 32U, 35U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ADDR, 36U, 45U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_CTRL_EN_CTUPAR, 0U, 0U), +} tegra_ari_mca_aserr5_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_SERR_ERR_CODE, 0U, 15U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_AV, 58U, 58U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_MV, 59U, 59U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_EN, 60U, 60U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_UC, 61U, 61U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_OVF, 62U, 62U), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_VAL, 63U, 63U), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_ADDR_TBD_INFO, 0U, 63U), +} tegra_ari_mca_serr1_bitmasks_t; + +#undef TEGRA_ARI_ENUM_MASK_LSB_MSB + +typedef enum { + TEGRA_NVG_CHANNEL_PMIC = 0U, + TEGRA_NVG_CHANNEL_POWER_PERF = 1U, + TEGRA_NVG_CHANNEL_POWER_MODES = 2U, + TEGRA_NVG_CHANNEL_WAKE_TIME = 3U, + TEGRA_NVG_CHANNEL_CSTATE_INFO = 4U, + TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 = 5U, + TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC6 = 6U, + TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC7 = 7U, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP1_CCP3 = 8U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC2 = 9U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC3 = 10U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC4 = 11U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC7 = 12U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CROSSOVER_SC0_SC7 = 12U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR = 13U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC7_ENTRIES = 14U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC4_ENTRIES = 15U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC3_ENTRIES = 16U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC2_ENTRIES = 17U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_CCP3_ENTRIES = 18U, /* obsoleted */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC6_ENTRIES = 19U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC7_ENTRIES = 20U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC6_ENTRIES = 21U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC7_ENTRIES = 22U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C6_ENTRIES = 23U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C6_ENTRIES = 24U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C6_ENTRIES = 25U, /* Reserved (for Denver15 core 2) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C6_ENTRIES = 26U, /* Reserved (for Denver15 core 3) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C7_ENTRIES = 27U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C7_ENTRIES = 28U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C7_ENTRIES = 29U, /* Reserved (for Denver15 core 2) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C7_ENTRIES = 30U, /* Reserved (for Denver15 core 3) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_0_C7_ENTRIES = 31U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_1_C7_ENTRIES = 32U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_2_C7_ENTRIES = 33U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_3_C7_ENTRIES = 34U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0 = 35U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1 = 36U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_2 = 37U, /* Reserved (for Denver15 core 2) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_3 = 38U, /* Reserved (for Denver15 core 3) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 39U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1 = 40U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2 = 41U, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3 = 42U, + TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = 43U, + TEGRA_NVG_CHANNEL_ONLINE_CORE = 44U, + TEGRA_NVG_CHANNEL_CC3_CTRL = 45U, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC1 = 46U, /* obsoleted */ + TEGRA_NVG_CHANNEL_LAST_INDEX, +} tegra_nvg_channel_id_t; + +#endif /* T18X_ARI_H */ diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S new file mode 100644 index 0000000..e3591ce --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. 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 + +/* 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 diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c new file mode 100644 index 0000000..a57bc11 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. 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 <drivers/delay_timer.h> +#include <denver.h> +#include <lib/mmio.h> +#include <plat/common/platform.h> + +#include <mce_private.h> +#include <t18x_ari.h> + +/******************************************************************************* + * Register offsets for ARI request/results + ******************************************************************************/ +#define ARI_REQUEST 0x0U +#define ARI_REQUEST_EVENT_MASK 0x4U +#define ARI_STATUS 0x8U +#define ARI_REQUEST_DATA_LO 0xCU +#define ARI_REQUEST_DATA_HI 0x10U +#define ARI_RESPONSE_DATA_LO 0x14U +#define ARI_RESPONSE_DATA_HI 0x18U + +/* Status values for the current request */ +#define ARI_REQ_PENDING 1U +#define ARI_REQ_ONGOING 3U +#define ARI_REQUEST_VALID_BIT (1U << 8) +#define ARI_EVT_MASK_STANDBYWFI_BIT (1U << 7) + +/* default timeout (us) to wait for ARI completion */ +#define ARI_MAX_RETRY_COUNT U(2000000) + +/******************************************************************************* + * ARI helper functions + ******************************************************************************/ +static inline uint32_t ari_read_32(uint32_t ari_base, uint32_t reg) +{ + return mmio_read_32((uint64_t)ari_base + (uint64_t)reg); +} + +static inline void ari_write_32(uint32_t ari_base, uint32_t val, uint32_t reg) +{ + mmio_write_32((uint64_t)ari_base + (uint64_t)reg, val); +} + +static inline uint32_t ari_get_request_low(uint32_t ari_base) +{ + return ari_read_32(ari_base, ARI_REQUEST_DATA_LO); +} + +static inline uint32_t ari_get_request_high(uint32_t ari_base) +{ + return ari_read_32(ari_base, ARI_REQUEST_DATA_HI); +} + +static inline uint32_t ari_get_response_low(uint32_t ari_base) +{ + return ari_read_32(ari_base, ARI_RESPONSE_DATA_LO); +} + +static inline uint32_t ari_get_response_high(uint32_t ari_base) +{ + return ari_read_32(ari_base, ARI_RESPONSE_DATA_HI); +} + +static inline void ari_clobber_response(uint32_t ari_base) +{ + ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_LO); + ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_HI); +} + +static int32_t ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req, + uint32_t lo, uint32_t hi) +{ + uint32_t retries = (uint32_t)ARI_MAX_RETRY_COUNT; + uint32_t status; + int32_t ret = 0; + + /* program the request, event_mask, hi and lo registers */ + ari_write_32(ari_base, lo, ARI_REQUEST_DATA_LO); + ari_write_32(ari_base, hi, ARI_REQUEST_DATA_HI); + ari_write_32(ari_base, evt_mask, ARI_REQUEST_EVENT_MASK); + ari_write_32(ari_base, req | ARI_REQUEST_VALID_BIT, ARI_REQUEST); + + /* + * For commands that have an event trigger, we should bypass + * ARI_STATUS polling, since MCE is waiting for SW to trigger + * the event. + */ + if (evt_mask != 0U) { + ret = 0; + } else { + /* For shutdown/reboot commands, we dont have to check for timeouts */ + if ((req == TEGRA_ARI_MISC_CCPLEX) && + ((lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) || + (lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT))) { + ret = 0; + } else { + /* + * Wait for the command response for not more than the timeout + */ + while (retries != 0U) { + + /* read the command status */ + status = ari_read_32(ari_base, ARI_STATUS); + if ((status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) == 0U) { + break; + } + + /* delay 1 us */ + udelay(1); + + /* decrement the retry count */ + retries--; + } + + /* assert if the command timed out */ + if (retries == 0U) { + ERROR("ARI request timed out: req %d on CPU %d\n", + req, plat_my_core_pos()); + assert(retries != 0U); + } + } + } + + return ret; +} + +int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + int32_t ret = 0; + + /* check for allowed power state */ + if ((state != TEGRA_ARI_CORE_C0) && + (state != TEGRA_ARI_CORE_C1) && + (state != TEGRA_ARI_CORE_C6) && + (state != TEGRA_ARI_CORE_C7)) { + ERROR("%s: unknown cstate (%d)\n", __func__, state); + ret = EINVAL; + } else { + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* Enter the cstate, to be woken up after wake_time (TSC ticks) */ + ret = ari_request_wait(ari_base, ARI_EVT_MASK_STANDBYWFI_BIT, + (uint32_t)TEGRA_ARI_ENTER_CSTATE, state, wake_time); + } + + return ret; +} + +int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, + uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, + uint8_t update_wake_mask) +{ + uint64_t val = 0U; + + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* update CLUSTER_CSTATE? */ + if (cluster != 0U) { + val |= (cluster & CLUSTER_CSTATE_MASK) | + CLUSTER_CSTATE_UPDATE_BIT; + } + + /* update CCPLEX_CSTATE? */ + if (ccplex != 0U) { + val |= ((ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) | + CCPLEX_CSTATE_UPDATE_BIT; + } + + /* update SYSTEM_CSTATE? */ + if (system != 0U) { + val |= ((system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) | + (((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) | + SYSTEM_CSTATE_UPDATE_BIT); + } + + /* update wake mask value? */ + if (update_wake_mask != 0U) { + val |= CSTATE_WAKE_MASK_UPDATE_BIT; + } + + /* set the updated cstate info */ + return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_UPDATE_CSTATE_INFO, + (uint32_t)val, wake_mask); +} + +int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time) +{ + int32_t ret = 0; + + /* sanity check crossover type */ + if ((type == TEGRA_ARI_CROSSOVER_C1_C6) || + (type > TEGRA_ARI_CROSSOVER_CCP3_SC1)) { + ret = EINVAL; + } else { + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* update crossover threshold time */ + ret = ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_UPDATE_CROSSOVER, type, time); + } + + return ret; +} + +uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state) +{ + int32_t ret; + uint64_t result; + + /* sanity check crossover type */ + if (state == 0U) { + result = EINVAL; + } else { + /* clean the previous response state */ + ari_clobber_response(ari_base); + + ret = ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_CSTATE_STATS, state, 0U); + if (ret != 0) { + result = EINVAL; + } else { + result = (uint64_t)ari_get_response_low(ari_base); + } + } + return result; +} + +int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats) +{ + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* write the cstate stats */ + return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_WRITE_CSTATE_STATS, + state, stats); +} + +uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data) +{ + uint64_t resp; + int32_t ret; + uint32_t local_data = data; + + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* ARI_REQUEST_DATA_HI is reserved for commands other than 'ECHO' */ + if (cmd != TEGRA_ARI_MISC_ECHO) { + local_data = 0U; + } + + ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MISC, cmd, local_data); + if (ret != 0) { + resp = (uint64_t)ret; + } else { + /* get the command response */ + resp = ari_get_response_low(ari_base); + resp |= ((uint64_t)ari_get_response_high(ari_base) << 32); + } + + return resp; +} + +int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + int32_t ret; + uint32_t result; + + /* clean the previous response state */ + ari_clobber_response(ari_base); + + ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_IS_CCX_ALLOWED, + state & 0x7U, wake_time); + if (ret != 0) { + ERROR("%s: failed (%d)\n", __func__, ret); + result = 0U; + } else { + result = ari_get_response_low(ari_base) & 0x1U; + } + + /* 1 = CCx allowed, 0 = CCx not allowed */ + return (int32_t)result; +} + +int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + int32_t ret, result; + + /* check for allowed power state */ + if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) && + (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) { + ERROR("%s: unknown cstate (%d)\n", __func__, state); + result = EINVAL; + } else { + /* clean the previous response state */ + ari_clobber_response(ari_base); + + ret = ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_IS_SC7_ALLOWED, state, wake_time); + if (ret != 0) { + ERROR("%s: failed (%d)\n", __func__, ret); + result = 0; + } else { + /* 1 = SC7 allowed, 0 = SC7 not allowed */ + result = (ari_get_response_low(ari_base) != 0U) ? 1 : 0; + } + } + + return result; +} + +int32_t ari_online_core(uint32_t ari_base, uint32_t core) +{ + uint64_t cpu = read_mpidr() & (MPIDR_CPU_MASK); + uint64_t cluster = (read_mpidr() & (MPIDR_CLUSTER_MASK)) >> + (MPIDR_AFFINITY_BITS); + uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + int32_t ret; + + /* construct the current CPU # */ + cpu |= (cluster << 2); + + /* sanity check target core id */ + if ((core >= MCE_CORE_ID_MAX) || (cpu == (uint64_t)core)) { + ERROR("%s: unsupported core id (%d)\n", __func__, core); + ret = EINVAL; + } else { + /* + * The Denver cluster has 2 CPUs only - 0, 1. + */ + if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) { + ERROR("%s: unknown core id (%d)\n", __func__, core); + ret = EINVAL; + } else { + /* clean the previous response state */ + ari_clobber_response(ari_base); + ret = ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_ONLINE_CORE, core, 0U); + } + } + + return ret; +} + +int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable) +{ + uint32_t val; + + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* + * If the enable bit is cleared, Auto-CC3 will be disabled by setting + * the SW visible voltage/frequency request registers for all non + * floorswept cores valid independent of StandbyWFI and disabling + * the IDLE voltage/frequency request register. If set, Auto-CC3 + * will be enabled by setting the ARM SW visible voltage/frequency + * request registers for all non floorswept cores to be enabled by + * StandbyWFI or the equivalent signal, and always keeping the IDLE + * voltage/frequency request register enabled. + */ + val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\ + ((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\ + ((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U)); + + return ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_CC3_CTRL, val, 0U); +} + +int32_t ari_reset_vector_update(uint32_t ari_base) +{ + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* + * Need to program the CPU reset vector one time during cold boot + * and SC7 exit + */ + (void)ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_COPY_MISCREG_AA64_RST, 0U, 0U); + + return 0; +} + +int32_t ari_roc_flush_cache_trbits(uint32_t ari_base) +{ + /* clean the previous response state */ + ari_clobber_response(ari_base); + + return ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS, 0U, 0U); +} + +int32_t ari_roc_flush_cache(uint32_t ari_base) +{ + /* clean the previous response state */ + ari_clobber_response(ari_base); + + return ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_ONLY, 0U, 0U); +} + +int32_t ari_roc_clean_cache(uint32_t ari_base) +{ + /* clean the previous response state */ + ari_clobber_response(ari_base); + + return ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_ROC_CLEAN_CACHE_ONLY, 0U, 0U); +} + +uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data) +{ + uint64_t mca_arg_data, result = 0; + uint32_t resp_lo, resp_hi; + uint32_t mca_arg_err, mca_arg_finish; + int32_t ret; + + /* Set data (write) */ + mca_arg_data = (data != NULL) ? *data : 0ULL; + + /* Set command */ + ari_write_32(ari_base, (uint32_t)cmd, ARI_RESPONSE_DATA_LO); + ari_write_32(ari_base, (uint32_t)(cmd >> 32U), ARI_RESPONSE_DATA_HI); + + ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MCA, + (uint32_t)mca_arg_data, + (uint32_t)(mca_arg_data >> 32U)); + if (ret == 0) { + resp_lo = ari_get_response_low(ari_base); + resp_hi = ari_get_response_high(ari_base); + + mca_arg_err = resp_lo & MCA_ARG_ERROR_MASK; + mca_arg_finish = (resp_hi >> MCA_ARG_FINISH_SHIFT) & + MCA_ARG_FINISH_MASK; + + if (mca_arg_finish == 0U) { + result = (uint64_t)mca_arg_err; + } else { + if (data != NULL) { + resp_lo = ari_get_request_low(ari_base); + resp_hi = ari_get_request_high(ari_base); + *data = ((uint64_t)resp_hi << 32U) | + (uint64_t)resp_lo; + } + } + } + + return result; +} + +int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx) +{ + int32_t ret = 0; + /* sanity check GSC ID */ + if (gsc_idx > TEGRA_ARI_GSC_VPR_IDX) { + ret = EINVAL; + } else { + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* + * The MCE code will read the GSC carveout value, corrseponding to + * the ID, from the MC registers and update the internal GSC registers + * of the CCPLEX. + */ + (void)ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_UPDATE_CCPLEX_GSC, gsc_idx, 0U); + } + + return ret; +} + +void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx) +{ + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* + * The MCE will shutdown or restart the entire system + */ + (void)ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_MISC_CCPLEX, state_idx, 0U); +} + +int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req, + uint64_t *data) +{ + int32_t ret, result; + uint32_t val, req_status; + uint8_t req_cmd; + + req_cmd = (uint8_t)(req & UNCORE_PERFMON_CMD_MASK); + + /* clean the previous response state */ + ari_clobber_response(ari_base); + + /* sanity check input parameters */ + if ((req_cmd == UNCORE_PERFMON_CMD_READ) && (data == NULL)) { + ERROR("invalid parameters\n"); + result = EINVAL; + } else { + /* + * For "write" commands get the value that has to be written + * to the uncore perfmon registers + */ + val = (req_cmd == UNCORE_PERFMON_CMD_WRITE) ? + (uint32_t)*data : 0U; + + ret = ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_PERFMON, val, (uint32_t)req); + if (ret != 0) { + result = ret; + } else { + /* read the command status value */ + req_status = ari_get_response_high(ari_base) & + UNCORE_PERFMON_RESP_STATUS_MASK; + + /* + * For "read" commands get the data from the uncore + * perfmon registers + */ + req_status &= UNCORE_PERFMON_RESP_STATUS_MASK; + if ((req_status == 0U) && (req_cmd == UNCORE_PERFMON_CMD_READ)) { + *data = ari_get_response_low(ari_base); + } + result = (int32_t)req_status; + } + } + + return result; +} + +void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value) +{ + /* + * This invokes the ARI_MISC_CCPLEX commands. This can be + * used to enable/disable coresight clock gating. + */ + + if ((index > TEGRA_ARI_MISC_CCPLEX_EDBGREQ) || + ((index == TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL) && + (value > 1U))) { + ERROR("%s: invalid parameters \n", __func__); + } else { + /* clean the previous response state */ + ari_clobber_response(ari_base); + (void)ari_request_wait(ari_base, 0U, + (uint32_t)TEGRA_ARI_MISC_CCPLEX, index, value); + } +} diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c new file mode 100644 index 0000000..aebaceb --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <inttypes.h> +#include <stdint.h> +#include <string.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <context.h> +#include <denver.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/mmio.h> + +#include <mce.h> +#include <mce_private.h> +#include <t18x_ari.h> +#include <tegra_def.h> +#include <tegra_platform.h> + +/* NVG functions handlers */ +static arch_mce_ops_t nvg_mce_ops = { + .enter_cstate = nvg_enter_cstate, + .update_cstate_info = nvg_update_cstate_info, + .update_crossover_time = nvg_update_crossover_time, + .read_cstate_stats = nvg_read_cstate_stats, + .write_cstate_stats = nvg_write_cstate_stats, + .call_enum_misc = ari_enumeration_misc, + .is_ccx_allowed = nvg_is_ccx_allowed, + .is_sc7_allowed = nvg_is_sc7_allowed, + .online_core = nvg_online_core, + .cc3_ctrl = nvg_cc3_ctrl, + .update_reset_vector = ari_reset_vector_update, + .roc_flush_cache = ari_roc_flush_cache, + .roc_flush_cache_trbits = ari_roc_flush_cache_trbits, + .roc_clean_cache = ari_roc_clean_cache, + .read_write_mca = ari_read_write_mca, + .update_ccplex_gsc = ari_update_ccplex_gsc, + .enter_ccplex_state = ari_enter_ccplex_state, + .read_write_uncore_perfmon = ari_read_write_uncore_perfmon, + .misc_ccplex = ari_misc_ccplex +}; + +/* ARI functions handlers */ +static arch_mce_ops_t ari_mce_ops = { + .enter_cstate = ari_enter_cstate, + .update_cstate_info = ari_update_cstate_info, + .update_crossover_time = ari_update_crossover_time, + .read_cstate_stats = ari_read_cstate_stats, + .write_cstate_stats = ari_write_cstate_stats, + .call_enum_misc = ari_enumeration_misc, + .is_ccx_allowed = ari_is_ccx_allowed, + .is_sc7_allowed = ari_is_sc7_allowed, + .online_core = ari_online_core, + .cc3_ctrl = ari_cc3_ctrl, + .update_reset_vector = ari_reset_vector_update, + .roc_flush_cache = ari_roc_flush_cache, + .roc_flush_cache_trbits = ari_roc_flush_cache_trbits, + .roc_clean_cache = ari_roc_clean_cache, + .read_write_mca = ari_read_write_mca, + .update_ccplex_gsc = ari_update_ccplex_gsc, + .enter_ccplex_state = ari_enter_ccplex_state, + .read_write_uncore_perfmon = ari_read_write_uncore_perfmon, + .misc_ccplex = ari_misc_ccplex +}; + +typedef struct { + uint32_t ari_base; + arch_mce_ops_t *ops; +} mce_config_t; + +/* Table to hold the per-CPU ARI base address and function handlers */ +static mce_config_t mce_cfg_table[MCE_ARI_APERTURES_MAX] = { + { + /* A57 Core 0 */ + .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_0_OFFSET, + .ops = &ari_mce_ops, + }, + { + /* A57 Core 1 */ + .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_1_OFFSET, + .ops = &ari_mce_ops, + }, + { + /* A57 Core 2 */ + .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_2_OFFSET, + .ops = &ari_mce_ops, + }, + { + /* A57 Core 3 */ + .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_3_OFFSET, + .ops = &ari_mce_ops, + }, + { + /* D15 Core 0 */ + .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_4_OFFSET, + .ops = &nvg_mce_ops, + }, + { + /* D15 Core 1 */ + .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_5_OFFSET, + .ops = &nvg_mce_ops, + } +}; + +static uint32_t mce_get_curr_cpu_ari_base(void) +{ + uint64_t mpidr = read_mpidr(); + uint64_t cpuid = mpidr & MPIDR_CPU_MASK; + uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + + /* + * T186 has 2 CPU clusters, one with Denver CPUs and the other with + * ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU + * numbers start from 0. In order to get the proper arch_mce_ops_t + * struct, we have to convert the Denver CPU ids to the corresponding + * indices in the mce_ops_table array. + */ + if (impl == DENVER_IMPL) { + cpuid |= 0x4U; + } + + return mce_cfg_table[cpuid].ari_base; +} + +static arch_mce_ops_t *mce_get_curr_cpu_ops(void) +{ + uint64_t mpidr = read_mpidr(); + uint64_t cpuid = mpidr & MPIDR_CPU_MASK; + uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & + MIDR_IMPL_MASK; + + /* + * T186 has 2 CPU clusters, one with Denver CPUs and the other with + * ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU + * numbers start from 0. In order to get the proper arch_mce_ops_t + * struct, we have to convert the Denver CPU ids to the corresponding + * indices in the mce_ops_table array. + */ + if (impl == DENVER_IMPL) { + cpuid |= 0x4U; + } + + return mce_cfg_table[cpuid].ops; +} + +/******************************************************************************* + * Common handler for all MCE commands + ******************************************************************************/ +int32_t mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1, + uint64_t arg2) +{ + const arch_mce_ops_t *ops; + gp_regs_t *gp_regs = get_gpregs_ctx(cm_get_context(NON_SECURE)); + uint32_t cpu_ari_base; + uint64_t ret64 = 0, arg3, arg4, arg5; + int32_t ret = 0; + + assert(gp_regs != NULL); + + /* get a pointer to the CPU's arch_mce_ops_t struct */ + ops = mce_get_curr_cpu_ops(); + + /* get the CPU's ARI base address */ + cpu_ari_base = mce_get_curr_cpu_ari_base(); + + switch (cmd) { + case (uint64_t)MCE_CMD_ENTER_CSTATE: + ret = ops->enter_cstate(cpu_ari_base, arg0, arg1); + + break; + + case (uint64_t)MCE_CMD_UPDATE_CSTATE_INFO: + /* + * get the parameters required for the update cstate info + * command + */ + arg3 = read_ctx_reg(gp_regs, CTX_GPREG_X4); + arg4 = read_ctx_reg(gp_regs, CTX_GPREG_X5); + arg5 = read_ctx_reg(gp_regs, CTX_GPREG_X6); + + ret = ops->update_cstate_info(cpu_ari_base, (uint32_t)arg0, + (uint32_t)arg1, (uint32_t)arg2, (uint8_t)arg3, + (uint32_t)arg4, (uint8_t)arg5); + + write_ctx_reg(gp_regs, CTX_GPREG_X4, (0ULL)); + write_ctx_reg(gp_regs, CTX_GPREG_X5, (0ULL)); + write_ctx_reg(gp_regs, CTX_GPREG_X6, (0ULL)); + + break; + + case (uint64_t)MCE_CMD_UPDATE_CROSSOVER_TIME: + ret = ops->update_crossover_time(cpu_ari_base, arg0, arg1); + + break; + + case (uint64_t)MCE_CMD_READ_CSTATE_STATS: + ret64 = ops->read_cstate_stats(cpu_ari_base, arg0); + + /* update context to return cstate stats value */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); + write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64)); + + break; + + case (uint64_t)MCE_CMD_WRITE_CSTATE_STATS: + ret = ops->write_cstate_stats(cpu_ari_base, arg0, arg1); + + break; + + case (uint64_t)MCE_CMD_IS_CCX_ALLOWED: + ret = ops->is_ccx_allowed(cpu_ari_base, arg0, arg1); + + /* update context to return CCx status value */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret)); + + break; + + case (uint64_t)MCE_CMD_IS_SC7_ALLOWED: + ret = ops->is_sc7_allowed(cpu_ari_base, arg0, arg1); + + /* update context to return SC7 status value */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret)); + write_ctx_reg(gp_regs, CTX_GPREG_X3, (uint64_t)(ret)); + + break; + + case (uint64_t)MCE_CMD_ONLINE_CORE: + ret = ops->online_core(cpu_ari_base, arg0); + + break; + + case (uint64_t)MCE_CMD_CC3_CTRL: + ret = ops->cc3_ctrl(cpu_ari_base, arg0, arg1, arg2); + + break; + + case (uint64_t)MCE_CMD_ECHO_DATA: + ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_ECHO, + arg0); + + /* update context to return if echo'd data matched source */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, ((ret64 == arg0) ? + 1ULL : 0ULL)); + write_ctx_reg(gp_regs, CTX_GPREG_X2, ((ret64 == arg0) ? + 1ULL : 0ULL)); + + break; + + case (uint64_t)MCE_CMD_READ_VERSIONS: + ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION, + arg0); + + /* + * version = minor(63:32) | major(31:0). Update context + * to return major and minor version number. + */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); + write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64 >> 32ULL)); + + break; + + case (uint64_t)MCE_CMD_ENUM_FEATURES: + ret64 = ops->call_enum_misc(cpu_ari_base, + TEGRA_ARI_MISC_FEATURE_LEAF_0, arg0); + + /* update context to return features value */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); + + break; + + case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE_TRBITS: + ret = ops->roc_flush_cache_trbits(cpu_ari_base); + + break; + + case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE: + ret = ops->roc_flush_cache(cpu_ari_base); + + break; + + case (uint64_t)MCE_CMD_ROC_CLEAN_CACHE: + ret = ops->roc_clean_cache(cpu_ari_base); + + break; + + case (uint64_t)MCE_CMD_ENUM_READ_MCA: + ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1); + + /* update context to return MCA data/error */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); + write_ctx_reg(gp_regs, CTX_GPREG_X2, (arg1)); + write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64)); + + break; + + case (uint64_t)MCE_CMD_ENUM_WRITE_MCA: + ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1); + + /* update context to return MCA error */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); + write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64)); + + break; + +#if ENABLE_CHIP_VERIFICATION_HARNESS + case (uint64_t)MCE_CMD_ENABLE_LATIC: + /* + * This call is not for production use. The constant value, + * 0xFFFF0000, is specific to allowing for enabling LATIC on + * pre-production parts for the chip verification harness. + * + * Enabling LATIC allows S/W to read the MINI ISPs in the + * CCPLEX. The ISMs are used for various measurements relevant + * to particular locations in the Silicon. They are small + * counters which can be polled to determine how fast a + * particular location in the Silicon is. + */ + ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(), + 0xFFFF0000); + + break; +#endif + + case (uint64_t)MCE_CMD_UNCORE_PERFMON_REQ: + ret = ops->read_write_uncore_perfmon(cpu_ari_base, arg0, &arg1); + + /* update context to return data */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, (arg1)); + break; + + case (uint64_t)MCE_CMD_MISC_CCPLEX: + ops->misc_ccplex(cpu_ari_base, arg0, arg1); + + break; + + default: + ERROR("unknown MCE command (%" PRIu64 ")\n", cmd); + ret = EINVAL; + break; + } + + return ret; +} + +/******************************************************************************* + * Handler to update the reset vector for CPUs + ******************************************************************************/ +int32_t mce_update_reset_vector(void) +{ + const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); + + ops->update_reset_vector(mce_get_curr_cpu_ari_base()); + + return 0; +} + +static int32_t mce_update_ccplex_gsc(tegra_ari_gsc_index_t gsc_idx) +{ + const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); + + ops->update_ccplex_gsc(mce_get_curr_cpu_ari_base(), gsc_idx); + + return 0; +} + +/******************************************************************************* + * Handler to update carveout values for Video Memory Carveout region + ******************************************************************************/ +int32_t mce_update_gsc_videomem(void) +{ + return mce_update_ccplex_gsc(TEGRA_ARI_GSC_VPR_IDX); +} + +/******************************************************************************* + * Handler to update carveout values for TZDRAM aperture + ******************************************************************************/ +int32_t mce_update_gsc_tzdram(void) +{ + return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZ_DRAM_IDX); +} + +/******************************************************************************* + * Handler to shutdown/reset the entire system + ******************************************************************************/ +__dead2 void mce_enter_ccplex_state(uint32_t state_idx) +{ + const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); + + /* sanity check state value */ + if ((state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) && + (state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT)) { + panic(); + } + + ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(), state_idx); + + /* wait till the CCPLEX powers down */ + for (;;) { + ; + } + +} + +/******************************************************************************* + * Handler to issue the UPDATE_CSTATE_INFO request + ******************************************************************************/ +void mce_update_cstate_info(const mce_cstate_info_t *cstate) +{ + const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); + + /* issue the UPDATE_CSTATE_INFO request */ + ops->update_cstate_info(mce_get_curr_cpu_ari_base(), cstate->cluster, + cstate->ccplex, cstate->system, cstate->system_state_force, + 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) +{ + const arch_mce_ops_t *ops; + uint32_t cpu_ari_base; + uint64_t version; + uint32_t major, minor; + + /* + * MCE firmware is not supported on simulation platforms. + */ + if (tegra_platform_is_emulation()) { + + INFO("MCE firmware is not supported\n"); + + } else { + /* get a pointer to the CPU's arch_mce_ops_t struct */ + ops = mce_get_curr_cpu_ops(); + + /* get the CPU's ARI base address */ + cpu_ari_base = mce_get_curr_cpu_ari_base(); + + /* + * Read the MCE firmware version and extract the major and minor + * version fields + */ + version = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION, 0); + major = (uint32_t)version; + minor = (uint32_t)(version >> 32); + + INFO("MCE Version - HW=%d:%d, SW=%d:%d\n", major, minor, + TEGRA_ARI_VERSION_MAJOR, TEGRA_ARI_VERSION_MINOR); + + /* + * Verify that the MCE firmware version and the interface header + * match + */ + if (major != TEGRA_ARI_VERSION_MAJOR) { + ERROR("ARI major version mismatch\n"); + panic(); + } + + if (minor < TEGRA_ARI_VERSION_MINOR) { + ERROR("ARI minor version mismatch\n"); + panic(); + } + } +} diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c b/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c new file mode 100644 index 0000000..cbc9aa3 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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 <t18x_ari.h> +#include <tegra_private.h> + +int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + int32_t ret = 0; + uint64_t val = 0ULL; + + (void)ari_base; + + /* check for allowed power state */ + if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) && + (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) { + ERROR("%s: unknown cstate (%d)\n", __func__, state); + ret = EINVAL; + } else { + /* time (TSC ticks) until the core is expected to get a wake event */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_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; +} + +/* + * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and + * SYSTEM_CSTATE values. + */ +int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, + uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, + uint8_t update_wake_mask) +{ + uint64_t val = 0ULL; + + (void)ari_base; + + /* 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) | + (((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_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 &= CSTATE_WAKE_MASK_CLEAR; + val |= ((uint64_t)wake_mask << CSTATE_WAKE_MASK_SHIFT); + + /* set the updated cstate info */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val); + + return 0; +} + +int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time) +{ + int32_t ret = 0; + + (void)ari_base; + + /* sanity check crossover type */ + if (type > TEGRA_ARI_CROSSOVER_CCP3_SC1) { + ret = EINVAL; + } else { + /* + * The crossover threshold limit types start from + * TEGRA_CROSSOVER_TYPE_C1_C6 to TEGRA_CROSSOVER_TYPE_CCP3_SC7. + * The command indices for updating the threshold be generated + * by adding the type to the NVG_SET_THRESHOLD_CROSSOVER_C1_C6 + * command index. + */ + nvg_set_request_data((TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 + + (uint64_t)type), (uint64_t)time); + } + + return ret; +} + +uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state) +{ + uint64_t ret; + + (void)ari_base; + + /* sanity check state */ + if (state == 0U) { + ret = EINVAL; + } else { + /* + * The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES + * to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for + * reading the threshold can be generated by adding the type to + * the NVG_CLEAR_CSTATE_STATS command index. + */ + nvg_set_request((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR + + (uint64_t)state)); + ret = nvg_get_result(); + } + + return ret; +} + +int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats) +{ + uint64_t val; + + (void)ari_base; + + /* + * The only difference between a CSTATE_STATS_WRITE and + * CSTATE_STATS_READ is the usage of the 63:32 in the request. + * 63:32 are set to '0' for a read, while a write contains the + * actual stats value to be written. + */ + val = ((uint64_t)stats << MCE_CSTATE_STATS_TYPE_SHIFT) | state; + + /* + * The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES + * to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for + * reading the threshold can be generated by adding the type to + * the NVG_CLEAR_CSTATE_STATS command index. + */ + nvg_set_request_data((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR + + (uint64_t)state), val); + + return 0; +} + +int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + (void)ari_base; + (void)state; + (void)wake_time; + + /* This does not apply to the Denver cluster */ + return 0; +} + +int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + uint64_t val; + int32_t ret; + + (void)ari_base; + + /* check for allowed power state */ + if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) && + (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) { + ERROR("%s: unknown cstate (%d)\n", __func__, state); + ret = EINVAL; + } else { + /* + * Request format - + * 63:32 = wake time + * 31:0 = C-state for this core + */ + val = ((uint64_t)wake_time << MCE_SC7_WAKE_TIME_SHIFT) | + ((uint64_t)state & MCE_SC7_ALLOWED_MASK); + + /* issue command to check if SC7 is allowed */ + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED, val); + + /* 1 = SC7 allowed, 0 = SC7 not allowed */ + ret = (nvg_get_result() != 0ULL) ? 1 : 0; + } + + return ret; +} + +int32_t nvg_online_core(uint32_t ari_base, uint32_t core) +{ + uint64_t cpu = read_mpidr() & MPIDR_CPU_MASK; + uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + int32_t ret = 0; + + (void)ari_base; + + /* sanity check code id */ + if ((core >= MCE_CORE_ID_MAX) || (cpu == core)) { + ERROR("%s: unsupported core id (%d)\n", __func__, core); + ret = EINVAL; + } else { + /* + * The Denver cluster has 2 CPUs only - 0, 1. + */ + if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) { + 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; +} + +int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable) +{ + uint32_t val; + + (void)ari_base; + + /* + * If the enable bit is cleared, Auto-CC3 will be disabled by setting + * the SW visible voltage/frequency request registers for all non + * floorswept cores valid independent of StandbyWFI and disabling + * the IDLE voltage/frequency request register. If set, Auto-CC3 + * will be enabled by setting the ARM SW visible voltage/frequency + * request registers for all non floorswept cores to be enabled by + * StandbyWFI or the equivalent signal, and always keeping the IDLE + * voltage/frequency request register enabled. + */ + val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\ + ((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\ + ((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U)); + + nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CC3_CTRL, (uint64_t)val); + + return 0; +} diff --git a/plat/nvidia/tegra/soc/t186/drivers/se/se.c b/plat/nvidia/tegra/soc/t186/drivers/se/se.c new file mode 100644 index 0000000..25f8cd0 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/se/se.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <drivers/delay_timer.h> +#include <errno.h> +#include <string.h> + +#include <bpmp_ipc.h> +#include <pmc.h> +#include <security_engine.h> +#include <tegra_private.h> + +#include "se_private.h" + +/******************************************************************************* + * Constants and Macros + ******************************************************************************/ +#define SE0_MAX_BUSY_TIMEOUT_MS U(100) /* 100ms */ +#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) + +/* + * 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_operation_complete(void) +{ + uint32_t val = 0U; + + /* Read SE0 interrupt register to ensure H/W operation complete */ + val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET); + if (SE0_INT_OP_DONE(val) == SE0_INT_OP_DONE_CLEAR) { + ERROR("%s: Engine busy state too many times! val = 0x%x\n", + __func__, val); + return -ETIMEDOUT; + } + + /* Read SE0 status idle to ensure H/W operation complete */ + val = tegra_se_read_32(SE0_SHA_STATUS_0); + if (val != SE0_SHA_STATUS_IDLE) { + ERROR("%s: Idle state timeout! val = 0x%x\n", __func__, + val); + return -ETIMEDOUT; + } + + /* Ensure that no errors are thrown during operation */ + val = tegra_se_read_32(SE0_ERR_STATUS_REG_OFFSET); + if (val != SE0_ERR_STATUS_CLEAR) { + ERROR("%s: Error during SE operation! val = 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) +{ + int32_t ret = 0; + uint32_t val = 0U; + uint32_t src_in_lo; + uint32_t src_in_msb; + uint32_t src_in_hi; + + if ((src_addr == 0UL) || (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 & 0xffffffU)); + + /* 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, 0x00000U); + } + + /* 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); + } + + /* Wait for SE-operation to finish */ + udelay(SE0_MAX_BUSY_TIMEOUT_MS * 100U); + + /* Check SE0 operation status */ + ret = tegra_se_operation_complete(); + if (ret != 0) { + ERROR("SE operation complete Failed! 0x%x", ret); + return ret; + } + + return 0; +} + +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 == 0UL) { + return -EINVAL; + } + + /* number of bytes per operation */ + max_bytes = SHA256_HASH_SIZE_BYTES * SHA256_MSG_LENGTH_ONETIME; + + src_len_inbits = src_len_inbyte * 8U; + len_bits_msb = (uint32_t)(src_len_inbits >> 32U); + len_bits_lsb = (uint32_t)(src_len_inbits & 0xFFFFFFFF); + + /* program SE0_CONFIG for SHA256 operation */ + val = 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; +} + +/* + * Handler to generate SHA256 and save SHA256 hash to PMC-Scratch register. + */ +int32_t tegra_se_save_sha256_hash(uint64_t bl31_base, uint32_t src_len_inbyte) +{ + int32_t ret = 0; + uint32_t val = 0U, hash_offset = 0U, scratch_offset = 0U, security; + + /* + * 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); + + ret = tegra_se_calculate_sha256_hash(bl31_base, src_len_inbyte); + if (ret != 0L) { + ERROR("%s: SHA256 generation failed\n", __func__); + return ret; + } + + /* + * Reset SE_SECURE to previous value. + */ + tegra_se_write_32(SE0_SECURITY, security); + + /* read SHA256_HASH_RESULT and save to PMC Scratch registers */ + scratch_offset = SECURE_SCRATCH_TZDRAM_SHA256_HASH_START; + while (scratch_offset <= SECURE_SCRATCH_TZDRAM_SHA256_HASH_END) { + + val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + hash_offset); + mmio_write_32(TEGRA_SCRATCH_BASE + scratch_offset, val); + + hash_offset += BYTES_IN_WORD; + scratch_offset += BYTES_IN_WORD; + } + + return ret; +} + diff --git a/plat/nvidia/tegra/soc/t186/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t186/drivers/se/se_private.h new file mode 100644 index 0000000..7aa0dd6 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/se/se_private.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 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> + +/* SE0 security register */ +#define SE0_SECURITY U(0x18) +#define SE0_SECURITY_SE_SOFT_SETTING (((uint32_t)1) << 16U) + +/* SE0 config register */ +#define SE0_SHA_CONFIG U(0x104) +#define SE0_SHA_TASK_CONFIG U(0x108) +#define SE0_SHA_CONFIG_HW_INIT_HASH ((1U) << 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_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)0) << SE0_INT_OP_DONE_SHIFT) +#define SE0_INT_OP_DONE(x) \ + ((x) & (((uint32_t)0x1) << 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) +#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) + +/* SE error status */ +#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_START SECURE_SCRATCH_RSV63_LO +#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_END SECURE_SCRATCH_RSV66_HI + +/******************************************************************************* + * Inline functions definition + ******************************************************************************/ + +static inline uint32_t tegra_se_read_32(uint32_t offset) +{ + return mmio_read_32((uint32_t)(TEGRA_SE0_BASE + offset)); +} + +static inline void tegra_se_write_32(uint32_t offset, uint32_t val) +{ + mmio_write_32(((uint32_t)(TEGRA_SE0_BASE + offset)), val); +} + +#endif /* SE_PRIVATE_H */ diff --git a/plat/nvidia/tegra/soc/t186/plat_memctrl.c b/plat/nvidia/tegra/soc/t186/plat_memctrl.c new file mode 100644 index 0000000..81de674 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/plat_memctrl.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 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 <tegra186_private.h> +#include <tegra_mc_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +extern uint64_t tegra_bl31_phys_base; + +/******************************************************************************* + * Array to hold stream_id override config register offsets + ******************************************************************************/ +const static uint32_t tegra186_streamid_override_regs[] = { + MC_STREAMID_OVERRIDE_CFG_SDMMCRA, + MC_STREAMID_OVERRIDE_CFG_SDMMCRAA, + MC_STREAMID_OVERRIDE_CFG_SDMMCR, + MC_STREAMID_OVERRIDE_CFG_SDMMCRAB, + MC_STREAMID_OVERRIDE_CFG_SDMMCWA, + MC_STREAMID_OVERRIDE_CFG_SDMMCWAA, + MC_STREAMID_OVERRIDE_CFG_SDMMCW, + MC_STREAMID_OVERRIDE_CFG_SDMMCWAB, +}; + +/******************************************************************************* + * Array to hold the security configs for stream IDs + ******************************************************************************/ +const static mc_streamid_security_cfg_t tegra186_streamid_sec_cfgs[] = { + mc_make_sec_cfg(SCEW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(AFIR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(AFIW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(NVDISPLAYR1, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(XUSB_DEVR, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(VICSRD1, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(NVENCSWR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(TSECSRDB, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(AXISW, SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCWAB, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(AONDMAW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(GPUSWR2, SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SATAW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(UFSHCW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(SCEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(UFSHCR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCWAA, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(SESWR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(MPCORER, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(PTCR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(BPMPW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(ETRW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(GPUSRD, SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(VICSWR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SCEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(HDAW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(ISPWA, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(EQOSW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(XUSB_HOSTW, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(TSECSWR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCRAA, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(VIW, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(AXISR, SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(BPMPDMAW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(ISPRA, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(NVDECSWR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(XUSB_DEVW, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(NVDECSRD, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(MPCOREW, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(NVDISPLAYR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(BPMPDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(NVJPGSWR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(NVDECSRD1, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(TSECSRD, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(NVJPGSRD, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCWA, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(SCER, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(XUSB_HOSTR, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(VICSRD, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(AONDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(AONW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCRA, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(HOST1XDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(EQOSR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(SATAR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(BPMPR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(HDAR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(SDMMCRAB, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(ETRR, NON_SECURE, OVERRIDE, DISABLE), + mc_make_sec_cfg(AONR, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(SESRD, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(NVENCSRD, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(GPUSWR, SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(TSECSWRB, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(ISPWB, NON_SECURE, OVERRIDE, ENABLE), + mc_make_sec_cfg(GPUSRD2, SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(APEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(APER, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(APEW, NON_SECURE, NO_OVERRIDE, DISABLE), + mc_make_sec_cfg(APEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), +}; + +/******************************************************************************* + * Array to hold the transaction override configs + ******************************************************************************/ +const static mc_txn_override_cfg_t tegra186_txn_override_cfgs[] = { + mc_make_txn_override_cfg(BPMPW, CGID_TAG_ADR), + mc_make_txn_override_cfg(EQOSW, CGID_TAG_ADR), + mc_make_txn_override_cfg(NVJPGSWR, CGID_TAG_ADR), + mc_make_txn_override_cfg(SDMMCWAA, CGID_TAG_ADR), + mc_make_txn_override_cfg(MPCOREW, CGID_TAG_ADR), + mc_make_txn_override_cfg(SCEDMAW, CGID_TAG_ADR), + mc_make_txn_override_cfg(SDMMCW, CGID_TAG_ADR), + mc_make_txn_override_cfg(AXISW, CGID_TAG_ADR), + mc_make_txn_override_cfg(TSECSWR, CGID_TAG_ADR), + mc_make_txn_override_cfg(GPUSWR, CGID_TAG_ADR), + mc_make_txn_override_cfg(XUSB_HOSTW, CGID_TAG_ADR), + mc_make_txn_override_cfg(TSECSWRB, CGID_TAG_ADR), + mc_make_txn_override_cfg(GPUSWR2, CGID_TAG_ADR), + mc_make_txn_override_cfg(AONDMAW, CGID_TAG_ADR), + mc_make_txn_override_cfg(AONW, CGID_TAG_ADR), + mc_make_txn_override_cfg(SESWR, CGID_TAG_ADR), + mc_make_txn_override_cfg(BPMPDMAW, CGID_TAG_ADR), + mc_make_txn_override_cfg(SDMMCWA, CGID_TAG_ADR), + mc_make_txn_override_cfg(HDAW, CGID_TAG_ADR), + mc_make_txn_override_cfg(NVDECSWR, CGID_TAG_ADR), + mc_make_txn_override_cfg(UFSHCW, CGID_TAG_ADR), + mc_make_txn_override_cfg(SATAW, CGID_TAG_ADR), + mc_make_txn_override_cfg(ETRW, CGID_TAG_ADR), + mc_make_txn_override_cfg(VICSWR, CGID_TAG_ADR), + mc_make_txn_override_cfg(NVENCSWR, CGID_TAG_ADR), + mc_make_txn_override_cfg(SDMMCWAB, CGID_TAG_ADR), + mc_make_txn_override_cfg(ISPWB, CGID_TAG_ADR), + mc_make_txn_override_cfg(APEW, CGID_TAG_ADR), + mc_make_txn_override_cfg(XUSB_DEVW, CGID_TAG_ADR), + mc_make_txn_override_cfg(AFIW, CGID_TAG_ADR), + mc_make_txn_override_cfg(SCEW, CGID_TAG_ADR), +}; + +static void tegra186_memctrl_reconfig_mss_clients(void) +{ +#if ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS + uint32_t val, wdata_0, wdata_1; + + /* + * Assert Memory Controller's HOTRESET_FLUSH_ENABLE signal for + * boot and strongly ordered MSS clients to flush existing memory + * traffic and stall future requests. + */ + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0); + assert(val == MC_CLIENT_HOTRESET_CTRL0_RESET_VAL); + + wdata_0 = MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB; + tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0); + + /* Wait for HOTRESET STATUS to indicate FLUSH_DONE */ + do { + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0); + } while ((val & wdata_0) != wdata_0); + + /* Wait one more time due to SW WAR for known legacy issue */ + do { + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0); + } while ((val & wdata_0) != wdata_0); + + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1); + assert(val == MC_CLIENT_HOTRESET_CTRL1_RESET_VAL); + + wdata_1 = MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB | + MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB; + tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1); + + /* Wait for HOTRESET STATUS to indicate FLUSH_DONE */ + do { + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1); + } while ((val & wdata_1) != wdata_1); + + /* Wait one more time due to SW WAR for known legacy issue */ + do { + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1); + } while ((val & wdata_1) != wdata_1); + + /* + * Change MEMTYPE_OVERRIDE from SO_DEV -> PASSTHRU for boot and + * strongly ordered MSS clients. ROC needs to be single point + * of control on overriding the memory type. So, remove TSA's + * memtype override. + * + * MC clients with default SO_DEV override still enabled at TSA: + * AONW, BPMPW, SCEW, APEW + */ + mc_set_tsa_passthrough(AFIW); + mc_set_tsa_passthrough(HDAW); + mc_set_tsa_passthrough(SATAW); + mc_set_tsa_passthrough(XUSB_HOSTW); + mc_set_tsa_passthrough(XUSB_DEVW); + mc_set_tsa_passthrough(SDMMCWAB); + mc_set_tsa_passthrough(APEDMAW); + mc_set_tsa_passthrough(SESWR); + mc_set_tsa_passthrough(ETRW); + mc_set_tsa_passthrough(AXISW); + mc_set_tsa_passthrough(EQOSW); + mc_set_tsa_passthrough(UFSHCW); + mc_set_tsa_passthrough(BPMPDMAW); + mc_set_tsa_passthrough(AONDMAW); + mc_set_tsa_passthrough(SCEDMAW); + + /* Parker has no IO Coherency support and need the following: + * Ordered MC Clients on Parker are AFI, EQOS, SATA, XUSB. + * ISO clients(DISP, VI, EQOS) should never snoop caches and + * don't need ROC/PCFIFO ordering. + * ISO clients(EQOS) that need ordering should use PCFIFO ordering + * and bypass ROC ordering by using FORCE_NON_COHERENT path. + * FORCE_NON_COHERENT/FORCE_COHERENT config take precedence + * over SMMU attributes. + * Force all Normal memory transactions from ISO and non-ISO to be + * non-coherent(bypass ROC, avoid cache snoop to avoid perf hit). + * Force the SO_DEV transactions from ordered ISO clients(EQOS) to + * non-coherent path and enable MC PCFIFO interlock for ordering. + * Force the SO_DEV transactions from ordered non-ISO clients (PCIe, + * XUSB, SATA) to coherent so that the transactions are + * ordered by ROC. + * PCFIFO ensure write ordering. + * Read after Write ordering is maintained/enforced by MC clients. + * Clients that need PCIe type write ordering must + * go through ROC ordering. + * Ordering enable for Read clients is not necessary. + * R5's and A9 would get necessary ordering from AXI and + * don't need ROC ordering enable: + * - MMIO ordering is through dev mapping and MMIO + * accesses bypass SMMU. + * - Normal memory is accessed through SMMU and ordering is + * ensured by client and AXI. + * - Ack point for Normal memory is WCAM in MC. + * - MMIO's can be early acked and AXI ensures dev memory ordering, + * Client ensures read/write direction change ordering. + * - See Bug 200312466 for more details. + * + * CGID_TAG_ADR is only present from T186 A02. As this code is common + * between A01 and A02, tegra_memctrl_set_overrides() programs + * CGID_TAG_ADR for the necessary clients on A02. + */ + mc_set_txn_override(HDAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(BPMPW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(PTCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVDISPLAYR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(EQOSW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVJPGSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(ISPRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SDMMCWAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(VICSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(MPCOREW, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE); + mc_set_txn_override(GPUSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(AXISR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SCEDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SDMMCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(EQOSR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + /* See bug 200131110 comment #35*/ + mc_set_txn_override(APEDMAR, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVENCSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SDMMCRAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(VICSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(BPMPDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(VIW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SDMMCRAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(AXISW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(XUSB_DEVR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(UFSHCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(TSECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(GPUSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SATAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(XUSB_HOSTW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT); + mc_set_txn_override(TSECSWRB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(GPUSRD2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SCEDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(GPUSWR2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(AONDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + /* See bug 200131110 comment #35*/ + mc_set_txn_override(APEDMAW, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(AONW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(HOST1XDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(ETRR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SESWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVJPGSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVDECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(TSECSRDB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(BPMPDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(APER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVDECSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(XUSB_HOSTR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(ISPWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SESRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SCER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(AONR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(MPCORER, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE); + mc_set_txn_override(SDMMCWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(HDAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVDECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(UFSHCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(AONDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SATAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT); + mc_set_txn_override(ETRW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(VICSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVENCSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + /* See bug 200131110 comment #35 */ + mc_set_txn_override(AFIR, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SDMMCWAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SDMMCRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(NVDISPLAYR1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(ISPWB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(BPMPR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(APEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(SDMMCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + mc_set_txn_override(XUSB_DEVW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT); + mc_set_txn_override(TSECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + /* + * See bug 200131110 comment #35 - there are no normal requests + * and AWID for SO/DEV requests is hardcoded in RTL for a + * particular PCIE controller + */ + mc_set_txn_override(AFIW, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_COHERENT); + mc_set_txn_override(SCEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); + + /* + * At this point, ordering can occur at ROC. So, remove PCFIFO's + * control over ordering requests. + * + * Change PCFIFO_*_ORDERED_CLIENT from ORDERED -> UNORDERED for + * boot and strongly ordered MSS clients + */ + val = MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL & + mc_set_pcfifo_unordered_boot_so_mss(1, AFIW) & + mc_set_pcfifo_unordered_boot_so_mss(1, HDAW) & + mc_set_pcfifo_unordered_boot_so_mss(1, SATAW); + tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG1, val); + + val = MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL & + mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_HOSTW) & + mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_DEVW); + tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG2, val); + + val = MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL & + mc_set_pcfifo_unordered_boot_so_mss(3, SDMMCWAB); + tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG3, val); + + val = MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL & + mc_set_pcfifo_unordered_boot_so_mss(4, SESWR) & + mc_set_pcfifo_unordered_boot_so_mss(4, ETRW) & + mc_set_pcfifo_unordered_boot_so_mss(4, AXISW) & + mc_set_pcfifo_unordered_boot_so_mss(4, UFSHCW) & + mc_set_pcfifo_unordered_boot_so_mss(4, BPMPDMAW) & + mc_set_pcfifo_unordered_boot_so_mss(4, AONDMAW) & + mc_set_pcfifo_unordered_boot_so_mss(4, SCEDMAW); + /* EQOSW is the only client that has PCFIFO order enabled. */ + val |= mc_set_pcfifo_ordered_boot_so_mss(4, EQOSW); + tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG4, val); + + val = MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL & + mc_set_pcfifo_unordered_boot_so_mss(5, APEDMAW); + tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG5, val); + + /* + * Deassert HOTRESET FLUSH_ENABLE for boot and strongly ordered MSS + * clients to allow memory traffic from all clients to start passing + * through ROC + */ + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0); + assert(val == wdata_0); + + wdata_0 = MC_CLIENT_HOTRESET_CTRL0_RESET_VAL; + tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0); + + val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1); + assert(val == wdata_1); + + wdata_1 = MC_CLIENT_HOTRESET_CTRL1_RESET_VAL; + tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1); + +#endif +} + +static void tegra186_memctrl_set_overrides(void) +{ + uint32_t i, val; + + /* + * Set the MC_TXN_OVERRIDE registers for write clients. + */ + if ((tegra_chipid_is_t186()) && + (!tegra_platform_is_silicon() || + (tegra_platform_is_silicon() && (tegra_get_chipid_minor() == 1U)))) { + + /* + * GPU and NVENC settings for Tegra186 simulation and + * Silicon rev. A01 + */ + val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR); + val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; + tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR, + val | MC_TXN_OVERRIDE_CGID_TAG_ZERO); + + val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2); + val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; + tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2, + val | MC_TXN_OVERRIDE_CGID_TAG_ZERO); + + val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR); + val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; + tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR, + val | MC_TXN_OVERRIDE_CGID_TAG_CLIENT_AXI_ID); + + } else { + + /* + * Settings for Tegra186 silicon rev. A02 and onwards. + */ + for (i = 0; i < ARRAY_SIZE(tegra186_txn_override_cfgs); i++) { + val = tegra_mc_read_32(tegra186_txn_override_cfgs[i].offset); + val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; + tegra_mc_write_32(tegra186_txn_override_cfgs[i].offset, + val | tegra186_txn_override_cfgs[i].cgid_tag); + } + } +} + + +/******************************************************************************* + * Array to hold MC context for Tegra186 + ******************************************************************************/ +static __attribute__((aligned(16))) mc_regs_t tegra186_mc_context[] = { + _START_OF_TABLE_, + mc_make_sid_security_cfg(SCEW), + mc_make_sid_security_cfg(AFIR), + mc_make_sid_security_cfg(NVDISPLAYR1), + mc_make_sid_security_cfg(XUSB_DEVR), + mc_make_sid_security_cfg(VICSRD1), + mc_make_sid_security_cfg(NVENCSWR), + mc_make_sid_security_cfg(TSECSRDB), + mc_make_sid_security_cfg(AXISW), + mc_make_sid_security_cfg(SDMMCWAB), + mc_make_sid_security_cfg(AONDMAW), + mc_make_sid_security_cfg(GPUSWR2), + mc_make_sid_security_cfg(SATAW), + mc_make_sid_security_cfg(UFSHCW), + mc_make_sid_security_cfg(AFIW), + mc_make_sid_security_cfg(SDMMCR), + mc_make_sid_security_cfg(SCEDMAW), + mc_make_sid_security_cfg(UFSHCR), + mc_make_sid_security_cfg(SDMMCWAA), + mc_make_sid_security_cfg(APEDMAW), + mc_make_sid_security_cfg(SESWR), + mc_make_sid_security_cfg(MPCORER), + mc_make_sid_security_cfg(PTCR), + mc_make_sid_security_cfg(BPMPW), + mc_make_sid_security_cfg(ETRW), + mc_make_sid_security_cfg(GPUSRD), + mc_make_sid_security_cfg(VICSWR), + mc_make_sid_security_cfg(SCEDMAR), + mc_make_sid_security_cfg(HDAW), + mc_make_sid_security_cfg(ISPWA), + mc_make_sid_security_cfg(EQOSW), + mc_make_sid_security_cfg(XUSB_HOSTW), + mc_make_sid_security_cfg(TSECSWR), + mc_make_sid_security_cfg(SDMMCRAA), + mc_make_sid_security_cfg(APER), + mc_make_sid_security_cfg(VIW), + mc_make_sid_security_cfg(APEW), + mc_make_sid_security_cfg(AXISR), + mc_make_sid_security_cfg(SDMMCW), + mc_make_sid_security_cfg(BPMPDMAW), + mc_make_sid_security_cfg(ISPRA), + mc_make_sid_security_cfg(NVDECSWR), + mc_make_sid_security_cfg(XUSB_DEVW), + mc_make_sid_security_cfg(NVDECSRD), + mc_make_sid_security_cfg(MPCOREW), + mc_make_sid_security_cfg(NVDISPLAYR), + mc_make_sid_security_cfg(BPMPDMAR), + mc_make_sid_security_cfg(NVJPGSWR), + mc_make_sid_security_cfg(NVDECSRD1), + mc_make_sid_security_cfg(TSECSRD), + mc_make_sid_security_cfg(NVJPGSRD), + mc_make_sid_security_cfg(SDMMCWA), + mc_make_sid_security_cfg(SCER), + mc_make_sid_security_cfg(XUSB_HOSTR), + mc_make_sid_security_cfg(VICSRD), + mc_make_sid_security_cfg(AONDMAR), + mc_make_sid_security_cfg(AONW), + mc_make_sid_security_cfg(SDMMCRA), + mc_make_sid_security_cfg(HOST1XDMAR), + mc_make_sid_security_cfg(EQOSR), + mc_make_sid_security_cfg(SATAR), + mc_make_sid_security_cfg(BPMPR), + mc_make_sid_security_cfg(HDAR), + mc_make_sid_security_cfg(SDMMCRAB), + mc_make_sid_security_cfg(ETRR), + mc_make_sid_security_cfg(AONR), + mc_make_sid_security_cfg(APEDMAR), + mc_make_sid_security_cfg(SESRD), + mc_make_sid_security_cfg(NVENCSRD), + mc_make_sid_security_cfg(GPUSWR), + mc_make_sid_security_cfg(TSECSWRB), + mc_make_sid_security_cfg(ISPWB), + mc_make_sid_security_cfg(GPUSRD2), + mc_make_sid_override_cfg(APER), + mc_make_sid_override_cfg(VICSRD), + mc_make_sid_override_cfg(NVENCSRD), + mc_make_sid_override_cfg(NVJPGSWR), + mc_make_sid_override_cfg(AONW), + mc_make_sid_override_cfg(BPMPR), + mc_make_sid_override_cfg(BPMPW), + mc_make_sid_override_cfg(HDAW), + mc_make_sid_override_cfg(NVDISPLAYR1), + mc_make_sid_override_cfg(APEDMAR), + mc_make_sid_override_cfg(AFIR), + mc_make_sid_override_cfg(AXISR), + mc_make_sid_override_cfg(VICSRD1), + mc_make_sid_override_cfg(TSECSRD), + mc_make_sid_override_cfg(BPMPDMAW), + mc_make_sid_override_cfg(MPCOREW), + mc_make_sid_override_cfg(XUSB_HOSTR), + mc_make_sid_override_cfg(GPUSWR), + mc_make_sid_override_cfg(XUSB_DEVR), + mc_make_sid_override_cfg(UFSHCW), + mc_make_sid_override_cfg(XUSB_HOSTW), + mc_make_sid_override_cfg(SDMMCWAB), + mc_make_sid_override_cfg(SATAW), + mc_make_sid_override_cfg(SCEDMAR), + mc_make_sid_override_cfg(HOST1XDMAR), + mc_make_sid_override_cfg(SDMMCWA), + mc_make_sid_override_cfg(APEDMAW), + mc_make_sid_override_cfg(SESWR), + mc_make_sid_override_cfg(AXISW), + mc_make_sid_override_cfg(AONDMAW), + mc_make_sid_override_cfg(TSECSWRB), + mc_make_sid_override_cfg(MPCORER), + mc_make_sid_override_cfg(ISPWB), + mc_make_sid_override_cfg(AONR), + mc_make_sid_override_cfg(BPMPDMAR), + mc_make_sid_override_cfg(HDAR), + mc_make_sid_override_cfg(SDMMCRA), + mc_make_sid_override_cfg(ETRW), + mc_make_sid_override_cfg(GPUSWR2), + mc_make_sid_override_cfg(EQOSR), + mc_make_sid_override_cfg(TSECSWR), + mc_make_sid_override_cfg(ETRR), + mc_make_sid_override_cfg(NVDECSRD), + mc_make_sid_override_cfg(TSECSRDB), + mc_make_sid_override_cfg(SDMMCRAA), + mc_make_sid_override_cfg(NVDECSRD1), + mc_make_sid_override_cfg(SDMMCR), + mc_make_sid_override_cfg(NVJPGSRD), + mc_make_sid_override_cfg(SCEDMAW), + mc_make_sid_override_cfg(SDMMCWAA), + mc_make_sid_override_cfg(APEW), + mc_make_sid_override_cfg(AONDMAR), + mc_make_sid_override_cfg(PTCR), + mc_make_sid_override_cfg(SCER), + mc_make_sid_override_cfg(ISPRA), + mc_make_sid_override_cfg(ISPWA), + mc_make_sid_override_cfg(VICSWR), + mc_make_sid_override_cfg(SESRD), + mc_make_sid_override_cfg(SDMMCW), + mc_make_sid_override_cfg(SDMMCRAB), + mc_make_sid_override_cfg(EQOSW), + mc_make_sid_override_cfg(GPUSRD2), + mc_make_sid_override_cfg(SCEW), + mc_make_sid_override_cfg(GPUSRD), + mc_make_sid_override_cfg(NVDECSWR), + mc_make_sid_override_cfg(XUSB_DEVW), + mc_make_sid_override_cfg(SATAR), + mc_make_sid_override_cfg(NVDISPLAYR), + mc_make_sid_override_cfg(VIW), + mc_make_sid_override_cfg(UFSHCR), + mc_make_sid_override_cfg(NVENCSWR), + mc_make_sid_override_cfg(AFIW), + 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_ */ + tegra186_mc_context[0].val = (uint32_t)(ARRAY_SIZE(tegra186_mc_context)) - 1U; + + return tegra186_mc_context; +} + +void plat_memctrl_setup(void) +{ + uint32_t val; + unsigned int i; + + /* Program all the Stream ID overrides */ + for (i = 0U; i < ARRAY_SIZE(tegra186_streamid_override_regs); i++) { + tegra_mc_streamid_write_32(tegra186_streamid_override_regs[i], + MC_STREAM_ID_MAX); + } + + /* Program the security config settings for all Stream IDs */ + for (i = 0U; i < ARRAY_SIZE(tegra186_streamid_sec_cfgs); i++) { + val = (tegra186_streamid_sec_cfgs[i].override_enable << 16) | + (tegra186_streamid_sec_cfgs[i].override_client_inputs << 8) | + (tegra186_streamid_sec_cfgs[i].override_client_ns_flag << 0); + tegra_mc_streamid_write_32(tegra186_streamid_sec_cfgs[i].offset, val); + } + + /* + * Re-configure MSS to allow ROC to deal with ordering of the + * Memory Controller traffic. This is needed as the Memory Controller + * boots with MSS having all control, but ROC provides a performance + * boost as compared to MSS. + */ + tegra186_memctrl_reconfig_mss_clients(); + + /* Program overrides for MC transactions */ + tegra186_memctrl_set_overrides(); +} + +/******************************************************************************* + * Handler to restore platform specific settings to the memory controller + ******************************************************************************/ +void plat_memctrl_restore(void) +{ + /* + * Re-configure MSS to allow ROC to deal with ordering of the + * Memory Controller traffic. This is needed as the Memory Controller + * boots with MSS having all control, but ROC provides a performance + * boost as compared to MSS. + */ + tegra186_memctrl_reconfig_mss_clients(); + + /* Program overrides for MC transactions */ + tegra186_memctrl_set_overrides(); +} + +/******************************************************************************* + * 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 val; + + /* + * 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, (uint32_t)phys_base); + tegra_mc_write_32(MC_SECURITY_CFG3_0, (uint32_t)(phys_base >> 32)); + tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20); + + /* + * When TZ encryption is enabled, we need to setup TZDRAM + * before CPU accesses TZ Carveout, else CPU will fetch + * non-decrypted data. So save TZDRAM setting for SC7 resume + * FW to restore. + * + * Scratch registers map: + * RSV55_0 = CFG1[12:0] | CFG0[31:20] + * RSV55_1 = CFG3[1:0] + */ + val = tegra_mc_read_32(MC_SECURITY_CFG1_0) & MC_SECURITY_SIZE_MB_MASK; + val |= tegra_mc_read_32(MC_SECURITY_CFG0_0) & MC_SECURITY_BOM_MASK; + mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_LO, val); + + val = tegra_mc_read_32(MC_SECURITY_CFG3_0) & MC_SECURITY_BOM_HI_MASK; + mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_HI, val); + + /* + * MCE propagates the security configuration values across the + * CCPLEX. + */ + (void)mce_update_gsc_tzdram(); +} diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c new file mode 100644 index 0000000..af4182e --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <stdbool.h> +#include <string.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <context.h> +#include <cortex_a57.h> +#include <denver.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/psci/psci.h> +#include <plat/common/platform.h> + +#include <bpmp_ipc.h> +#include <mce.h> +#include <memctrl_v2.h> +#include <security_engine.h> +#include <smmu.h> +#include <t18x_ari.h> +#include <tegra186_private.h> +#include <tegra_private.h> + +extern void memcpy16(void *dest, const void *src, unsigned int length); + +/* state id mask */ +#define TEGRA186_STATE_ID_MASK 0xFU +/* constants to get power state's wake time */ +#define TEGRA186_WAKE_TIME_MASK 0x0FFFFFF0U +#define TEGRA186_WAKE_TIME_SHIFT 4U +/* default core wake mask for CPU_SUSPEND */ +#define TEGRA186_CORE_WAKE_MASK 0x180cU +/* context size to save during system suspend */ +#define TEGRA186_SE_CONTEXT_SIZE 3U + +static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE]; +static struct tegra_psci_percpu_data { + uint32_t wake_time; +} __aligned(CACHE_WRITEBACK_GRANULE) tegra_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) & TEGRA186_STATE_ID_MASK; + uint32_t cpu = plat_my_core_pos(); + int32_t ret = PSCI_E_SUCCESS; + + /* save the core wake time (in TSC ticks)*/ + tegra_percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK) + << TEGRA186_WAKE_TIME_SHIFT; + + /* + * Clean 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)&tegra_percpu_data[cpu], + sizeof(tegra_percpu_data[cpu])); + + /* Sanity check the requested state id */ + switch (state_id) { + case PSTATE_ID_CORE_IDLE: + case PSTATE_ID_CORE_POWERDN: + + if (psci_get_pstate_type(power_state) != PSTATE_TYPE_POWERDOWN) { + ret = PSCI_E_INVALID_PARAMS; + break; + } + + /* Core powerdown request */ + req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id; + req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id; + + 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) +{ + (void)cpu_state; + 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_afflvl0, stateid_afflvl2; + uint32_t cpu = plat_my_core_pos(); + const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + mce_cstate_info_t cstate_info = { 0 }; + uint64_t mc_ctx_base; + uint32_t val; + + /* get the state ID */ + pwr_domain_state = target_state->pwr_domain_state; + stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] & + TEGRA186_STATE_ID_MASK; + stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & + TEGRA186_STATE_ID_MASK; + + if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) || + (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) { + + /* Enter CPU idle/powerdown */ + val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ? + (uint32_t)TEGRA_ARI_CORE_C6 : (uint32_t)TEGRA_ARI_CORE_C7; + (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val, + tegra_percpu_data[cpu].wake_time, 0U); + + } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + + /* save SE registers */ + se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + + SE_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE + + RNG_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE + + PKA_MUTEX_WATCHDOG_NS_LIMIT); + + /* 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 to TZDRAM */ + mc_ctx_base = params_from_bl2->tzdram_base; + tegra_mc_save_context((uintptr_t)mc_ctx_base); + + /* Prepare for system suspend */ + cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7; + cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7; + cstate_info.system_state_force = 1; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + + /* Loop until system suspend is allowed */ + do { + val = (uint32_t)mce_command_handler( + (uint64_t)MCE_CMD_IS_SC7_ALLOWED, + (uint64_t)TEGRA_ARI_CORE_C7, + MCE_CORE_SLEEP_TIME_INFINITE, + 0U); + } while (val == 0U); + + /* Instruct the MCE to enter system suspend state */ + (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, + (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U); + + } else { + ; /* do nothing */ + } + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Helper function to check if this is the last ON CPU in the cluster + ******************************************************************************/ +static bool tegra_last_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; + uint32_t cpu = plat_my_core_pos(); + int32_t ret; + plat_local_state_t target = states[core_pos]; + mce_cstate_info_t cstate_info = { 0 }; + + /* CPU suspend */ + if (target == PSTATE_ID_CORE_POWERDN) { + /* Program default wake mask */ + cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + + /* Check if CCx state is allowed. */ + ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED, + (uint64_t)TEGRA_ARI_CORE_C7, + tegra_percpu_data[cpu].wake_time, + 0U); + if (ret == 0) { + target = PSCI_LOCAL_STATE_RUN; + } + } + + /* CPU off */ + if (target == PLAT_MAX_OFF_STATE) { + /* Enable cluster powerdn from last CPU in the cluster */ + if (tegra_last_cpu_in_cluster(states, ncpu)) { + /* Enable CC7 state and turn off wake mask */ + cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + + /* Check if CCx state is allowed. */ + ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED, + (uint64_t)TEGRA_ARI_CORE_C7, + MCE_CORE_SLEEP_TIME_INFINITE, + 0U); + if (ret == 0) { + target = PSCI_LOCAL_STATE_RUN; + } + + } else { + + /* Turn off wake_mask */ + cstate_info.update_wake_mask = 1; + 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; + const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & + TEGRA186_STATE_ID_MASK; + uint64_t val; + uint64_t src_len_in_bytes = (uint64_t)(((uintptr_t)(&__BL31_END__) - + (uintptr_t)BL31_BASE)); + int32_t ret; + + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + val = params_from_bl2->tzdram_base + + tegra186_get_mc_ctx_size(); + + /* Initialise communication channel with BPMP */ + assert(tegra_bpmp_ipc_init() == 0); + + /* Enable SE clock */ + ret = tegra_bpmp_ipc_enable_clock(TEGRA186_CLK_SE); + if (ret != 0) { + ERROR("Failed to enable clock\n"); + return ret; + } + + /* + * Generate/save SHA256 of ATF during SC7 entry + */ + if (tegra_se_save_sha256_hash(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 + + tegra186_get_mc_ctx_size(); + memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE, + (uintptr_t)BL31_END - (uintptr_t)BL31_BASE); + + /* + * Save code base and size; this would be used by SC7-RF to + * verify binary + */ + mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV68_LO, + (uint32_t)val); + mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV0_HI, + (uint32_t)src_len_in_bytes); + + ret = tegra_bpmp_ipc_disable_clock(TEGRA186_CLK_SE); + if (ret != 0) { + ERROR("Failed to disable clock\n"); + return ret; + } + } + + return PSCI_E_SUCCESS; +} + +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) +{ + int32_t ret = PSCI_E_SUCCESS; + uint64_t target_cpu = mpidr & MPIDR_CPU_MASK; + uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >> + MPIDR_AFFINITY_BITS; + + if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) { + + ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr); + ret = PSCI_E_NOT_PRESENT; + + } else { + /* construct the target CPU # */ + target_cpu |= (target_cluster << 2); + + (void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U); + } + + return ret; +} + +int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; + uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0]; + mce_cstate_info_t cstate_info = { 0 }; + uint64_t impl, val; + const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); + + impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + + /* + * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186 + * A02p and beyond). + */ + if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) { + + val = read_l2ctlr_el1(); + val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT; + write_l2ctlr_el1(val); + } + + /* + * 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. + */ + if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) { + + cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + } + + /* + * Check if we are exiting from deep sleep and restore SE + * context if we are. + */ + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + + mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[0]); + mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[1]); + mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[2]); + + /* Init SMMU */ + tegra_smmu_init(); + + /* + * Reset power state info for the last core doing SC7 + * entry and exit, we set deepest power state as CC7 + * and SC7 for SC7 entry which may not be requested by + * non-secure SW which controls idle states. + */ + cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7; + cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + } + + 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) & (uint64_t)MIDR_IMPL_MASK; + + (void)target_state; + + /* Disable Denver's DCO operations */ + if (impl == DENVER_IMPL) { + denver_disable_dco(); + } + + /* Turn off CPU */ + (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, + (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U); + + return PSCI_E_SUCCESS; +} + +__dead2 void tegra_soc_prepare_system_off(void) +{ + /* power off the entire system */ + mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF); + + wfi(); + + /* wait for the system to power down */ + for (;;) { + ; + } +} + +int32_t tegra_soc_prepare_system_reset(void) +{ + mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT); + + return PSCI_E_SUCCESS; +} diff --git a/plat/nvidia/tegra/soc/t186/plat_secondary.c b/plat/nvidia/tegra/soc/t186/plat_secondary.c new file mode 100644 index 0000000..fbb550a --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/plat_secondary.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <string.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <lib/mmio.h> + +#include <mce.h> +#include <tegra_def.h> +#include <tegra_private.h> + +#define SCRATCH_SECURE_RSV1_SCRATCH_0 0x658U +#define SCRATCH_SECURE_RSV1_SCRATCH_1 0x65CU + +#define CPU_RESET_MODE_AA64 1U + +/******************************************************************************* + * Setup secondary CPU vectors + ******************************************************************************/ +void plat_secondary_setup(void) +{ + uint32_t addr_low, addr_high; + + INFO("Setting up secondary CPU boot\n"); + + /* TZDRAM base will be used as the "resume" address */ + addr_low = (uintptr_t)&tegra_secure_entrypoint | CPU_RESET_MODE_AA64; + addr_high = (uintptr_t)(((uintptr_t)&tegra_secure_entrypoint >> 32U) & 0x7ffU); + + /* save reset vector to be used during SYSTEM_SUSPEND exit */ + mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO, + addr_low); + mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI, + addr_high); +} diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c new file mode 100644 index 0000000..d6d090a --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <bl31/bl31.h> +#include <bl31/interrupt_mgmt.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <common/ep_info.h> +#include <common/interrupt_props.h> +#include <context.h> +#include <cortex_a57.h> +#include <denver.h> +#include <drivers/arm/gic_common.h> +#include <drivers/arm/gicv2.h> +#include <drivers/console.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/utils.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <plat/common/platform.h> + +#include <mce.h> +#include <memctrl.h> +#include <smmu.h> +#include <tegra_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +extern void memcpy16(void *dest, const void *src, unsigned int length); + +/******************************************************************************* + * Tegra186 CPU numbers in cluster #0 + ******************************************************************************* + */ +#define TEGRA186_CLUSTER0_CORE2 2U +#define TEGRA186_CLUSTER0_CORE3 3U + +/******************************************************************************* + * 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 +}; + +/******************************************************************************* + * 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, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_TSA_BASE, 0x20000U, /* 128KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_MC_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000U, /* 128KB - UART A, B*/ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000U, /* 128KB - UART C, G */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000U, /* 192KB - UART D, E, F */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_FUSE_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x20000U, /* 128KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_PMC_BASE, 0x40000U, /* 256KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_TMRUS_BASE, 0x1000U, /* 4KB */ + MT_DEVICE | MT_RO | MT_SECURE), + MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_MMCRAB_BASE, 0x60000U, /* 384KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_ARM_ACTMON_CTR_BASE, 0x20000U, /* 128KB - ARM/Denver */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_SMMU0_BASE, 0x1000000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_HSP_DBELL_BASE, 0x10000U, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_BPMP_IPC_TX_PHYS_BASE, TEGRA_BPMP_IPC_CH_MAP_SIZE, /* 4KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_BPMP_IPC_RX_PHYS_BASE, TEGRA_BPMP_IPC_CH_MAP_SIZE, /* 4KB */ + MT_DEVICE | MT_RW | 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; +} + +/******************************************************************************* + * Maximum supported UART controllers + ******************************************************************************/ +#define TEGRA186_MAX_UART_PORTS 7 + +/******************************************************************************* + * This variable holds the UART port base addresses + ******************************************************************************/ +static uint32_t tegra186_uart_addresses[TEGRA186_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, +}; + +/******************************************************************************* + * Enable console corresponding to the console ID + ******************************************************************************/ +void plat_enable_console(int32_t id) +{ + static console_t uart_console; + uint32_t console_clock; + + if ((id > 0) && (id < TEGRA186_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(tegra186_uart_addresses[id], + console_clock, + TEGRA_CONSOLE_BAUDRATE, + &uart_console); + console_set_scope(&uart_console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); + } +} + +/******************************************************************************* + * Handler for early platform setup + ******************************************************************************/ +void plat_early_platform_setup(void) +{ + uint64_t impl, val; + const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); + const struct tegra_bl31_params *arg_from_bl2 = plat_get_bl31_params(); + + /* Verify chip id is t186 */ + assert(tegra_chipid_is_t186()); + + /* sanity check MCE firmware compatibility */ + mce_verify_firmware_version(); + + /* + * Do initial security configuration to allow DRAM/device access. + */ + tegra_memctrl_tzdram_setup(plat_params->tzdram_base, + (uint32_t)plat_params->tzdram_size); + + impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK; + + /* + * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186 + * A02p and beyond). + */ + if ((plat_params->l2_ecc_parity_prot_dis != 1) && + (impl != (uint64_t)DENVER_IMPL)) { + + val = read_l2ctlr_el1(); + val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT; + write_l2ctlr_el1(val); + } + + /* + * The previous bootloader might not have placed the BL32 image + * inside the TZDRAM. Platform handler to allow relocation of BL32 + * image to TZDRAM memory. This behavior might change per platform. + */ + plat_relocate_bl32_image(arg_from_bl2->bl32_image_info); +} + +/******************************************************************************* + * Handler for late platform setup + ******************************************************************************/ +void plat_late_platform_setup(void) +{ + ; /* do nothing */ +} + +/* Secure IRQs for Tegra186 */ +static const interrupt_prop_t tegra186_interrupt_props[] = { + INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI, + GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(TEGRA186_TOP_WDT_IRQ, PLAT_TEGRA_WDT_PRIO, + GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(TEGRA186_AON_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(tegra186_interrupt_props, ARRAY_SIZE(tegra186_interrupt_props)); + tegra_gic_init(); + + /* + * Initialize the FIQ handler only if the platform supports any + * FIQ interrupt sources. + */ + tegra_fiq_handler_setup(); +} + +/******************************************************************************* + * Return pointer to the BL31 params from previous bootloader + ******************************************************************************/ +struct tegra_bl31_params *plat_get_bl31_params(void) +{ + uint32_t val; + + val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_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) +{ + uint32_t val; + + val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_ADDR); + + return (plat_params_from_bl2_t *)(uintptr_t)val; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. + ******************************************************************************/ +int32_t plat_core_pos_by_mpidr(u_register_t mpidr) +{ + u_register_t cluster_id, cpu_id, pos; + int32_t ret; + + cluster_id = (mpidr >> (u_register_t)MPIDR_AFF1_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK; + cpu_id = (mpidr >> (u_register_t)MPIDR_AFF0_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK; + + /* + * Validate cluster_id by checking whether it represents + * one of the two clusters present on the platform. + * Validate cpu_id by checking whether it represents a CPU in + * one of the two clusters present on the platform. + */ + if ((cluster_id >= (u_register_t)PLATFORM_CLUSTER_COUNT) || + (cpu_id >= (u_register_t)PLATFORM_MAX_CPUS_PER_CLUSTER)) { + ret = PSCI_E_NOT_PRESENT; + } else { + /* calculate the core position */ + pos = cpu_id + (cluster_id << 2U); + + /* check for non-existent CPUs */ + if ((pos == TEGRA186_CLUSTER0_CORE2) || (pos == TEGRA186_CLUSTER0_CORE3)) { + ret = PSCI_E_NOT_PRESENT; + } else { + ret = (int32_t)pos; + } + } + + return ret; +} + +/******************************************************************************* + * Handler to relocate BL32 image to TZDRAM + ******************************************************************************/ +void plat_relocate_bl32_image(const image_info_t *bl32_img_info) +{ + const plat_params_from_bl2_t *plat_bl31_params = plat_get_bl31_plat_params(); + const entry_point_info_t *bl32_ep_info = bl31_plat_get_next_image_ep_info(SECURE); + uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end; + + if ((bl32_img_info != NULL) && (bl32_ep_info != NULL)) { + + /* Relocate BL32 if it resides outside of the TZDRAM */ + tzdram_start = plat_bl31_params->tzdram_base; + tzdram_end = plat_bl31_params->tzdram_base + + plat_bl31_params->tzdram_size; + bl32_start = bl32_img_info->image_base; + bl32_end = bl32_img_info->image_base + bl32_img_info->image_size; + + assert(tzdram_end > tzdram_start); + assert(bl32_end > bl32_start); + assert(bl32_ep_info->pc > tzdram_start); + assert(bl32_ep_info->pc < tzdram_end); + + /* relocate BL32 */ + if ((bl32_start >= tzdram_end) || (bl32_end <= tzdram_start)) { + + INFO("Relocate BL32 to TZDRAM\n"); + + (void)memcpy16((void *)(uintptr_t)bl32_ep_info->pc, + (void *)(uintptr_t)bl32_start, + bl32_img_info->image_size); + + /* clean up non-secure intermediate buffer */ + zeromem((void *)(uintptr_t)bl32_start, + bl32_img_info->image_size); + } + } +} + +/******************************************************************************* + * Handler to indicate support for System Suspend + ******************************************************************************/ +bool plat_supports_system_suspend(void) +{ + return true; +} +/******************************************************************************* + * Platform specific runtime setup. + ******************************************************************************/ +void plat_runtime_setup(void) +{ + /* + * During cold boot, it is observed that the arbitration + * bit is set in the Memory controller leading to false + * error interrupts in the non-secure world. To avoid + * this, clean the interrupt status register before + * booting into the non-secure world + */ + tegra_memctrl_clear_pending_interrupts(); + + /* + * During boot, USB3 and flash media (SDMMC/SATA) devices need + * access to IRAM. Because these clients connect to the MC and + * do not have a direct path to the IRAM, the MC implements AHB + * redirection during boot to allow path to IRAM. In this mode + * accesses to a programmed memory address aperture are directed + * to the AHB bus, allowing access to the IRAM. This mode must be + * disabled before we jump to the non-secure world. + */ + tegra_memctrl_disable_ahb_redirection(); + + /* + * Verify the integrity of the previously configured SMMU(s) + * settings + */ + tegra_smmu_verify(); +} diff --git a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c new file mode 100644 index 0000000..4de8a9e --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <common/runtime_svc.h> +#include <denver.h> +#include <lib/el3_runtime/context_mgmt.h> + +#include <mce.h> +#include <memctrl.h> +#include <t18x_ari.h> +#include <tegra_private.h> + +/******************************************************************************* + * Offset to read the ref_clk counter value + ******************************************************************************/ +#define REF_CLK_OFFSET 4ULL + +/******************************************************************************* + * Tegra186 SiP SMCs + ******************************************************************************/ +#define TEGRA_SIP_GET_ACTMON_CLK_COUNTERS 0xC2FFFE02 +#define TEGRA_SIP_MCE_CMD_ENTER_CSTATE 0xC2FFFF00 +#define TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO 0xC2FFFF01 +#define TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME 0xC2FFFF02 +#define TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS 0xC2FFFF03 +#define TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS 0xC2FFFF04 +#define TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED 0xC2FFFF05 + +#define TEGRA_SIP_MCE_CMD_CC3_CTRL 0xC2FFFF07 +#define TEGRA_SIP_MCE_CMD_ECHO_DATA 0xC2FFFF08 +#define TEGRA_SIP_MCE_CMD_READ_VERSIONS 0xC2FFFF09 +#define TEGRA_SIP_MCE_CMD_ENUM_FEATURES 0xC2FFFF0A +#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS 0xC2FFFF0B +#define TEGRA_SIP_MCE_CMD_ENUM_READ_MCA 0xC2FFFF0C +#define TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA 0xC2FFFF0D +#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE 0xC2FFFF0E +#define TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE 0xC2FFFF0F +#define TEGRA_SIP_MCE_CMD_ENABLE_LATIC 0xC2FFFF10 +#define TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ 0xC2FFFF11 +#define TEGRA_SIP_MCE_CMD_MISC_CCPLEX 0xC2FFFF12 + +/******************************************************************************* + * This function is responsible for handling all T186 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 mce_ret, ret = 0; + uint32_t impl, cpu; + uint32_t base, core_clk_ctr, ref_clk_ctr; + uint32_t local_smc_fid = smc_fid; + uint64_t local_x1 = x1, local_x2 = x2, local_x3 = x3; + + (void)x4; + (void)cookie; + (void)flags; + + if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) { + /* 32-bit function, clear top parameter bits */ + + local_x1 = (uint32_t)x1; + local_x2 = (uint32_t)x2; + local_x3 = (uint32_t)x3; + } + + /* + * Convert SMC FID to SMC64, to support SMC32/SMC64 configurations + */ + local_smc_fid |= (SMC_64 << FUNCID_CC_SHIFT); + + switch (local_smc_fid) { + /* + * Micro Coded Engine (MCE) commands reside in the 0x82FFFF00 - + * 0x82FFFFFF SiP SMC space + */ + case TEGRA_SIP_MCE_CMD_ENTER_CSTATE: + case TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO: + case TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME: + case TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS: + case TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS: + case TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED: + case TEGRA_SIP_MCE_CMD_CC3_CTRL: + case TEGRA_SIP_MCE_CMD_ECHO_DATA: + case TEGRA_SIP_MCE_CMD_READ_VERSIONS: + case TEGRA_SIP_MCE_CMD_ENUM_FEATURES: + case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS: + case TEGRA_SIP_MCE_CMD_ENUM_READ_MCA: + case TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA: + case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE: + case TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE: + case TEGRA_SIP_MCE_CMD_ENABLE_LATIC: + case TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ: + case TEGRA_SIP_MCE_CMD_MISC_CCPLEX: + + /* clean up the high bits */ + local_smc_fid &= MCE_CMD_MASK; + + /* execute the command and store the result */ + mce_ret = mce_command_handler(local_smc_fid, local_x1, local_x2, local_x3); + write_ctx_reg(get_gpregs_ctx(handle), + CTX_GPREG_X0, (uint64_t)(mce_ret)); + break; + + /* + * This function ID reads the Activity monitor's core/ref clock + * counter values for a core/cluster. + * + * x1 = MPIDR of the target core + * x2 = MIDR of the target core + */ + case TEGRA_SIP_GET_ACTMON_CLK_COUNTERS: + + cpu = (uint32_t)x1 & MPIDR_CPU_MASK; + impl = ((uint32_t)x2 >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + + /* sanity check target CPU number */ + if (cpu > (uint32_t)PLATFORM_MAX_CPUS_PER_CLUSTER) { + ret = -EINVAL; + } else { + /* get the base address for the current CPU */ + base = (impl == DENVER_IMPL) ? TEGRA_DENVER_ACTMON_CTR_BASE : + TEGRA_ARM_ACTMON_CTR_BASE; + + /* read the clock counter values */ + core_clk_ctr = mmio_read_32(base + (8ULL * cpu)); + ref_clk_ctr = mmio_read_32(base + (8ULL * cpu) + REF_CLK_OFFSET); + + /* return the counter values as two different parameters */ + write_ctx_reg(get_gpregs_ctx(handle), + CTX_GPREG_X1, (core_clk_ctr)); + write_ctx_reg(get_gpregs_ctx(handle), + CTX_GPREG_X2, (ref_clk_ctr)); + } + + break; + + default: + ret = -ENOTSUP; + break; + } + + return ret; +} diff --git a/plat/nvidia/tegra/soc/t186/plat_smmu.c b/plat/nvidia/tegra/soc/t186/plat_smmu.c new file mode 100644 index 0000000..f1bc235 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/plat_smmu.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/bl_common.h> + +#include <smmu.h> +#include <tegra_def.h> +#include <tegra_mc_def.h> + +#define MAX_NUM_SMMU_DEVICES U(1) + +/******************************************************************************* + * Handler to return the support SMMU devices number + ******************************************************************************/ +uint32_t plat_get_num_smmu_devices(void) +{ + return MAX_NUM_SMMU_DEVICES; +} diff --git a/plat/nvidia/tegra/soc/t186/plat_trampoline.S b/plat/nvidia/tegra/soc/t186/plat_trampoline.S new file mode 100644 index 0000000..2fc2046 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/plat_trampoline.S @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <common/bl_common.h> +#include <memctrl_v2.h> +#include <plat/common/common_def.h> +#include <tegra_def.h> + +#define TEGRA186_MC_CTX_SIZE 0x93 + + .globl tegra186_get_mc_ctx_size + + /* + * Tegra186 reset data (offset 0x0 - 0x420) + * + * 0x000: MC context start + * 0x420: MC context end + */ + + .align 4 +__tegra186_mc_context: + .rept TEGRA186_MC_CTX_SIZE + .quad 0 + .endr + + .align 4 +__tegra186_mc_context_end: + +/* return the size of the MC context */ +func tegra186_get_mc_ctx_size + adr x0, __tegra186_mc_context_end + adr x1, __tegra186_mc_context + sub x0, x0, x1 + ret +endfunc tegra186_get_mc_ctx_size diff --git a/plat/nvidia/tegra/soc/t186/platform_t186.mk b/plat/nvidia/tegra/soc/t186/platform_t186.mk new file mode 100644 index 0000000..5275b8e --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/platform_t186.mk @@ -0,0 +1,77 @@ +# +# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2020, NVIDIA Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# platform configs +ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS := 1 +$(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS)) + +ENABLE_CHIP_VERIFICATION_HARNESS := 0 +$(eval $(call add_define,ENABLE_CHIP_VERIFICATION_HARNESS)) + +RESET_TO_BL31 := 1 + +PROGRAMMABLE_RESET_ADDRESS := 0 + +COLD_BOOT_SINGLE_CPU := 1 + +RELOCATE_BL32_IMAGE := 1 + +# platform settings +TZDRAM_BASE := 0x30000000 +$(eval $(call add_define,TZDRAM_BASE)) + +PLATFORM_CLUSTER_COUNT := 2 +$(eval $(call add_define,PLATFORM_CLUSTER_COUNT)) + +PLATFORM_MAX_CPUS_PER_CLUSTER := 4 +$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER)) + +MAX_XLAT_TABLES := 25 +$(eval $(call add_define,MAX_XLAT_TABLES)) + +MAX_MMAP_REGIONS := 30 +$(eval $(call add_define,MAX_MMAP_REGIONS)) + +# platform files +PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t186 \ + -I${SOC_DIR}/drivers/include + +BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \ + drivers/ti/uart/aarch64/16550_console.S \ + lib/cpus/aarch64/denver.S \ + lib/cpus/aarch64/cortex_a57.S \ + ${TEGRA_DRIVERS}/bpmp_ipc/intf.c \ + ${TEGRA_DRIVERS}/bpmp_ipc/ivc.c \ + ${TEGRA_DRIVERS}/gpcdma/gpcdma.c \ + ${TEGRA_DRIVERS}/memctrl/memctrl_v2.c \ + ${TEGRA_DRIVERS}/smmu/smmu.c \ + ${SOC_DIR}/drivers/mce/mce.c \ + ${SOC_DIR}/drivers/mce/ari.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 + +# Enable workarounds for selected Cortex-A57 erratas. +A57_DISABLE_NON_TEMPORAL_HINT := 1 +ERRATA_A57_806969 := 1 +ERRATA_A57_813419 := 1 +ERRATA_A57_813420 := 1 +ERRATA_A57_826974 := 1 +ERRATA_A57_826977 := 1 +ERRATA_A57_828024 := 1 +ERRATA_A57_829520 := 1 +ERRATA_A57_833471 := 1 + +# Enable higher performance Non-cacheable load forwarding +A57_ENABLE_NONCACHEABLE_LOAD_FWD := 1 |