Tegra186: mce: driver for the CPU complex power manager block
authorVarun Wadekar <vwadekar@nvidia.com>
Tue, 14 Mar 2017 21:24:35 +0000 (14:24 -0700)
committerVarun Wadekar <vwadekar@nvidia.com>
Mon, 20 Mar 2017 16:09:36 +0000 (09:09 -0700)
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 <vwadekar@nvidia.com>
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
plat/nvidia/tegra/soc/t186/drivers/include/mce.h [new file with mode: 0644]
plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h [new file with mode: 0644]
plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S [new file with mode: 0644]
plat/nvidia/tegra/soc/t186/drivers/mce/ari.c [new file with mode: 0644]
plat/nvidia/tegra/soc/t186/drivers/mce/mce.c [new file with mode: 0644]
plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c [new file with mode: 0644]
plat/nvidia/tegra/soc/t186/platform_t186.mk

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 (file)
index 0000000..7078b8b
--- /dev/null
@@ -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 <mmio.h>
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * 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 (file)
index 0000000..3e6054b
--- /dev/null
@@ -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 (file)
index 0000000..e1398cc
--- /dev/null
@@ -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 <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
+       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 (file)
index 0000000..147a358
--- /dev/null
@@ -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 <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <denver.h>
+#include <mmio.h>
+#include <mce.h>
+#include <sys/errno.h>
+#include <t18x_ari.h>
+
+/*******************************************************************************
+ * 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 (file)
index 0000000..9815107
--- /dev/null
@@ -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 <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <context.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <denver.h>
+#include <mce.h>
+#include <mmio.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <t18x_ari.h>
+#include <tegra_def.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
+};
+
+/* 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 (file)
index 0000000..25479a2
--- /dev/null
@@ -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 <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <denver.h>
+#include <mmio.h>
+#include <mce.h>
+#include <sys/errno.h>
+#include <t18x_ari.h>
+
+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;
+}
index 374b6e617c3b98663926ec03fa2c6339b02d7521..e29282a396f345a8bf606303e18e524087c293e3 100644 (file)
@@ -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             \