diff --git a/plat/nvidia/tegra/include/t194/tegra_def.h b/plat/nvidia/tegra/include/t194/tegra_def.h new file mode 100644 index 0000000..8e7b28c --- /dev/null +++ b/plat/nvidia/tegra/include/t194/tegra_def.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __TEGRA_DEF_H__ +#define __TEGRA_DEF_H__ + +#include + +/******************************************************************************* + * These values are used by the PSCI implementation during the `CPU_SUSPEND` + * and `SYSTEM_SUSPEND` calls as the `state-id` field in the 'power state' + * parameter. + ******************************************************************************/ +#define PSTATE_ID_CORE_IDLE 6 +#define PSTATE_ID_CORE_POWERDN 7 +#define PSTATE_ID_SOC_POWERDN 2 + +/******************************************************************************* + * Platform power states (used by PSCI framework) + * + * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID + * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID + ******************************************************************************/ +#define PLAT_MAX_RET_STATE 1 +#define PLAT_MAX_OFF_STATE 8 + +/******************************************************************************* + * Implementation defined ACTLR_EL3 bit definitions + ******************************************************************************/ +#define ACTLR_EL3_L2ACTLR_BIT (1 << 6) +#define ACTLR_EL3_L2ECTLR_BIT (1 << 5) +#define ACTLR_EL3_L2CTLR_BIT (1 << 4) +#define ACTLR_EL3_CPUECTLR_BIT (1 << 1) +#define ACTLR_EL3_CPUACTLR_BIT (1 << 0) +#define ACTLR_EL3_ENABLE_ALL_ACCESS (ACTLR_EL3_L2ACTLR_BIT | \ + ACTLR_EL3_L2ECTLR_BIT | \ + ACTLR_EL3_L2CTLR_BIT | \ + ACTLR_EL3_CPUECTLR_BIT | \ + ACTLR_EL3_CPUACTLR_BIT) + +/******************************************************************************* + * Secure IRQ definitions + ******************************************************************************/ +#define TEGRA186_MAX_SEC_IRQS 5 +#define TEGRA186_BPMP_WDT_IRQ 46 +#define TEGRA186_SPE_WDT_IRQ 47 +#define TEGRA186_SCE_WDT_IRQ 48 +#define TEGRA186_TOP_WDT_IRQ 49 +#define TEGRA186_AON_WDT_IRQ 50 + +#define TEGRA186_SEC_IRQ_TARGET_MASK 0xFF /* 8 Carmel */ + +/******************************************************************************* + * Tegra Miscellanous register constants + ******************************************************************************/ +#define TEGRA_MISC_BASE 0x00100000 +#define HARDWARE_REVISION_OFFSET 0x4 + +#define MISCREG_PFCFG 0x200C + +/******************************************************************************* + * Tegra TSA Controller constants + ******************************************************************************/ +#define TEGRA_TSA_BASE 0x02000000 + +#define TSA_CONFIG_STATIC0_CSW_SESWR 0x1010 +#define TSA_CONFIG_STATIC0_CSW_SESWR_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_ETRW 0xD034 +#define TSA_CONFIG_STATIC0_CSW_ETRW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_SDMMCWAB 0x3020 +#define TSA_CONFIG_STATIC0_CSW_SDMMCWAB_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_AXISW 0x8008 +#define TSA_CONFIG_STATIC0_CSW_AXISW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_HDAW 0xD008 +#define TSA_CONFIG_STATIC0_CSW_HDAW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_AONDMAW 0xE018 +#define TSA_CONFIG_STATIC0_CSW_AONDMAW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_SCEDMAW 0x9008 +#define TSA_CONFIG_STATIC0_CSW_SCEDMAW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_BPMPDMAW 0x9028 +#define TSA_CONFIG_STATIC0_CSW_BPMPDMAW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_APEDMAW 0xB008 +#define TSA_CONFIG_STATIC0_CSW_APEDMAW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_UFSHCW 0x6008 +#define TSA_CONFIG_STATIC0_CSW_UFSHCW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_AFIW 0xF008 +#define TSA_CONFIG_STATIC0_CSW_AFIW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_SATAW 0x4008 +#define TSA_CONFIG_STATIC0_CSW_SATAW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_EQOSW 0x3038 +#define TSA_CONFIG_STATIC0_CSW_EQOSW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW 0x6018 +#define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW_RESET 0x1100 +#define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW 0x6028 +#define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW_RESET 0x1100 + +#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK (0x3 << 11) +#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU (0 << 11) + +/******************************************************************************* + * Tegra Memory Controller constants + ******************************************************************************/ +#define TEGRA_MC_STREAMID_BASE 0x02C00000 +#define TEGRA_MC_BASE 0x02C10000 + +/* TZDRAM carveout configuration registers */ +#define MC_SECURITY_CFG0_0 0x70 +#define MC_SECURITY_CFG1_0 0x74 +#define MC_SECURITY_CFG3_0 0x9BC + +/* Video Memory carveout configuration registers */ +#define MC_VIDEO_PROTECT_BASE_HI 0x978 +#define MC_VIDEO_PROTECT_BASE_LO 0x648 +#define MC_VIDEO_PROTECT_SIZE_MB 0x64c + +/* TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers */ +#define MC_TZRAM_BASE_LO 0x2194 +#define TZRAM_BASE_LO_SHIFT 12 +#define TZRAM_BASE_LO_MASK 0xFFFFF +#define MC_TZRAM_BASE_HI 0x2198 +#define TZRAM_BASE_HI_SHIFT 0 +#define TZRAM_BASE_HI_MASK 3 +#define MC_TZRAM_SIZE 0x219C +#define TZRAM_SIZE_RANGE_4KB_SHIFT 27 + +#define MC_TZRAM_CARVEOUT_CFG 0x2190 +#define TZRAM_LOCK_CFG_SETTINGS_BIT (1 << 1) +#define TZRAM_ENABLE_TZ_LOCK_BIT (1 << 0) +#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG0 0x21A0 +#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG1 0x21A4 +#define TZRAM_CARVEOUT_CPU_WRITE_ACCESS_BIT (1 << 25) +#define TZRAM_CARVEOUT_CPU_READ_ACCESS_BIT (1 << 7) +#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG2 0x21A8 +#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG3 0x21AC +#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG4 0x21B0 +#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG5 0x21B4 + +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS0 0x21C0 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS1 0x21C4 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS2 0x21C8 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS3 0x21CC +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS4 0x21D0 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS5 0x21D4 + +/* Memory Controller Reset Control registers */ +#define MC_CLIENT_HOTRESET_CTRL1_VIFAL_FLUSH_ENB (1 << 27) +#define MC_CLIENT_HOTRESET_CTRL1_DLAA_FLUSH_ENB (1 << 28) +#define MC_CLIENT_HOTRESET_CTRL1_DLA1A_FLUSH_ENB (1 << 29) +#define MC_CLIENT_HOTRESET_CTRL1_PVA0A_FLUSH_ENB (1 << 30) +#define MC_CLIENT_HOTRESET_CTRL1_PVA1A_FLUSH_ENB (1 << 31) + +/******************************************************************************* + * Tegra UART Controller constants + ******************************************************************************/ +#define TEGRA_UARTA_BASE 0x03100000 +#define TEGRA_UARTB_BASE 0x03110000 +#define TEGRA_UARTC_BASE 0x0C280000 +#define TEGRA_UARTD_BASE 0x03130000 +#define TEGRA_UARTE_BASE 0x03140000 +#define TEGRA_UARTF_BASE 0x03150000 +#define TEGRA_UARTG_BASE 0x0C290000 + +/******************************************************************************* + * Tegra Fuse Controller related constants + ******************************************************************************/ +#define TEGRA_FUSE_BASE 0x03820000 +#define OPT_SUBREVISION 0x248 +#define SUBREVISION_MASK 0xF + +/******************************************************************************* + * GICv2 & interrupt handling related constants + ******************************************************************************/ +#define TEGRA_GICD_BASE 0x03881000 +#define TEGRA_GICC_BASE 0x03882000 + +/******************************************************************************* + * Security Engine related constants + ******************************************************************************/ +#define TEGRA_SE0_BASE 0x03AC0000 +#define SE_MUTEX_WATCHDOG_NS_LIMIT 0x6C +#define TEGRA_PKA1_BASE 0x03AD0000 +#define PKA_MUTEX_WATCHDOG_NS_LIMIT 0x8144 +#define TEGRA_RNG1_BASE 0x03AE0000 +#define RNG_MUTEX_WATCHDOG_NS_LIMIT 0xFE0 + +/******************************************************************************* + * Tegra micro-seconds timer constants + ******************************************************************************/ +#define TEGRA_TMRUS_BASE 0x0C2E0000 + +/******************************************************************************* + * Tegra Power Mgmt Controller constants + ******************************************************************************/ +#define TEGRA_PMC_BASE 0x0C360000 + +/******************************************************************************* + * Tegra scratch registers constants + ******************************************************************************/ +#define TEGRA_SCRATCH_BASE 0x0C390000 +#define SECURE_SCRATCH_RSV1_LO 0x06C +#define SECURE_SCRATCH_RSV1_HI 0x070 +#define SECURE_SCRATCH_RSV6 0x094 +#define SECURE_SCRATCH_RSV11_LO 0x0BC +#define SECURE_SCRATCH_RSV11_HI 0x0C0 +#define SECURE_SCRATCH_RSV53_LO 0x20C +#define SECURE_SCRATCH_RSV53_HI 0x210 +#define SECURE_SCRATCH_RSV54_HI 0x218 +#define SECURE_SCRATCH_RSV55_LO 0x21C +#define SECURE_SCRATCH_RSV55_HI 0x220 + +/******************************************************************************* + * Tegra Memory Mapped Control Register Access Bus constants + ******************************************************************************/ +#define TEGRA_MMCRAB_BASE 0x0E000000 + +/******************************************************************************* + * Tegra SMMU Controller constants + ******************************************************************************/ +#define TEGRA_SMMU_BASE 0x10000000 + +/******************************************************************************* + * Tegra TZRAM constants + ******************************************************************************/ +#define TEGRA_TZRAM_BASE 0x40000000 +#define TEGRA_TZRAM_SIZE 0x40000 + +/******************************************************************************* + * Tegra Clock and Reset Controller constants + ******************************************************************************/ +#define TEGRA_CAR_RESET_BASE 0x200000000 + +#endif /* __TEGRA_DEF_H__ */ diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h new file mode 100644 index 0000000..4735404 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/include/mce_private.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __MCE_PRIVATE_H__ +#define __MCE_PRIVATE_H__ + +#include +#include + +/******************************************************************************* + * 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; + +/******************************************************************************* + * Uncore PERFMON ARI struct + ******************************************************************************/ +typedef union uncore_perfmon_req { + struct perfmon_command { + /* + * Commands: 0 = READ, 1 = WRITE + */ + uint64_t cmd:8; + /* + * The unit group: L2=0, L3=1, ROC=2, MC=3, IOB=4 + */ + uint64_t grp:4; + /* + * Unit selector: Selects the unit instance, with 0 = Unit + * = (number of units in group) - 1. + */ + uint64_t unit:4; + /* + * Selects the uncore perfmon register to access + */ + uint64_t reg:8; + /* + * Counter number. Selects which counter to use for + * registers NV_PMEVCNTR and NV_PMEVTYPER. + */ + uint64_t counter:8; + } perfmon_command; + struct perfmon_status { + /* + * Resulting command status + */ + uint64_t val:8; + uint64_t unused:24; + } perfmon_status; + uint64_t data; +} uncore_perfmon_req_t; + +#define UNCORE_PERFMON_CMD_READ 0 +#define UNCORE_PERFMON_CMD_WRITE 1 + +#define UNCORE_PERFMON_CMD_MASK 0xFF +#define UNCORE_PERFMON_UNIT_GRP_MASK 0xF +#define UNCORE_PERFMON_SELECTOR_MASK 0xF +#define UNCORE_PERFMON_REG_MASK 0xFF +#define UNCORE_PERFMON_CTR_MASK 0xFF +#define UNCORE_PERFMON_RESP_STATUS_MASK 0xFF + +/* declarations for NVG handler functions */ +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_PRIVATE_H__ */ diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S b/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S new file mode 100644 index 0000000..e6a6a99 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/mce/aarch64/nvg_helpers.S @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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 + 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/t194/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c new file mode 100644 index 0000000..3a2e262 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/mce/mce.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************************* + * Common handler for all MCE commands + ******************************************************************************/ +int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, + uint64_t arg2) +{ + uint64_t ret64 = 0, arg3, arg4, arg5; + int ret = 0; + mca_cmd_t mca_cmd; + uncore_perfmon_req_t req; + cpu_context_t *ctx = cm_get_context(NON_SECURE); + gp_regs_t *gp_regs = get_gpregs_ctx(ctx); + + assert(ctx); + assert(gp_regs); + + switch (cmd) { + case MCE_CMD_ENTER_CSTATE: + /* NVG */ + 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); + + /* NVG */ + + write_ctx_reg(gp_regs, CTX_GPREG_X4, arg3); + write_ctx_reg(gp_regs, CTX_GPREG_X5, arg4); + write_ctx_reg(gp_regs, CTX_GPREG_X6, arg5); + + break; + + case MCE_CMD_UPDATE_CROSSOVER_TIME: + /* NVG */ + + break; + + case MCE_CMD_READ_CSTATE_STATS: + /* NVG */ + + /* 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: + /* NVG */ + + break; + + case MCE_CMD_IS_CCX_ALLOWED: + /* NVG */ + + /* update context to return CCx status value */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, ret); + + break; + + case MCE_CMD_IS_SC7_ALLOWED: + /* NVG */ + + /* 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); + + break; + + case MCE_CMD_ONLINE_CORE: + /* NVG */ + + break; + + case MCE_CMD_CC3_CTRL: + /* NVG */ + + break; + + case MCE_CMD_ECHO_DATA: + /* issue NVG to echo data */ + + /* 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: + /* get the MCE firmware version */ + + /* + * 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: + break; + + case MCE_CMD_ROC_FLUSH_CACHE_TRBITS: + /* NVG */ + + break; + + case MCE_CMD_ROC_FLUSH_CACHE: + /* NVG */ + + break; + + case MCE_CMD_ROC_CLEAN_CACHE: + /* NVG */ + + break; + + case MCE_CMD_ENUM_READ_MCA: + memcpy(&mca_cmd, &arg0, sizeof(arg0)); + + /* NVG */ + + /* 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)); + + /* NVG */ + + /* 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; + + case MCE_CMD_ENABLE_LATIC: + /* + * This call is not for production use. The constant value, + * 0xFFFF0000, is specific to allowing for enabling LATIC on + * pre-production parts for the chip verification harness. + * + * Enabling LATIC allows S/W to read the MINI ISPs in the + * CCPLEX. The ISMs are used for various measurements relevant + * to particular locations in the Silicon. They are small + * counters which can be polled to determine how fast a + * particular location in the Silicon is. + */ + /* NVG */ + + break; + + case MCE_CMD_UNCORE_PERFMON_REQ: + memcpy(&req, &arg0, sizeof(arg0)); + /* NVG */ + + /* update context to return data */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, arg1); + break; + + case MCE_CMD_MISC_CCPLEX: + /* NVG */ + + break; + + default: + ERROR("unknown MCE command (%lld)\n", cmd); + return EINVAL; + } + + return ret; +} + +/******************************************************************************* + * Handler to update the reset vector for CPUs + ******************************************************************************/ +int mce_update_reset_vector(void) +{ + return 0; +} + +static int mce_update_ccplex_gsc(/* GSC ID */) +{ + return 0; +} + +/******************************************************************************* + * Handler to update carveout values for Video Memory Carveout region + ******************************************************************************/ +int mce_update_gsc_videomem(void) +{ + return mce_update_ccplex_gsc(); +} + +/******************************************************************************* + * Handler to update carveout values for TZDRAM aperture + ******************************************************************************/ +int mce_update_gsc_tzdram(void) +{ + return mce_update_ccplex_gsc(); +} + +/******************************************************************************* + * Handler to update carveout values for TZ SysRAM aperture + ******************************************************************************/ +int mce_update_gsc_tzram(void) +{ + return mce_update_ccplex_gsc(); +} + +/******************************************************************************* + * Handler to shutdown/reset the entire system + ******************************************************************************/ +__dead2 void mce_enter_ccplex_state(uint32_t state_idx) +{ + /* sanity check state value */ + + /* enter ccplex power state */ + + /* wait till the CCPLEX powers down */ + for (;;) + ; + + panic(); +} + +/******************************************************************************* + * Handler to issue the UPDATE_CSTATE_INFO request + ******************************************************************************/ +void mce_update_cstate_info(mce_cstate_info_t *cstate) +{ + /* issue the UPDATE_CSTATE_INFO request */ + /* NVG */ +} + +/******************************************************************************* + * Handler to read the MCE firmware version and check if it is compatible + * with interface header the BL3-1 was compiled against + ******************************************************************************/ +void mce_verify_firmware_version(void) +{ + uint64_t version; + uint32_t major, minor; + + /* + * MCE firmware is not running on simulation platforms. + */ + if (tegra_platform_is_linsim() || tegra_platform_is_virt_dev_kit()) + return; + + /* get a pointer to the CPU's arch_mce_ops_t struct */ + + /* + * Read the MCE firmware version and extract the major and minor + * version fields + */ + version = 0; + major = (uint32_t)version; + minor = (uint32_t)(version >> 32); + + INFO("MCE Version - HW=%d:%d, SW=%d:%d\n", major, minor, + 0, 0); + + /* + * Verify that the MCE firmware version and the interface header + * match + */ + if (major != 0) { + ERROR("MCE major version mismatch\n"); + panic(); + } + + if (minor < 0) { + ERROR("MCE minor version mismatch\n"); + panic(); + } +} diff --git a/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c new file mode 100644 index 0000000..36b3aab --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/mce/nvg.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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/t194/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c new file mode 100644 index 0000000..fb33c13 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void prepare_core_pwr_dwn(void); + +#if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM +extern void tegra186_cpu_reset_handler(void); +extern uint32_t __tegra186_cpu_reset_handler_data, + __tegra186_cpu_reset_handler_end; + +/* TZDRAM offset for saving SMMU context */ +#define TEGRA186_SMMU_CTX_OFFSET 16 +#endif + +/* state id mask */ +#define TEGRA186_STATE_ID_MASK 0xF +/* constants to get power state's wake time */ +#define TEGRA186_WAKE_TIME_MASK 0x0FFFFFF0 +#define TEGRA186_WAKE_TIME_SHIFT 4 +/* default core wake mask for CPU_SUSPEND */ +#define TEGRA186_CORE_WAKE_MASK 0x180c +/* context size to save during system suspend */ +#define TEGRA186_SE_CONTEXT_SIZE 3 + +static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE]; +static struct t18x_psci_percpu_data { + unsigned int wake_time; +} __aligned(CACHE_WRITEBACK_GRANULE) percpu_data[PLATFORM_CORE_COUNT]; + +int32_t tegra_soc_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + int state_id = psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK; + int cpu = plat_my_core_pos(); + + /* save the core wake time (in TSC ticks)*/ + percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK) + << TEGRA186_WAKE_TIME_SHIFT; + + /* + * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that + * the correct value is read in tegra_soc_pwr_domain_suspend(), which + * is called with caches disabled. It is possible to read a stale value + * from DRAM in that function, because the L2 cache is not flushed + * unless the cluster is entering CC6/CC7. + */ + clean_dcache_range((uint64_t)&percpu_data[cpu], + sizeof(percpu_data[cpu])); + + /* Sanity check the requested state id */ + switch (state_id) { + case PSTATE_ID_CORE_IDLE: + case PSTATE_ID_CORE_POWERDN: + + /* Core powerdown request */ + req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id; + req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id; + + break; + + default: + ERROR("%s: unsupported state id (%d)\n", __func__, state_id); + return PSCI_E_INVALID_PARAMS; + } + + return PSCI_E_SUCCESS; +} + +int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + const plat_local_state_t *pwr_domain_state; + unsigned int stateid_afflvl0, stateid_afflvl2; +#if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM + plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint64_t smmu_ctx_base; +#endif + uint32_t val; + + /* get the state ID */ + pwr_domain_state = target_state->pwr_domain_state; + stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] & + TEGRA186_STATE_ID_MASK; + stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & + TEGRA186_STATE_ID_MASK; + + if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) || + (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) { + + /* Enter CPU idle/powerdown */ + + } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + + /* save SE registers */ + se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + + SE_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE + + RNG_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE + + PKA_MUTEX_WATCHDOG_NS_LIMIT); + + /* save 'Secure Boot' Processor Feature Config Register */ + val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG); + mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV6, val); + +#if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM + /* save SMMU context */ + smmu_ctx_base = params_from_bl2->tzdram_base + + ((uintptr_t)&__tegra186_cpu_reset_handler_data - + (uintptr_t)tegra186_cpu_reset_handler) + + TEGRA186_SMMU_CTX_OFFSET; + tegra_smmu_save_context((uintptr_t)smmu_ctx_base); +#else + tegra_smmu_save_context(0); +#endif + + /* Instruct the MCE to enter system suspend state */ + } + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Platform handler to calculate the proper target power level at the + * specified affinity level + ******************************************************************************/ +plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl, + const plat_local_state_t *states, + unsigned int ncpu) +{ + plat_local_state_t target = *states; + int cluster_powerdn = 1; + int core_pos = read_mpidr() & MPIDR_CPU_MASK; + + /* get the current core's power state */ + target = *(states + core_pos); + + /* CPU suspend */ + if (lvl == MPIDR_AFFLVL1 && target == PSTATE_ID_CORE_POWERDN) { + + /* Program default wake mask */ + + /* Check if CCx state is allowed. */ + } + + /* CPU off */ + if (lvl == MPIDR_AFFLVL1 && target == PLAT_MAX_OFF_STATE) { + + /* find out the number of ON cpus in the cluster */ + do { + target = *states++; + if (target != PLAT_MAX_OFF_STATE) + cluster_powerdn = 0; + } while (--ncpu); + + /* Enable cluster powerdn from last CPU in the cluster */ + if (cluster_powerdn) { + + /* Enable CC7 state and turn off wake mask */ + + } else { + + /* Turn off wake_mask */ + } + } + + /* System Suspend */ + if ((lvl == MPIDR_AFFLVL2) || (target == PSTATE_ID_SOC_POWERDN)) + return PSTATE_ID_SOC_POWERDN; + + /* default state */ + return PSCI_LOCAL_STATE_RUN; +} + +#if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM +int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) +{ + const plat_local_state_t *pwr_domain_state = + target_state->pwr_domain_state; + plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & + TEGRA186_STATE_ID_MASK; + uint32_t val; + + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + /* + * The TZRAM loses power when we enter system suspend. To + * allow graceful exit from system suspend, we need to copy + * BL3-1 over to TZDRAM. + */ + val = params_from_bl2->tzdram_base + + ((uintptr_t)&__tegra186_cpu_reset_handler_end - + (uintptr_t)tegra186_cpu_reset_handler); + memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE, + (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE); + } + + return PSCI_E_SUCCESS; +} +#endif + +int tegra_soc_pwr_domain_on(u_register_t mpidr) +{ + int target_cpu = mpidr & MPIDR_CPU_MASK; + int target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >> + MPIDR_AFFINITY_BITS; + + if (target_cluster > MPIDR_AFFLVL1) { + ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr); + return PSCI_E_NOT_PRESENT; + } + + /* construct the target CPU # */ + target_cpu |= (target_cluster << 2); + + mce_command_handler(MCE_CMD_ONLINE_CORE, target_cpu, 0, 0); + + return PSCI_E_SUCCESS; +} + +int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + int stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; + + /* + * Reset power state info for CPUs when onlining, we set + * deepest power when offlining a core but that may not be + * requested by non-secure sw which controls idle states. It + * will re-init this info from non-secure software when the + * core come online. + */ + + /* + * Check if we are exiting from deep sleep and restore SE + * context if we are. + */ + if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + + mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[0]); + mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[1]); + mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[2]); + + /* Init SMMU */ + + /* + * Reset power state info for the last core doing SC7 + * entry and exit, we set deepest power state as CC7 + * and SC7 for SC7 entry which may not be requested by + * non-secure SW which controls idle states. + */ + } + + return PSCI_E_SUCCESS; +} + +int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) +{ + int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + + /* Disable Denver's DCO operations */ + if (impl == DENVER_IMPL) + denver_disable_dco(); + + /* Turn off CPU */ + + return PSCI_E_SUCCESS; +} + +__dead2 void tegra_soc_prepare_system_off(void) +{ + /* System power off */ + + /* SC8 */ + + wfi(); + + /* wait for the system to power down */ + for (;;) { + ; + } +} + +int tegra_soc_prepare_system_reset(void) +{ + return PSCI_E_SUCCESS; +} diff --git a/plat/nvidia/tegra/soc/t194/plat_secondary.c b/plat/nvidia/tegra/soc/t194/plat_secondary.c new file mode 100644 index 0000000..33c8e1b --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_secondary.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MISCREG_CPU_RESET_VECTOR 0x2000 +#define MISCREG_AA64_RST_LOW 0x2004 +#define MISCREG_AA64_RST_HIGH 0x2008 + +#define CPU_RESET_MODE_AA64 1 + +extern void tegra_secure_entrypoint(void); + +#if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM +extern void tegra186_cpu_reset_handler(void); +extern uint64_t __tegra186_smmu_ctx_start; +#endif + +/******************************************************************************* + * Setup secondary CPU vectors + ******************************************************************************/ +void plat_secondary_setup(void) +{ + uint32_t addr_low, addr_high; +#if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM + plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + uint64_t cpu_reset_handler_base = params_from_bl2->tzdram_base; +#else + uint64_t cpu_reset_handler_base = (uintptr_t)tegra_secure_entrypoint; +#endif + + INFO("Setting up secondary CPU boot\n"); + +#if ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM + memcpy((void *)((uintptr_t)cpu_reset_handler_base), + (void *)(uintptr_t)tegra186_cpu_reset_handler, + (uintptr_t)&__tegra186_smmu_ctx_start - + (uintptr_t)tegra186_cpu_reset_handler); +#endif + + addr_low = (uint32_t)cpu_reset_handler_base | CPU_RESET_MODE_AA64; + addr_high = (uint32_t)((cpu_reset_handler_base >> 32) & 0x7ff); + + /* write lower 32 bits first, then the upper 11 bits */ + mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW, addr_low); + mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH, addr_high); + + /* save reset vector to be used during SYSTEM_SUSPEND exit */ + mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV1_LO, + addr_low); + mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV1_HI, + addr_high); + + /* update reset vector address to the CCPLEX */ + mce_update_reset_vector(); +} diff --git a/plat/nvidia/tegra/soc/t194/plat_setup.c b/plat/nvidia/tegra/soc/t194/plat_setup.c new file mode 100644 index 0000000..aab884e --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_setup.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DEFINE_RENAME_SYSREG_RW_FUNCS(l2ctlr_el1, L2CTLR_EL1) +extern uint64_t tegra_enable_l2_ecc_parity_prot; + +/******************************************************************************* + * The Tegra power domain tree has a single system level power domain i.e. a + * single root node. The first entry in the power domain descriptor specifies + * the number of power domains at the highest power level. + ******************************************************************************* + */ +const unsigned char tegra_power_domain_tree_desc[] = { + /* No of root nodes */ + 1, + /* No of clusters */ + PLATFORM_CLUSTER_COUNT, + /* No of CPU cores - cluster0 */ + PLATFORM_MAX_CPUS_PER_CLUSTER, + /* No of CPU cores - cluster1 */ + PLATFORM_MAX_CPUS_PER_CLUSTER +}; + +/* + * Table of regions to map using the MMU. + */ +static const mmap_region_t tegra_mmap[] = { + MAP_REGION_FLAT(TEGRA_MISC_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_TSA_BASE, 0x20000, /* 128KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_MC_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000, /* 128KB - UART A, B*/ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000, /* 128KB - UART C, G */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000, /* 192KB - UART D, E, F */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_FUSE_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x20000, /* 128KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_PMC_BASE, 0x40000, /* 256KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x10000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_MMCRAB_BASE, 0x60000, /* 384KB */ + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(TEGRA_SMMU_BASE, 0x1000000, /* 64KB */ + MT_DEVICE | MT_RW | MT_SECURE), + {0} +}; + +/******************************************************************************* + * Set up the pagetables as per the platform memory map & initialize the MMU + ******************************************************************************/ +const mmap_region_t *plat_get_mmio_map(void) +{ + /* MMIO space */ + return tegra_mmap; +} + +/******************************************************************************* + * Handler to get the System Counter Frequency + ******************************************************************************/ +unsigned int plat_get_syscnt_freq2(void) +{ + return 31250000; +} + +/******************************************************************************* + * Maximum supported UART controllers + ******************************************************************************/ +#define TEGRA186_MAX_UART_PORTS 7 + +/******************************************************************************* + * This variable holds the UART port base addresses + ******************************************************************************/ +static uint32_t tegra186_uart_addresses[TEGRA186_MAX_UART_PORTS + 1] = { + 0, /* undefined - treated as an error case */ + TEGRA_UARTA_BASE, + TEGRA_UARTB_BASE, + TEGRA_UARTC_BASE, + TEGRA_UARTD_BASE, + TEGRA_UARTE_BASE, + TEGRA_UARTF_BASE, + TEGRA_UARTG_BASE, +}; + +/******************************************************************************* + * Retrieve the UART controller base to be used as the console + ******************************************************************************/ +uint32_t plat_get_console_from_id(int id) +{ + if (id > TEGRA186_MAX_UART_PORTS) + return 0; + + return tegra186_uart_addresses[id]; +} + +/* represent chip-version as concatenation of major (15:12), minor (11:8) and subrev (7:0) */ +#define TEGRA186_VER_A02P 0x1201 + +/******************************************************************************* + * Handler for early platform setup + ******************************************************************************/ +void plat_early_platform_setup(void) +{ + int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; + uint32_t chip_subrev, val; + + /* sanity check MCE firmware compatibility */ + mce_verify_firmware_version(); + + /* + * Enable ECC and Parity Protection for Cortex-A57 CPUs + * for Tegra A02p SKUs + */ + if (impl != DENVER_IMPL) { + + /* get the major, minor and sub-version values */ + chip_subrev = mmio_read_32(TEGRA_FUSE_BASE + OPT_SUBREVISION) & + SUBREVISION_MASK; + + /* prepare chip version number */ + val = (tegra_get_chipid_major() << 12) | + (tegra_get_chipid_minor() << 8) | + chip_subrev; + + /* enable L2 ECC for Tegra186 A02P and beyond */ + if (val >= TEGRA186_VER_A02P) { + + val = read_l2ctlr_el1(); + val |= L2_ECC_PARITY_PROTECTION_BIT; + write_l2ctlr_el1(val); + + /* + * Set the flag to enable ECC/Parity Protection + * when we exit System Suspend or Cluster Powerdn + */ + tegra_enable_l2_ecc_parity_prot = 1; + } + } +} + +/* Secure IRQs for Tegra186 */ +static const irq_sec_cfg_t tegra186_sec_irqs[] = { + [0] = { + TEGRA186_BPMP_WDT_IRQ, + TEGRA186_SEC_IRQ_TARGET_MASK, + INTR_TYPE_EL3, + }, + [1] = { + TEGRA186_BPMP_WDT_IRQ, + TEGRA186_SEC_IRQ_TARGET_MASK, + INTR_TYPE_EL3, + }, + [2] = { + TEGRA186_SPE_WDT_IRQ, + TEGRA186_SEC_IRQ_TARGET_MASK, + INTR_TYPE_EL3, + }, + [3] = { + TEGRA186_SCE_WDT_IRQ, + TEGRA186_SEC_IRQ_TARGET_MASK, + INTR_TYPE_EL3, + }, + [4] = { + TEGRA186_TOP_WDT_IRQ, + TEGRA186_SEC_IRQ_TARGET_MASK, + INTR_TYPE_EL3, + }, + [5] = { + TEGRA186_AON_WDT_IRQ, + TEGRA186_SEC_IRQ_TARGET_MASK, + INTR_TYPE_EL3, + }, +}; + +/******************************************************************************* + * Initialize the GIC and SGIs + ******************************************************************************/ +void plat_gic_setup(void) +{ + tegra_gic_setup(tegra186_sec_irqs, + sizeof(tegra186_sec_irqs) / sizeof(tegra186_sec_irqs[0])); + + /* + * Initialize the FIQ handler only if the platform supports any + * FIQ interrupt sources. + */ + if (sizeof(tegra186_sec_irqs) > 0) + tegra_fiq_handler_setup(); +} + +/******************************************************************************* + * Return pointer to the BL31 params from previous bootloader + ******************************************************************************/ +struct tegra_bl31_params *plat_get_bl31_params(void) +{ + uint32_t val; + + val = mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV53_LO); + + return (struct tegra_bl31_params *)(uintptr_t)val; +} + +/******************************************************************************* + * Return pointer to the BL31 platform params from previous bootloader + ******************************************************************************/ +plat_params_from_bl2_t *plat_get_bl31_plat_params(void) +{ + uint32_t val; + + val = mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV53_HI); + + return (plat_params_from_bl2_t *)(uintptr_t)val; +} diff --git a/plat/nvidia/tegra/soc/t194/plat_sip_calls.c b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c new file mode 100644 index 0000000..12b4b77 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern uint32_t tegra186_system_powerdn_state; + +/******************************************************************************* + * Tegra186 SiP SMCs + ******************************************************************************/ +#define TEGRA_SIP_NEW_VIDEOMEM_REGION 0x82000003 +#define TEGRA_SIP_SYSTEM_SHUTDOWN_STATE 0x82FFFE01 +#define TEGRA_SIP_MCE_CMD_ENTER_CSTATE 0x82FFFF00 +#define TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO 0x82FFFF01 +#define TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME 0x82FFFF02 +#define TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS 0x82FFFF03 +#define TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS 0x82FFFF04 +#define TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED 0x82FFFF05 +#define TEGRA_SIP_MCE_CMD_ONLINE_CORE 0x82FFFF06 +#define TEGRA_SIP_MCE_CMD_CC3_CTRL 0x82FFFF07 +#define TEGRA_SIP_MCE_CMD_ECHO_DATA 0x82FFFF08 +#define TEGRA_SIP_MCE_CMD_READ_VERSIONS 0x82FFFF09 +#define TEGRA_SIP_MCE_CMD_ENUM_FEATURES 0x82FFFF0A +#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS 0x82FFFF0B +#define TEGRA_SIP_MCE_CMD_ENUM_READ_MCA 0x82FFFF0C +#define TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA 0x82FFFF0D +#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE 0x82FFFF0E +#define TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE 0x82FFFF0F +#define TEGRA_SIP_MCE_CMD_ENABLE_LATIC 0x82FFFF10 +#define TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ 0x82FFFF11 +#define TEGRA_SIP_MCE_CMD_MISC_CCPLEX 0x82FFFF12 + +/******************************************************************************* + * This function is responsible for handling all T186 SiP calls + ******************************************************************************/ +int plat_sip_handler(uint32_t smc_fid, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + int mce_ret; + + switch (smc_fid) { + + /* + * Micro Coded Engine (MCE) commands reside in the 0x82FFFF00 - + * 0x82FFFFFF SiP SMC space + */ + case TEGRA_SIP_MCE_CMD_ENTER_CSTATE: + case TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO: + case TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME: + case TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS: + case TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS: + case TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED: + case TEGRA_SIP_MCE_CMD_CC3_CTRL: + case TEGRA_SIP_MCE_CMD_ECHO_DATA: + case TEGRA_SIP_MCE_CMD_READ_VERSIONS: + case TEGRA_SIP_MCE_CMD_ENUM_FEATURES: + case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS: + case TEGRA_SIP_MCE_CMD_ENUM_READ_MCA: + case TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA: + case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE: + case TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE: + case TEGRA_SIP_MCE_CMD_ENABLE_LATIC: + case TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ: + case TEGRA_SIP_MCE_CMD_MISC_CCPLEX: + + /* clean up the high bits */ + smc_fid &= MCE_CMD_MASK; + + /* execute the command and store the result */ + mce_ret = mce_command_handler(smc_fid, x1, x2, x3); + write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X0, mce_ret); + + return 0; + + case TEGRA_SIP_SYSTEM_SHUTDOWN_STATE: + + /* clean up the high bits */ + x1 = (uint32_t)x1; + + /* + * SC8 is a special Tegra186 system state where the CPUs and + * DRAM are powered down but the other subsystem is still + * alive. + */ + + return 0; + + default: + break; + } + + return -ENOTSUP; +} diff --git a/plat/nvidia/tegra/soc/t194/plat_trampoline.S b/plat/nvidia/tegra/soc/t194/plat_trampoline.S new file mode 100644 index 0000000..cf76507 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/plat_trampoline.S @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#define TEGRA186_SMMU_CTX_SIZE 0x420 + + .align 4 + .globl tegra186_cpu_reset_handler + +/* CPU reset handler routine */ +func tegra186_cpu_reset_handler + /* + * The TZRAM loses state during System Suspend. We use this + * information to decide if the reset handler is running after a + * System Suspend. Resume from system suspend requires restoring + * the entire state from TZDRAM to TZRAM. + */ + mov x0, #BL31_BASE + ldr x0, [x0] + cbnz x0, boot_cpu + + /* resume from system suspend */ + mov x0, #BL31_BASE + adr x1, __tegra186_cpu_reset_handler_end + adr x2, __tegra186_cpu_reset_handler_data + ldr x2, [x2, #8] + + /* memcpy16 */ +m_loop16: + cmp x2, #16 + b.lt m_loop1 + ldp x3, x4, [x1], #16 + stp x3, x4, [x0], #16 + sub x2, x2, #16 + b m_loop16 + /* copy byte per byte */ +m_loop1: + cbz x2, boot_cpu + ldrb w3, [x1], #1 + strb w3, [x0], #1 + subs x2, x2, #1 + b.ne m_loop1 + +boot_cpu: + adr x0, __tegra186_cpu_reset_handler_data + ldr x0, [x0] + br x0 +endfunc tegra186_cpu_reset_handler + + /* + * Tegra186 reset data (offset 0x0 - 0x430) + * + * 0x000: secure world's entrypoint + * 0x008: BL31 size (RO + RW) + * 0x00C: SMMU context start + * 0x42C: SMMU context end + */ + + .align 4 + .type __tegra186_cpu_reset_handler_data, %object + .globl __tegra186_cpu_reset_handler_data +__tegra186_cpu_reset_handler_data: + .quad tegra_secure_entrypoint + .quad __BL31_END__ - BL31_BASE + .globl __tegra186_smmu_ctx_start +__tegra186_smmu_ctx_start: + .rept TEGRA186_SMMU_CTX_SIZE + .quad 0 + .endr + .size __tegra186_cpu_reset_handler_data, \ + . - __tegra186_cpu_reset_handler_data + + .align 4 + .globl __tegra186_cpu_reset_handler_end +__tegra186_cpu_reset_handler_end: diff --git a/plat/nvidia/tegra/soc/t194/platform_t194.mk b/plat/nvidia/tegra/soc/t194/platform_t194.mk new file mode 100644 index 0000000..54bc941 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/platform_t194.mk @@ -0,0 +1,62 @@ +# +# Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# platform configs +ENABLE_AFI_DEVICE := 0 +$(eval $(call add_define,ENABLE_AFI_DEVICE)) + +ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS := 0 +$(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS)) + +ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM := 1 +$(eval $(call add_define,ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM)) + +RELOCATE_TO_BL31_BASE := 1 +$(eval $(call add_define,RELOCATE_TO_BL31_BASE)) + +ENABLE_CHIP_VERIFICATION_HARNESS := 0 +$(eval $(call add_define,ENABLE_CHIP_VERIFICATION_HARNESS)) + +ENABLE_SMMU_DEVICE := 0 +$(eval $(call add_define,ENABLE_SMMU_DEVICE)) + +RESET_TO_BL31 := 1 + +PROGRAMMABLE_RESET_ADDRESS := 1 + +COLD_BOOT_SINGLE_CPU := 1 + +# platform settings +TZDRAM_BASE := 0x40000000 +$(eval $(call add_define,TZDRAM_BASE)) + +PLATFORM_CLUSTER_COUNT := 2 +$(eval $(call add_define,PLATFORM_CLUSTER_COUNT)) + +PLATFORM_MAX_CPUS_PER_CLUSTER := 4 +$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER)) + +MAX_XLAT_TABLES := 24 +$(eval $(call add_define,MAX_XLAT_TABLES)) + +MAX_MMAP_REGIONS := 24 +$(eval $(call add_define,MAX_MMAP_REGIONS)) + +# platform files +PLAT_INCLUDES += -I${SOC_DIR}/drivers/include + +BL31_SOURCES += lib/cpus/aarch64/denver.S \ + ${COMMON_DIR}/drivers/memctrl/memctrl_v2.c \ + ${COMMON_DIR}/drivers/smmu/smmu.c \ + ${SOC_DIR}/drivers/mce/mce.c \ + ${SOC_DIR}/plat_psci_handlers.c \ + ${SOC_DIR}/plat_setup.c \ + ${SOC_DIR}/plat_secondary.c \ + ${SOC_DIR}/plat_sip_calls.c + +ifeq (${ENABLE_SYSTEM_SUSPEND_CTX_SAVE_TZDRAM}, 1) +BL31_SOURCES += ${SOC_DIR}/plat_trampoline.S +endif