From 7808b06b991905e58228c8c4df7026be637b0c00 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Tue, 14 Mar 2017 14:24:35 -0700 Subject: [PATCH] Tegra186: mce: driver for the CPU complex power manager block The CPU Complex (CCPLEX) Power Manager (Denver MCE, or DMCE) is an offload engine for BPMP to do voltage related sequencing and for hardware requests to be handled in a better latency than BPMP-firmware. There are two interfaces to the MCEs - Abstract Request Interface (ARI) and the traditional NVGINDEX/NVGDATA interface. MCE supports various commands which can be used by CPUs - ARM as well as Denver, for power management and reset functionality. Since the linux kernel is the master for all these scenarios, each MCE command can be issued by a corresponding SMC. These SMCs have been moved to SiP SMC space as they are specific to the Tegra186 SoC. Change-Id: I67bee83d2289a8ab63bc5556e5744e5043803e51 Signed-off-by: Varun Wadekar Signed-off-by: Varun Wadekar --- .../tegra/soc/t186/drivers/include/mce.h | 358 ++++++++++++++ .../tegra/soc/t186/drivers/include/t18x_ari.h | 450 ++++++++++++++++++ .../t186/drivers/mce/aarch64/nvg_helpers.S | 56 +++ plat/nvidia/tegra/soc/t186/drivers/mce/ari.c | 391 +++++++++++++++ plat/nvidia/tegra/soc/t186/drivers/mce/mce.c | 432 +++++++++++++++++ plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c | 239 ++++++++++ plat/nvidia/tegra/soc/t186/platform_t186.mk | 4 + 7 files changed, 1930 insertions(+) create mode 100644 plat/nvidia/tegra/soc/t186/drivers/include/mce.h create mode 100644 plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h create mode 100644 plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S create mode 100644 plat/nvidia/tegra/soc/t186/drivers/mce/ari.c create mode 100644 plat/nvidia/tegra/soc/t186/drivers/mce/mce.c create mode 100644 plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/mce.h b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h new file mode 100644 index 00000000..7078b8bb --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MCE_H__ +#define __MCE_H__ + +#include +#include + +/******************************************************************************* + * MCE apertures used by the ARI interface + * + * Aperture 0 - Cpu0 (ARM Cortex A-57) + * Aperture 1 - Cpu1 (ARM Cortex A-57) + * Aperture 2 - Cpu2 (ARM Cortex A-57) + * Aperture 3 - Cpu3 (ARM Cortex A-57) + * Aperture 4 - Cpu4 (Denver15) + * Aperture 5 - Cpu5 (Denver15) + ******************************************************************************/ +#define MCE_ARI_APERTURE_0_OFFSET 0x0 +#define MCE_ARI_APERTURE_1_OFFSET 0x10000 +#define MCE_ARI_APERTURE_2_OFFSET 0x20000 +#define MCE_ARI_APERTURE_3_OFFSET 0x30000 +#define MCE_ARI_APERTURE_4_OFFSET 0x40000 +#define MCE_ARI_APERTURE_5_OFFSET 0x50000 +#define MCE_ARI_APERTURE_OFFSET_MAX MCE_APERTURE_5_OFFSET + +/* number of apertures */ +#define MCE_ARI_APERTURES_MAX 6 + +/* each ARI aperture is 64KB */ +#define MCE_ARI_APERTURE_SIZE 0x10000 + +/******************************************************************************* + * CPU core ids - used by the MCE_ONLINE_CORE ARI + ******************************************************************************/ +typedef enum mce_core_id { + MCE_CORE_ID_DENVER_15_0, + MCE_CORE_ID_DENVER_15_1, + /* 2 and 3 are reserved */ + MCE_CORE_ID_A57_0 = 4, + MCE_CORE_ID_A57_1, + MCE_CORE_ID_A57_2, + MCE_CORE_ID_A57_3, + MCE_CORE_ID_MAX +} mce_core_id_t; + +#define MCE_CORE_ID_MASK 0x7 + +/******************************************************************************* + * MCE commands + ******************************************************************************/ +typedef enum mce_cmd { + MCE_CMD_ENTER_CSTATE = 0, + MCE_CMD_UPDATE_CSTATE_INFO, + MCE_CMD_UPDATE_CROSSOVER_TIME, + MCE_CMD_READ_CSTATE_STATS, + MCE_CMD_WRITE_CSTATE_STATS, + MCE_CMD_IS_SC7_ALLOWED, + MCE_CMD_ONLINE_CORE, + MCE_CMD_CC3_CTRL, + MCE_CMD_ECHO_DATA, + MCE_CMD_READ_VERSIONS, + MCE_CMD_ENUM_FEATURES, + MCE_CMD_ROC_FLUSH_CACHE_TRBITS, + MCE_CMD_ENUM_READ_MCA, + MCE_CMD_ENUM_WRITE_MCA, + MCE_CMD_ROC_FLUSH_CACHE, + MCE_CMD_ROC_CLEAN_CACHE, + MCE_CMD_IS_CCX_ALLOWED = 0xFE, + MCE_CMD_MAX = 0xFF, +} mce_cmd_t; + +#define MCE_CMD_MASK 0xFF + +/******************************************************************************* + * Macros to prepare CSTATE info request + ******************************************************************************/ +/* Description of the parameters for UPDATE_CSTATE_INFO request */ +#define CLUSTER_CSTATE_MASK 0x7 +#define CLUSTER_CSTATE_SHIFT 0 +#define CLUSTER_CSTATE_UPDATE_BIT (1 << 7) +#define CCPLEX_CSTATE_MASK 0x3 +#define CCPLEX_CSTATE_SHIFT 8 +#define CCPLEX_CSTATE_UPDATE_BIT (1 << 15) +#define SYSTEM_CSTATE_MASK 0xF +#define SYSTEM_CSTATE_SHIFT 16 +#define SYSTEM_CSTATE_FORCE_UPDATE_SHIFT 22 +#define SYSTEM_CSTATE_FORCE_UPDATE_BIT (1 << 22) +#define SYSTEM_CSTATE_UPDATE_BIT (1 << 23) +#define CSTATE_WAKE_MASK_UPDATE_BIT (1 << 31) +#define CSTATE_WAKE_MASK_SHIFT 32 +#define CSTATE_WAKE_MASK_CLEAR 0xFFFFFFFF + +/******************************************************************************* + * Auto-CC3 control macros + ******************************************************************************/ +#define MCE_AUTO_CC3_FREQ_MASK 0x1FF +#define MCE_AUTO_CC3_FREQ_SHIFT 0 +#define MCE_AUTO_CC3_VTG_MASK 0x7F +#define MCE_AUTO_CC3_VTG_SHIFT 16 +#define MCE_AUTO_CC3_ENABLE_BIT (1 << 31) + +/******************************************************************************* + * Macros for the 'IS_SC7_ALLOWED' command + ******************************************************************************/ +#define MCE_SC7_ALLOWED_MASK 0x7 +#define MCE_SC7_WAKE_TIME_SHIFT 32 + +/******************************************************************************* + * Macros for 'read/write ctats' commands + ******************************************************************************/ +#define MCE_CSTATE_STATS_TYPE_SHIFT 32 +#define MCE_CSTATE_WRITE_DATA_LO_MASK 0xF + +/******************************************************************************* + * Macros for 'update crossover threshold' command + ******************************************************************************/ +#define MCE_CROSSOVER_THRESHOLD_TIME_SHIFT 32 + +/******************************************************************************* + * Timeout value used to powerdown a core + ******************************************************************************/ +#define MCE_CORE_SLEEP_TIME_INFINITE 0xFFFFFFFF + +/******************************************************************************* + * MCA command struct + ******************************************************************************/ +typedef union mca_cmd { + struct command { + uint8_t cmd; + uint8_t idx; + uint8_t subidx; + } command; + struct input { + uint32_t low; + uint32_t high; + } input; + uint64_t data; +} mca_cmd_t; + +/******************************************************************************* + * MCA argument struct + ******************************************************************************/ +typedef union mca_arg { + struct err { + uint64_t error:8; + uint64_t unused:48; + uint64_t finish:8; + } err; + struct arg { + uint32_t low; + uint32_t high; + } arg; + uint64_t data; +} mca_arg_t; + +/******************************************************************************* + * 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. + */ + int (*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. + */ + int (*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. + */ + int (*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. + */ + int (*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 + */ + int (*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 + */ + int (*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. + */ + int (*online_core)(uint32_t ari_base, uint32_t cpuid); + /* + * This ARI request allows the CPU to enable/disable Auto-CC3 idle + * state. + */ + int (*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. + */ + int (*update_reset_vector)(uint32_t ari_base, + uint32_t addr_low, + uint32_t addr_high); + /* + * This ARI request instructs the ROC to flush A57 data caches in + * order to maintain coherency with the Denver cluster. + */ + int (*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. + */ + int (*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. + */ + int (*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, + mca_cmd_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. + */ + int (*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); +} arch_mce_ops_t; + +int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, + uint64_t arg2); +int mce_update_reset_vector(uint32_t addr_lo, uint32_t addr_hi); +int mce_update_gsc_videomem(void); +int mce_update_gsc_tzdram(void); +int mce_update_gsc_tzram(void); +__dead2 void mce_enter_ccplex_state(uint32_t state_idx); + +/* declarations for ARI/NVG handler functions */ +int ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int 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); +int 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); +int 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); +int ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int ari_online_core(uint32_t ari_base, uint32_t core); +int ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable); +int ari_reset_vector_update(uint32_t ari_base, uint32_t lo, uint32_t hi); +int ari_roc_flush_cache_trbits(uint32_t ari_base); +int ari_roc_flush_cache(uint32_t ari_base); +int ari_roc_clean_cache(uint32_t ari_base); +uint64_t ari_read_write_mca(uint32_t ari_base, mca_cmd_t cmd, uint64_t *data); +int 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); + +int nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int 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); +int 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); +int nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t val); +int nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); +int nvg_online_core(uint32_t ari_base, uint32_t core); +int nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable); + +#endif /* __MCE_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 00000000..3e6054bd --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef T18X_TEGRA_ARI_H +#define T18X_TEGRA_ARI_H + +/* + * ---------------------------------------------------------------------------- + * t18x_ari.h + * + * Global ARI definitions. + * ---------------------------------------------------------------------------- + */ + +enum { + TEGRA_ARI_VERSION_MAJOR = 2, + TEGRA_ARI_VERSION_MINOR = 19, +}; + +typedef enum { + /* indexes below get the core lock */ + TEGRA_ARI_MISC = 0, + /* index 1 is deprecated */ + /* index 2 is deprecated */ + /* index 3 is deprecated */ + TEGRA_ARI_ONLINE_CORE = 4, + + /* indexes below need cluster lock */ + TEGRA_ARI_MISC_CLUSTER = 41, + TEGRA_ARI_IS_CCX_ALLOWED = 42, + TEGRA_ARI_CC3_CTRL = 43, + + /* indexes below need ccplex lock */ + TEGRA_ARI_ENTER_CSTATE = 80, + TEGRA_ARI_UPDATE_CSTATE_INFO = 81, + TEGRA_ARI_IS_SC7_ALLOWED = 82, + /* index 83 is deprecated */ + TEGRA_ARI_PERFMON = 84, + TEGRA_ARI_UPDATE_CCPLEX_GSC = 85, + /* index 86 is depracated */ + /* index 87 is deprecated */ + TEGRA_ARI_ROC_FLUSH_CACHE_ONLY = 88, + TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS = 89, + TEGRA_ARI_MISC_CCPLEX = 90, + TEGRA_ARI_MCA = 91, + TEGRA_ARI_UPDATE_CROSSOVER = 92, + TEGRA_ARI_CSTATE_STATS = 93, + TEGRA_ARI_WRITE_CSTATE_STATS = 94, + TEGRA_ARI_COPY_MISCREG_AA64_RST = 95, + TEGRA_ARI_ROC_CLEAN_CACHE_ONLY = 96, +} tegra_ari_req_id_t; + +typedef enum { + TEGRA_ARI_MISC_ECHO = 0, + TEGRA_ARI_MISC_VERSION = 1, + TEGRA_ARI_MISC_FEATURE_LEAF_0 = 2, +} tegra_ari_misc_index_t; + +typedef enum { + TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF = 0, + TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT = 1, + TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL = 2, +} tegra_ari_misc_ccplex_index_t; + +typedef enum { + TEGRA_ARI_CORE_C0 = 0, + TEGRA_ARI_CORE_C1 = 1, + TEGRA_ARI_CORE_C6 = 6, + TEGRA_ARI_CORE_C7 = 7, + TEGRA_ARI_CORE_WARMRSTREQ = 8, +} tegra_ari_core_sleep_state_t; + +typedef enum { + TEGRA_ARI_CLUSTER_CC0 = 0, + TEGRA_ARI_CLUSTER_CC1 = 1, + TEGRA_ARI_CLUSTER_CC6 = 6, + TEGRA_ARI_CLUSTER_CC7 = 7, +} tegra_ari_cluster_sleep_state_t; + +typedef enum { + TEGRA_ARI_CCPLEX_CCP0 = 0, + TEGRA_ARI_CCPLEX_CCP1 = 1, + TEGRA_ARI_CCPLEX_CCP3 = 3, +} tegra_ari_ccplex_sleep_state_t; + +typedef enum { + TEGRA_ARI_SYSTEM_SC0 = 0, + TEGRA_ARI_SYSTEM_SC1 = 1, + TEGRA_ARI_SYSTEM_SC2 = 2, + TEGRA_ARI_SYSTEM_SC3 = 3, + TEGRA_ARI_SYSTEM_SC4 = 4, + TEGRA_ARI_SYSTEM_SC7 = 7, + TEGRA_ARI_SYSTEM_SC8 = 8, +} tegra_ari_system_sleep_state_t; + +typedef enum { + TEGRA_ARI_CROSSOVER_C1_C6 = 0, + TEGRA_ARI_CROSSOVER_CC1_CC6 = 1, + TEGRA_ARI_CROSSOVER_CC1_CC7 = 2, + TEGRA_ARI_CROSSOVER_CCP1_CCP3 = 3, + TEGRA_ARI_CROSSOVER_CCP3_SC2 = 4, + TEGRA_ARI_CROSSOVER_CCP3_SC3 = 5, + TEGRA_ARI_CROSSOVER_CCP3_SC4 = 6, + TEGRA_ARI_CROSSOVER_CCP3_SC7 = 7, + TEGRA_ARI_CROSSOVER_CCP3_SC1 = 8, +} tegra_ari_crossover_index_t; + +typedef enum { + TEGRA_ARI_CSTATE_STATS_CLEAR = 0, + TEGRA_ARI_CSTATE_STATS_SC7_ENTRIES = 1, + TEGRA_ARI_CSTATE_STATS_SC4_ENTRIES, + TEGRA_ARI_CSTATE_STATS_SC3_ENTRIES, + TEGRA_ARI_CSTATE_STATS_SC2_ENTRIES, + TEGRA_ARI_CSTATE_STATS_CCP3_ENTRIES, + 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 = 14, + TEGRA_ARI_CSTATE_STATS_D15_1_C7_ENTRIES, + TEGRA_ARI_CSTATE_STATS_A57_0_C7_ENTRIES = 18, + 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 = 26, + 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 = 0, + + TEGRA_ARI_GSC_BPMP = 6, + TEGRA_ARI_GSC_APE = 7, + TEGRA_ARI_GSC_SPE = 8, + TEGRA_ARI_GSC_SCE = 9, + TEGRA_ARI_GSC_APR = 10, + TEGRA_ARI_GSC_TZRAM = 11, + TEGRA_ARI_GSC_SE = 12, + + TEGRA_ARI_GSC_BPMP_TO_SPE = 16, + TEGRA_ARI_GSC_SPE_TO_BPMP = 17, + TEGRA_ARI_GSC_CPU_TZ_TO_BPMP = 18, + TEGRA_ARI_GSC_BPMP_TO_CPU_TZ = 19, + TEGRA_ARI_GSC_CPU_NS_TO_BPMP = 20, + TEGRA_ARI_GSC_BPMP_TO_CPU_NS = 21, + TEGRA_ARI_GSC_IPC_SE_SPE_SCE_BPMP = 22, + TEGRA_ARI_GSC_SC7_RESUME_FW = 23, + + TEGRA_ARI_GSC_TZ_DRAM_IDX = 34, + TEGRA_ARI_GSC_VPR_IDX = 35, +} 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, 0, 2), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE_PRESENT, 7, 7), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE, 8, 9), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE_PRESENT, 15, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE, 16, 19), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__IGNORE_CROSSOVERS, 22, 22), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE_PRESENT, 23, 23), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__WAKE_MASK_PRESENT, 31, 31), +} tegra_ari_update_cstate_info_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL__EN, 0, 0), +} tegra_ari_misc_ccplex_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_FREQ, 0, 8), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_VOLT, 16, 23), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__ENABLE, 31, 31), +} tegra_ari_cc3_ctrl_bitmasks_t; + +typedef enum { + TEGRA_ARI_MCA_NOP = 0, + TEGRA_ARI_MCA_READ_SERR = 1, + TEGRA_ARI_MCA_WRITE_SERR = 2, + TEGRA_ARI_MCA_CLEAR_SERR = 4, + TEGRA_ARI_MCA_REPORT_SERR = 5, + TEGRA_ARI_MCA_READ_INTSTS = 6, + TEGRA_ARI_MCA_WRITE_INTSTS = 7, + TEGRA_ARI_MCA_READ_PREBOOT_SERR = 8, +} tegra_ari_mca_commands_t; + +typedef enum { + TEGRA_ARI_MCA_RD_WR_DPMU = 0, + TEGRA_ARI_MCA_RD_WR_IOB = 1, + TEGRA_ARI_MCA_RD_WR_MCB = 2, + TEGRA_ARI_MCA_RD_WR_CCE = 3, + TEGRA_ARI_MCA_RD_WR_CQX = 4, + TEGRA_ARI_MCA_RD_WR_CTU = 5, + TEGRA_ARI_MCA_RD_BANK_INFO = 0x0f, + TEGRA_ARI_MCA_RD_BANK_TEMPLATE = 0x10, + TEGRA_ARI_MCA_RD_WR_SECURE_ACCESS_REGISTER = 0x11, + TEGRA_ARI_MCA_RD_WR_GLOBAL_CONFIG_REGISTER = 0x12, +} tegra_ari_mca_rd_wr_indexes_t; + +typedef enum { + TEGRA_ARI_MCA_RD_WR_ASERRX_CTRL = 0, + TEGRA_ARI_MCA_RD_WR_ASERRX_STATUS = 1, + TEGRA_ARI_MCA_RD_WR_ASERRX_ADDR = 2, + TEGRA_ARI_MCA_RD_WR_ASERRX_MISC1 = 3, + TEGRA_ARI_MCA_RD_WR_ASERRX_MISC2 = 4, +} tegra_ari_mca_read_asserx_subindexes_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_SETTING_ENABLES_NS_PERMITTED, 0, 0), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_READING_STATUS_NS_PERMITTED, 1, 1), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_PENDING_MCA_ERRORS_NS_PERMITTED, 2, 2), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_CLEARING_MCA_INTERRUPTS_NS_PERMITTED, 3, 3), +} tegra_ari_mca_secure_register_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_SERR_ERR_CODE, 0, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM_ERR, 16, 16), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_CRAB_ERR, 17, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_RD_WR_N, 18, 18), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UCODE_ERR, 19, 19), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM, 20, 23), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_AV, 58, 58), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_MV, 59, 59), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_EN, 60, 60), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UC, 61, 61), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_OVF, 62, 62), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_VAL, 63, 63), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_ADDR, 0, 41), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_UCODE_ERRCD, 42, 52), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_PWM_ERR, 0, 0), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_CRAB_ERR, 1, 1), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_UCODE_ERR, 3, 3), +} tegra_ari_mca_aserr0_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_SERR_ERR_CODE, 0, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MSI_ERR, 16, 16), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_IHI_ERR, 17, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CRI_ERR, 18, 18), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MMCRAB_ERR, 19, 19), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CSI_ERR, 20, 20), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RD_WR_N, 21, 21), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_REQ_ERRT, 22, 23), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RESP_ERRT, 24, 25), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AV, 58, 58), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MV, 59, 59), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_EN, 60, 60), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_UC, 61, 61), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_OVF, 62, 62), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_VAL, 63, 63), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AXI_ID, 0, 7), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_ID, 8, 27), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CID, 28, 31), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CMD, 32, 35), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MSI_ERR, 0, 0), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_IHI_ERR, 1, 1), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CRI_ERR, 2, 2), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MMCRAB_ERR, 3, 3), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CSI_ERR, 4, 4), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_MISC_ADDR, 0, 41), +} tegra_ari_mca_aserr1_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SERR_ERR_CODE, 0, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MC_ERR, 16, 16), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SYSRAM_ERR, 17, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_CLIENT_ID, 18, 19), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_AV, 58, 58), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MV, 59, 59), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_EN, 60, 60), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_UC, 61, 61), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_OVF, 62, 62), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_VAL, 63, 63), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ID, 0, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_CMD, 18, 21), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ADDR, 22, 53), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_CTRL_EN_MC_ERR, 0, 0), +} tegra_ari_mca_aserr2_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_SERR_ERR_CODE, 0, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_TO_ERR, 16, 16), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_STAT_ERR, 17, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_DST_ERR, 18, 18), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UNC_ERR, 19, 19), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MH_ERR, 20, 20), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PERR, 21, 21), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PSN_ERR, 22, 22), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_AV, 58, 58), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MV, 59, 59), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_EN, 60, 60), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UC, 61, 61), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_OVF, 62, 62), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_VAL, 63, 63), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_CMD, 0, 5), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_ADDR, 6, 47), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TO, 0, 0), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_DIV4, 1, 1), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TLIMIT, 2, 11), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_PSN_ERR_CORR_MSK, 12, 25), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_MORE_INFO, 0, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TO_INFO, 18, 43), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_SRC, 44, 45), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TID, 46, 52), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_TO_ERR, 0, 0), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_STAT_ERR, 1, 1), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_DST_ERR, 2, 2), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_UNC_ERR, 3, 3), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_MH_ERR, 4, 4), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PERR, 5, 5), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PSN_ERR, 6, 19), +} tegra_ari_mca_aserr3_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SERR_ERR_CODE, 0, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SRC_ERR, 16, 16), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_DST_ERR, 17, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_REQ_ERR, 18, 18), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_RSP_ERR, 19, 19), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_AV, 58, 58), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_MV, 59, 59), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_EN, 60, 60), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_UC, 61, 61), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_OVF, 62, 62), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_VAL, 63, 63), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_CTRL_EN_CPE_ERR, 0, 0), +} tegra_ari_mca_aserr4_bitmasks_t; + +typedef enum { + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_SERR_ERR_CODE, 0, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_CTUPAR, 16, 16), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MULTI, 17, 17), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_AV, 58, 58), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MV, 59, 59), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_EN, 60, 60), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_UC, 61, 61), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_OVF, 62, 62), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_VAL, 63, 63), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_SRC, 0, 7), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ID, 8, 15), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_DATA, 16, 26), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_CMD, 32, 35), + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ADDR, 36, 45), + + TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_CTRL_EN_CTUPAR, 0, 0), +} tegra_ari_mca_aserr5_bitmasks_t; + +#undef TEGRA_ARI_ENUM_MASK_LSB_MSB + +typedef enum { + TEGRA_NVG_CHANNEL_PMIC = 0, + TEGRA_NVG_CHANNEL_POWER_PERF = 1, + TEGRA_NVG_CHANNEL_POWER_MODES = 2, + TEGRA_NVG_CHANNEL_WAKE_TIME = 3, + TEGRA_NVG_CHANNEL_CSTATE_INFO = 4, + TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 = 5, + TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC6 = 6, + TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC7 = 7, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP1_CCP3 = 8, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC2 = 9, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC3 = 10, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC4 = 11, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC7 = 12, + TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR = 13, + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC7_ENTRIES = 14, + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC4_ENTRIES = 15, + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC3_ENTRIES = 16, + TEGRA_NVG_CHANNEL_CSTATE_STATS_SC2_ENTRIES = 17, + TEGRA_NVG_CHANNEL_CSTATE_STATS_CCP3_ENTRIES = 18, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC6_ENTRIES = 19, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC7_ENTRIES = 20, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC6_ENTRIES = 21, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC7_ENTRIES = 22, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C6_ENTRIES = 23, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C6_ENTRIES = 24, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C6_ENTRIES = 25, /* Reserved (for Denver15 core 2) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C6_ENTRIES = 26, /* Reserved (for Denver15 core 3) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C7_ENTRIES = 27, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C7_ENTRIES = 28, + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C7_ENTRIES = 29, /* Reserved (for Denver15 core 2) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C7_ENTRIES = 30, /* Reserved (for Denver15 core 3) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_0_C7_ENTRIES = 31, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_1_C7_ENTRIES = 32, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_2_C7_ENTRIES = 33, + TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_3_C7_ENTRIES = 34, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0 = 35, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1 = 36, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_2 = 37, /* Reserved (for Denver15 core 2) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_3 = 38, /* Reserved (for Denver15 core 3) */ + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 39, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1 = 40, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2 = 41, + TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3 = 42, + TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = 43, + TEGRA_NVG_CHANNEL_ONLINE_CORE = 44, + TEGRA_NVG_CHANNEL_CC3_CTRL = 45, + TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC1 = 46, + TEGRA_NVG_CHANNEL_LAST_INDEX, +} tegra_nvg_channel_id_t; + +#endif /* T18X_TEGRA_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 00000000..e1398cce --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + + .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 + isb + 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 00000000..147a358a --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************************* + * Register offsets for ARI request/results + ******************************************************************************/ +#define ARI_REQUEST 0x0 +#define ARI_REQUEST_EVENT_MASK 0x4 +#define ARI_STATUS 0x8 +#define ARI_REQUEST_DATA_LO 0xC +#define ARI_REQUEST_DATA_HI 0x10 +#define ARI_RESPONSE_DATA_LO 0x14 +#define ARI_RESPONSE_DATA_HI 0x18 + +/* Status values for the current request */ +#define ARI_REQ_PENDING 1 +#define ARI_REQ_ONGOING 3 +#define ARI_REQUEST_VALID_BIT (1 << 8) +#define ARI_EVT_MASK_STANDBYWFI_BIT (1 << 7) + +/******************************************************************************* + * ARI helper functions + ******************************************************************************/ +static inline uint32_t ari_read_32(uint32_t ari_base, uint32_t reg) +{ + return mmio_read_32(ari_base + reg); +} + +static inline void ari_write_32(uint32_t ari_base, uint32_t val, uint32_t reg) +{ + mmio_write_32(ari_base + 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 int ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req, + uint32_t lo, uint32_t hi) +{ + int status; + + /* 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) + return 0; + + /* NOTE: add timeout check if needed */ + status = ari_read_32(ari_base, ARI_STATUS); + while (status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) + status = ari_read_32(ari_base, ARI_STATUS); + + return 0; +} + +int ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + /* 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); + return EINVAL; + } + + /* Enter the cstate, to be woken up after wake_time (TSC ticks) */ + return ari_request_wait(ari_base, ARI_EVT_MASK_STANDBYWFI_BIT, + TEGRA_ARI_ENTER_CSTATE, state, wake_time); +} + +int 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) +{ + uint32_t val = 0; + + /* update CLUSTER_CSTATE? */ + if (cluster) + val |= (cluster & CLUSTER_CSTATE_MASK) | + CLUSTER_CSTATE_UPDATE_BIT; + + /* update CCPLEX_CSTATE? */ + if (ccplex) + val |= (ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT | + CCPLEX_CSTATE_UPDATE_BIT; + + /* update SYSTEM_CSTATE? */ + if (system) + val |= ((system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) | + ((sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) | + SYSTEM_CSTATE_UPDATE_BIT); + + /* update wake mask value? */ + if (update_wake_mask) + val |= CSTATE_WAKE_MASK_UPDATE_BIT; + + /* set the updated cstate info */ + return ari_request_wait(ari_base, 0, TEGRA_ARI_UPDATE_CSTATE_INFO, val, + wake_mask); +} + +int ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time) +{ + /* sanity check crossover type */ + if ((type == TEGRA_ARI_CROSSOVER_C1_C6) || + (type > TEGRA_ARI_CROSSOVER_CCP3_SC1)) + return EINVAL; + + /* update crossover threshold time */ + return ari_request_wait(ari_base, 0, TEGRA_ARI_UPDATE_CROSSOVER, + type, time); +} + +uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state) +{ + int ret; + + /* sanity check crossover type */ + if (state == 0) + return EINVAL; + + ret = ari_request_wait(ari_base, 0, TEGRA_ARI_CSTATE_STATS, state, 0); + if (ret != 0) + return EINVAL; + + return (uint64_t)ari_get_response_low(ari_base); +} + +int ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats) +{ + /* write the cstate stats */ + return ari_request_wait(ari_base, 0, 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; + int ret; + + /* 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) + data = 0; + + ret = ari_request_wait(ari_base, 0, TEGRA_ARI_MISC, cmd, data); + if (ret) + return (uint64_t)ret; + + /* get the command response */ + resp = ari_get_response_low(ari_base); + resp |= ((uint64_t)ari_get_response_high(ari_base) << 32); + + return resp; +} + +int ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + int ret; + + ret = ari_request_wait(ari_base, 0, TEGRA_ARI_IS_CCX_ALLOWED, state & 0x7, + wake_time); + if (ret) { + ERROR("%s: failed (%d)\n", __func__, ret); + return 0; + } + + /* 1 = CCx allowed, 0 = CCx not allowed */ + return (ari_get_response_low(ari_base) & 0x1); +} + +int ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + int ret; + + /* 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); + return EINVAL; + } + + ret = ari_request_wait(ari_base, 0, TEGRA_ARI_IS_SC7_ALLOWED, state, + wake_time); + if (ret) { + ERROR("%s: failed (%d)\n", __func__, ret); + return 0; + } + + /* 1 = SC7 allowed, 0 = SC7 not allowed */ + return !!ari_get_response_low(ari_base); +} + +int ari_online_core(uint32_t ari_base, uint32_t core) +{ + int cpu = read_mpidr() & MPIDR_CPU_MASK; + int cluster = (read_mpidr() & MPIDR_CLUSTER_MASK) >> + MPIDR_AFFINITY_BITS; + int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + + /* construct the current CPU # */ + cpu |= (cluster << 2); + + /* sanity check target core id */ + if ((core >= MCE_CORE_ID_MAX) || (cpu == core)) { + ERROR("%s: unsupported core id (%d)\n", __func__, core); + return EINVAL; + } + + /* + * The Denver cluster has 2 CPUs only - 0, 1. + */ + if (impl == DENVER_IMPL && ((core == 2) || (core == 3))) { + ERROR("%s: unknown core id (%d)\n", __func__, core); + return EINVAL; + } + + return ari_request_wait(ari_base, 0, TEGRA_ARI_ONLINE_CORE, core, 0); +} + +int ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable) +{ + int val; + + /* + * 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 ? MCE_AUTO_CC3_ENABLE_BIT : 0)); + + return ari_request_wait(ari_base, 0, TEGRA_ARI_CC3_CTRL, val, 0); +} + +int ari_reset_vector_update(uint32_t ari_base, uint32_t lo, uint32_t hi) +{ + /* + * Need to program the CPU reset vector one time during cold boot + * and SC7 exit + */ + ari_request_wait(ari_base, 0, TEGRA_ARI_COPY_MISCREG_AA64_RST, lo, hi); + + return 0; +} + +int ari_roc_flush_cache_trbits(uint32_t ari_base) +{ + return ari_request_wait(ari_base, 0, TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS, + 0, 0); +} + +int ari_roc_flush_cache(uint32_t ari_base) +{ + return ari_request_wait(ari_base, 0, TEGRA_ARI_ROC_FLUSH_CACHE_ONLY, + 0, 0); +} + +int ari_roc_clean_cache(uint32_t ari_base) +{ + return ari_request_wait(ari_base, 0, TEGRA_ARI_ROC_CLEAN_CACHE_ONLY, + 0, 0); +} + +uint64_t ari_read_write_mca(uint32_t ari_base, mca_cmd_t cmd, uint64_t *data) +{ + mca_arg_t mca_arg; + int ret; + + /* Set data (write) */ + mca_arg.data = data ? *data : 0ull; + + /* Set command */ + ari_write_32(ari_base, cmd.input.low, ARI_RESPONSE_DATA_LO); + ari_write_32(ari_base, cmd.input.high, ARI_RESPONSE_DATA_HI); + + ret = ari_request_wait(ari_base, 0, TEGRA_ARI_MCA, mca_arg.arg.low, + mca_arg.arg.high); + if (!ret) { + mca_arg.arg.low = ari_get_response_low(ari_base); + mca_arg.arg.high = ari_get_response_high(ari_base); + if (!mca_arg.err.finish) + return (uint64_t)mca_arg.err.error; + + if (data) { + mca_arg.arg.low = ari_get_request_low(ari_base); + mca_arg.arg.high = ari_get_request_high(ari_base); + *data = mca_arg.data; + } + } + + return 0; +} + +int ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx) +{ + /* sanity check GSC ID */ + if (gsc_idx > TEGRA_ARI_GSC_VPR_IDX) + return EINVAL; + + /* + * 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. + */ + ari_request_wait(ari_base, 0, TEGRA_ARI_UPDATE_CCPLEX_GSC, gsc_idx, 0); + + return 0; +} + +void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx) +{ + /* + * The MCE will shutdown or restart the entire system + */ + (void)ari_request_wait(ari_base, 0, TEGRA_ARI_MISC_CCPLEX, state_idx, 0); +} 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 00000000..98151070 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 +}; + +/* 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 +}; + +typedef struct mce_config { + 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) +{ + uint32_t mpidr = read_mpidr(); + int cpuid = mpidr & MPIDR_CPU_MASK; + int 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 |= 0x4; + + return mce_cfg_table[cpuid].ari_base; +} + +static arch_mce_ops_t *mce_get_curr_cpu_ops(void) +{ + uint32_t mpidr = read_mpidr(); + int cpuid = mpidr & MPIDR_CPU_MASK; + int 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 |= 0x4; + + return mce_cfg_table[cpuid].ops; +} + +/******************************************************************************* + * Common handler for all MCE commands + ******************************************************************************/ +int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, + uint64_t arg2) +{ + arch_mce_ops_t *ops; + uint32_t cpu_ari_base; + uint64_t ret64 = 0, arg3, arg4, arg5; + int ret = 0; + mca_cmd_t mca_cmd; + cpu_context_t *ctx = cm_get_context(NON_SECURE); + gp_regs_t *gp_regs = get_gpregs_ctx(ctx); + + assert(ctx); + assert(gp_regs); + + /* 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 MCE_CMD_ENTER_CSTATE: + ret = ops->enter_cstate(cpu_ari_base, arg0, arg1); + if (ret < 0) + ERROR("%s: enter_cstate failed(%d)\n", __func__, ret); + + break; + + case 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); + if (ret < 0) + ERROR("%s: update_cstate_info failed(%d)\n", + __func__, ret); + + write_ctx_reg(gp_regs, CTX_GPREG_X4, 0); + write_ctx_reg(gp_regs, CTX_GPREG_X5, 0); + write_ctx_reg(gp_regs, CTX_GPREG_X6, 0); + + break; + + case MCE_CMD_UPDATE_CROSSOVER_TIME: + ret = ops->update_crossover_time(cpu_ari_base, arg0, arg1); + if (ret < 0) + ERROR("%s: update_crossover_time failed(%d)\n", + __func__, ret); + + break; + + case 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 MCE_CMD_WRITE_CSTATE_STATS: + ret = ops->write_cstate_stats(cpu_ari_base, arg0, arg1); + if (ret < 0) + ERROR("%s: write_cstate_stats failed(%d)\n", + __func__, ret); + + break; + + case MCE_CMD_IS_CCX_ALLOWED: + ret = ops->is_ccx_allowed(cpu_ari_base, arg0, arg1); + if (ret < 0) { + ERROR("%s: is_ccx_allowed failed(%d)\n", __func__, ret); + break; + } + + /* update context to return CCx status value */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, ret); + + break; + + case MCE_CMD_IS_SC7_ALLOWED: + ret = ops->is_sc7_allowed(cpu_ari_base, arg0, arg1); + if (ret < 0) { + ERROR("%s: is_sc7_allowed failed(%d)\n", __func__, ret); + break; + } + + /* update context to return SC7 status value */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, ret); + write_ctx_reg(gp_regs, CTX_GPREG_X3, ret); + ret = 0; + + break; + + case MCE_CMD_ONLINE_CORE: + ret = ops->online_core(cpu_ari_base, arg0); + if (ret < 0) + ERROR("%s: online_core failed(%d)\n", __func__, ret); + + break; + + case MCE_CMD_CC3_CTRL: + ret = ops->cc3_ctrl(cpu_ari_base, arg0, arg1, arg2); + if (ret < 0) + ERROR("%s: cc3_ctrl failed(%d)\n", __func__, ret); + + break; + + case 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); + write_ctx_reg(gp_regs, CTX_GPREG_X2, ret64 == arg0); + + break; + + case 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, (uint32_t)ret64); + write_ctx_reg(gp_regs, CTX_GPREG_X2, (uint32_t)(ret64 >> 32)); + + break; + + case MCE_CMD_ENUM_FEATURES: + ret = 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); + + ret = 0; + + break; + + case MCE_CMD_ROC_FLUSH_CACHE_TRBITS: + ret = ops->roc_flush_cache_trbits(cpu_ari_base); + if (ret < 0) + ERROR("%s: flush cache_trbits failed(%d)\n", __func__, + ret); + + break; + + case MCE_CMD_ROC_FLUSH_CACHE: + ret = ops->roc_flush_cache(cpu_ari_base); + if (ret < 0) + ERROR("%s: flush cache failed(%d)\n", __func__, ret); + + break; + + case MCE_CMD_ROC_CLEAN_CACHE: + ret = ops->roc_clean_cache(cpu_ari_base); + if (ret < 0) + ERROR("%s: clean cache failed(%d)\n", __func__, ret); + + break; + + case MCE_CMD_ENUM_READ_MCA: + memcpy(&mca_cmd, &arg0, sizeof(arg0)); + ret64 = ops->read_write_mca(cpu_ari_base, mca_cmd, &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 MCE_CMD_ENUM_WRITE_MCA: + memcpy(&mca_cmd, &arg0, sizeof(arg0)); + ret64 = ops->read_write_mca(cpu_ari_base, mca_cmd, &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; + + default: + ERROR("unknown MCE command (%d)\n", cmd); + return EINVAL; + } + + return ret; +} + +/******************************************************************************* + * Handler to update the reset vector for CPUs + ******************************************************************************/ +int mce_update_reset_vector(uint32_t addr_lo, uint32_t addr_hi) +{ + arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); + + ops->update_reset_vector(mce_get_curr_cpu_ari_base(), addr_lo, addr_hi); + + return 0; +} + +static int mce_update_ccplex_gsc(tegra_ari_gsc_index_t gsc_idx) +{ + 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 + ******************************************************************************/ +int mce_update_gsc_videomem(void) +{ + return mce_update_ccplex_gsc(TEGRA_ARI_GSC_VPR_IDX); +} + +/******************************************************************************* + * Handler to update carveout values for TZDRAM aperture + ******************************************************************************/ +int mce_update_gsc_tzdram(void) +{ + return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZ_DRAM_IDX); +} + +/******************************************************************************* + * Handler to update carveout values for TZ SysRAM aperture + ******************************************************************************/ +int mce_update_gsc_tzram(void) +{ + return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZRAM); +} + +/******************************************************************************* + * Handler to shutdown/reset the entire system + ******************************************************************************/ +__dead2 void mce_enter_ccplex_state(uint32_t state_idx) +{ + 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 (;;) + ; + + 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 00000000..25479a24 --- /dev/null +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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); + +int nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + /* 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); + return EINVAL; + } + + /* time (TSC ticks) until the core is expected to get a wake event */ + nvg_set_request_data(TEGRA_NVG_CHANNEL_WAKE_TIME, wake_time); + + /* set the core cstate */ + write_actlr_el1(state); + + return 0; +} + +/* + * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and + * SYSTEM_CSTATE values. + */ +int 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 = 0; + + /* update CLUSTER_CSTATE? */ + if (cluster) + val |= (cluster & CLUSTER_CSTATE_MASK) | + CLUSTER_CSTATE_UPDATE_BIT; + + /* update CCPLEX_CSTATE? */ + if (ccplex) + val |= (ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT | + CCPLEX_CSTATE_UPDATE_BIT; + + /* update SYSTEM_CSTATE? */ + if (system) + val |= ((system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) | + ((sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) | + SYSTEM_CSTATE_UPDATE_BIT); + + /* update wake mask value? */ + if (update_wake_mask) + 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(TEGRA_NVG_CHANNEL_CSTATE_INFO, val); + + return 0; +} + +int nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time) +{ + /* sanity check crossover type */ + if (type > TEGRA_ARI_CROSSOVER_CCP3_SC1) + return EINVAL; + + /* + * 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 can 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 + type, + (uint64_t)time); + + return 0; +} + +uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state) +{ + /* sanity check state */ + if (state == 0) + return EINVAL; + + /* + * 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 + state); + + return (int64_t)nvg_get_result(); +} + +int nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats) +{ + uint64_t val; + + /* + * 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 + state, val); + + return 0; +} + +int nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + /* This does not apply to the Denver cluster */ + return 0; +} + +int nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) +{ + uint64_t val; + + /* 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); + return EINVAL; + } + + /* + * Request format - + * 63:32 = wake time + * 31:0 = C-state for this core + */ + val = ((uint64_t)wake_time << MCE_SC7_WAKE_TIME_SHIFT) | + (state & MCE_SC7_ALLOWED_MASK); + + /* issue command to check if SC7 is allowed */ + nvg_set_request_data(TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED, val); + + /* 1 = SC7 allowed, 0 = SC7 not allowed */ + return !!nvg_get_result(); +} + +int nvg_online_core(uint32_t ari_base, uint32_t core) +{ + int cpu = read_mpidr() & MPIDR_CPU_MASK; + int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + + /* sanity check code id */ + if ((core >= MCE_CORE_ID_MAX) || (cpu == core)) { + ERROR("%s: unsupported core id (%d)\n", __func__, core); + return EINVAL; + } + + /* + * The Denver cluster has 2 CPUs only - 0, 1. + */ + if (impl == DENVER_IMPL && ((core == 2) || (core == 3))) { + ERROR("%s: unknown core id (%d)\n", __func__, core); + return EINVAL; + } + + /* get a core online */ + nvg_set_request_data(TEGRA_NVG_CHANNEL_ONLINE_CORE, core & MCE_CORE_ID_MASK); + + return 0; +} + +int nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable) +{ + int val; + + /* + * 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 ? MCE_AUTO_CC3_ENABLE_BIT : 0)); + + nvg_set_request_data(TEGRA_NVG_CHANNEL_CC3_CTRL, val); + + return 0; +} diff --git a/plat/nvidia/tegra/soc/t186/platform_t186.mk b/plat/nvidia/tegra/soc/t186/platform_t186.mk index 374b6e61..e29282a3 100644 --- a/plat/nvidia/tegra/soc/t186/platform_t186.mk +++ b/plat/nvidia/tegra/soc/t186/platform_t186.mk @@ -54,6 +54,10 @@ PLAT_INCLUDES += -I${SOC_DIR}/drivers/include BL31_SOURCES += lib/cpus/aarch64/denver.S \ lib/cpus/aarch64/cortex_a57.S \ ${COMMON_DIR}/drivers/memctrl/memctrl_v2.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}/plat_psci_handlers.c \ ${SOC_DIR}/plat_setup.c \ ${SOC_DIR}/plat_secondary.c \ -- 2.30.2