From 87a1df73619e9031c970ea5e0813a3040cc80992 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Thu, 23 Mar 2017 17:32:20 -0700 Subject: [PATCH 01/14] Tegra186: mce: add the mce_update_cstate_info() helper function This patch adds a helper function to the MCE driver to allow its clients to issue UPDATE_CSTATE_INFO requests, without having to setup the CPU context struct. We introduced a struct to encapsulate the request parameters, that clients can pass on to the MCE driver. The MCE driver gets the parameters from the struct and programs the hardware accordingly. Change-Id: I02bce57506c4ccd90da82127805d6b564375cbf1 Signed-off-by: Varun Wadekar --- .../tegra/soc/t186/drivers/include/mce.h | 19 +++++++++++++++++++ plat/nvidia/tegra/soc/t186/drivers/mce/mce.c | 13 +++++++++++++ 2 files changed, 32 insertions(+) diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/mce.h b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h index 606569236..38ca32c37 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/include/mce.h +++ b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h @@ -101,6 +101,24 @@ typedef enum mce_cmd { #define MCE_CMD_MASK 0xFF +/******************************************************************************* + * Struct to prepare UPDATE_CSTATE_INFO request + ******************************************************************************/ +typedef struct mce_cstate_info { + /* cluster cstate value */ + uint32_t cluster; + /* ccplex cstate value */ + uint32_t ccplex; + /* system cstate value */ + uint32_t system; + /* force system state? */ + uint8_t system_state_force; + /* wake mask value */ + uint32_t wake_mask; + /* update the wake mask? */ + uint8_t update_wake_mask; +} mce_cstate_info_t; + /******************************************************************************* * Macros to prepare CSTATE info request ******************************************************************************/ @@ -322,6 +340,7 @@ 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); +void mce_update_cstate_info(mce_cstate_info_t *cstate); void mce_verify_firmware_version(void); /* declarations for ARI/NVG handler functions */ diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c index 9d0d71fd6..1a712dcca 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c @@ -448,6 +448,19 @@ __dead2 void mce_enter_ccplex_state(uint32_t state_idx) panic(); } +/******************************************************************************* + * Handler to issue the UPDATE_CSTATE_INFO request + ******************************************************************************/ +void mce_update_cstate_info(mce_cstate_info_t *cstate) +{ + arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); + + /* issue the UPDATE_CSTATE_INFO request */ + ops->update_cstate_info(mce_get_curr_cpu_ari_base(), cstate->cluster, + cstate->ccplex, cstate->system, cstate->system_state_force, + cstate->wake_mask, cstate->update_wake_mask); +} + /******************************************************************************* * Handler to read the MCE firmware version and check if it is compatible * with interface header the BL3-1 was compiled against From f3a20c32242f0369e4538622c0d2205c739d7059 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Sat, 9 Apr 2016 00:36:42 -0700 Subject: [PATCH 02/14] Tegra186: implement `get_target_pwr_state` handler This patch implements the `get_target_pwr_state` handler for Tegra186 SoCs. The SoC port uses this handler to find out the cluster/system state during CPU_SUSPEND, CPU_OFF and SYSTEM_SUSPEND calls. The MCE firmware controls the power state of the CPU/CLuster/System, so we query it to get the state and act accordingly. Change-Id: I86633d8d79aec7dcb405d2301ac69910f93110fe Signed-off-by: Varun Wadekar --- .../tegra/soc/t186/plat_psci_handlers.c | 201 ++++++++++-------- 1 file changed, 117 insertions(+), 84 deletions(-) diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c index 835527001..358287870 100644 --- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -71,12 +72,9 @@ 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 = read_mpidr() & MPIDR_CPU_MASK; - int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; - - if (impl == DENVER_IMPL) - cpu |= 0x4; + int cpu = plat_my_core_pos(); + /* save the core wake time (us) */ wake_time[cpu] = (power_state >> TEGRA186_WAKE_TIME_SHIFT) & TEGRA186_WAKE_TIME_MASK; @@ -84,10 +82,10 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state, switch (state_id) { case PSTATE_ID_CORE_IDLE: case PSTATE_ID_CORE_POWERDN: - /* - * Core powerdown request only for afflvl 0 - */ + + /* Core powerdown request */ req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id; + req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id; break; @@ -103,20 +101,12 @@ 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; - int cpu = read_mpidr() & MPIDR_CPU_MASK; - int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; - cpu_context_t *ctx = cm_get_context(NON_SECURE); - gp_regs_t *gp_regs = get_gpregs_ctx(ctx); + int cpu = plat_my_core_pos(); plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + mce_cstate_info_t cstate_info = { 0 }; uint64_t smmu_ctx_base; uint32_t val; - assert(ctx); - assert(gp_regs); - - if (impl == DENVER_IMPL) - cpu |= 0x4; - /* get the state ID */ pwr_domain_state = target_state->pwr_domain_state; stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] & @@ -124,29 +114,14 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & TEGRA186_STATE_ID_MASK; - if (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) { + if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) || + (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) { - /* Program default wake mask */ - write_ctx_reg(gp_regs, CTX_GPREG_X4, 0); - write_ctx_reg(gp_regs, CTX_GPREG_X5, TEGRA186_CORE_WAKE_MASK); - write_ctx_reg(gp_regs, CTX_GPREG_X6, 1); - (void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, 0, 0, 0); - - /* Prepare for cpu idle */ - (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, - TEGRA_ARI_CORE_C6, wake_time[cpu], 0); - - } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) { - - /* Program default wake mask */ - write_ctx_reg(gp_regs, CTX_GPREG_X4, 0); - write_ctx_reg(gp_regs, CTX_GPREG_X5, TEGRA186_CORE_WAKE_MASK); - write_ctx_reg(gp_regs, CTX_GPREG_X6, 1); - (void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, 0, 0, 0); - - /* Prepare for cpu powerdn */ - (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, - TEGRA_ARI_CORE_C7, wake_time[cpu], 0); + /* Enter CPU idle/powerdown */ + val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ? + TEGRA_ARI_CORE_C6 : TEGRA_ARI_CORE_C7; + (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, val, + wake_time[cpu], 0); } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { @@ -170,11 +145,11 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) tegra_smmu_save_context((uintptr_t)smmu_ctx_base); /* Prepare for system suspend */ - write_ctx_reg(gp_regs, CTX_GPREG_X4, 1); - write_ctx_reg(gp_regs, CTX_GPREG_X5, 0); - write_ctx_reg(gp_regs, CTX_GPREG_X6, 1); - (void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, - TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC7); + cstate_info.cluster = TEGRA_ARI_CLUSTER_CC7; + cstate_info.system = TEGRA_ARI_SYSTEM_SC7; + cstate_info.system_state_force = 1; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); /* Loop until system suspend is allowed */ do { @@ -187,15 +162,84 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) /* Instruct the MCE to enter system suspend state */ (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0); - - } else { - ERROR("%s: Unknown state id\n", __func__); - return PSCI_E_NOT_SUPPORTED; } 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 cpu = plat_my_core_pos(), ret, cluster_powerdn = 1; + int core_pos = read_mpidr() & MPIDR_CPU_MASK; + mce_cstate_info_t cstate_info = { 0 }; + + /* 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 */ + cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + + /* Check if CCx state is allowed. */ + ret = mce_command_handler(MCE_CMD_IS_CCX_ALLOWED, + TEGRA_ARI_CORE_C7, wake_time[cpu], 0); + if (ret) + return PSTATE_ID_CORE_POWERDN; + } + + /* 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 */ + cstate_info.cluster = TEGRA_ARI_CLUSTER_CC7; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + + /* Check if CCx state is allowed. */ + ret = mce_command_handler(MCE_CMD_IS_CCX_ALLOWED, + TEGRA_ARI_CORE_C7, + MCE_CORE_SLEEP_TIME_INFINITE, + 0); + if (ret) + return PSTATE_ID_CORE_POWERDN; + + } else { + + /* Turn off wake_mask */ + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); + } + } + + /* System Suspend */ + if ((lvl == MPIDR_AFFLVL2) || (target == PSTATE_ID_SOC_POWERDN)) + return PSTATE_ID_SOC_POWERDN; + + /* default state */ + return PSCI_LOCAL_STATE_RUN; +} + int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) { const plat_local_state_t *pwr_domain_state = @@ -244,8 +288,7 @@ 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]; int stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0]; - cpu_context_t *ctx = cm_get_context(NON_SECURE); - gp_regs_t *gp_regs = get_gpregs_ctx(ctx); + mce_cstate_info_t cstate_info = { 0 }; /* * Reset power state info for CPUs when onlining, we set @@ -256,11 +299,9 @@ int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) */ if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) { - 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, 1); - mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, - TEGRA_ARI_CLUSTER_CC1, 0, 0); + cstate_info.cluster = TEGRA_ARI_CLUSTER_CC1; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); } /* @@ -280,15 +321,15 @@ int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) tegra_smmu_init(); /* - * Reset power state info for the last core doing SC7 entry and exit, - * we set deepest power state as CC7 and SC7 for SC7 entry which - * may not be requested by non-secure SW which controls idle states. + * 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. */ - 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, 1); - (void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, - TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC1); + cstate_info.cluster = TEGRA_ARI_CLUSTER_CC7; + cstate_info.system = TEGRA_ARI_SYSTEM_SC1; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); } return PSCI_E_SUCCESS; @@ -296,33 +337,22 @@ int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { - cpu_context_t *ctx = cm_get_context(NON_SECURE); - gp_regs_t *gp_regs = get_gpregs_ctx(ctx); int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; - assert(ctx); - assert(gp_regs); - - /* Turn off wake_mask */ - 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, 1); - mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, TEGRA_ARI_CLUSTER_CC7, - 0, 0); - /* Disable Denver's DCO operations */ if (impl == DENVER_IMPL) denver_disable_dco(); /* Turn off CPU */ - return mce_command_handler(MCE_CMD_ENTER_CSTATE, TEGRA_ARI_CORE_C7, + (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0); + + return PSCI_E_SUCCESS; } __dead2 void tegra_soc_prepare_system_off(void) { - cpu_context_t *ctx = cm_get_context(NON_SECURE); - gp_regs_t *gp_regs = get_gpregs_ctx(ctx); + mce_cstate_info_t cstate_info = { 0 }; uint32_t val; if (tegra186_system_powerdn_state == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) { @@ -333,11 +363,11 @@ __dead2 void tegra_soc_prepare_system_off(void) } else if (tegra186_system_powerdn_state == TEGRA_ARI_SYSTEM_SC8) { /* Prepare for quasi power down */ - write_ctx_reg(gp_regs, CTX_GPREG_X4, 1); - write_ctx_reg(gp_regs, CTX_GPREG_X5, 0); - write_ctx_reg(gp_regs, CTX_GPREG_X6, 1); - (void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO, - TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC8); + cstate_info.cluster = TEGRA_ARI_CLUSTER_CC7; + cstate_info.system = TEGRA_ARI_SYSTEM_SC8; + cstate_info.system_state_force = 1; + cstate_info.update_wake_mask = 1; + mce_update_cstate_info(&cstate_info); /* loop until other CPUs power down */ do { @@ -357,6 +387,9 @@ __dead2 void tegra_soc_prepare_system_off(void) /* power down core */ prepare_cpu_pwr_dwn(); + /* flush L1/L2 data caches */ + dcsw_op_all(DCCISW); + } else { ERROR("%s: unsupported power down state (%d)\n", __func__, tegra186_system_powerdn_state); From c11e0ddfbff1475c581cfb2babc27d3e48984c74 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Fri, 29 Apr 2016 10:40:02 -0700 Subject: [PATCH 03/14] Tegra186: mce: Uncore Perfmon ARI Programming Uncore perfmon appears to the CPU as a set of uncore perfmon registers which can be read and written using the ARI interface. The MCE code sequence handles reads and writes to these registers by manipulating the underlying T186 uncore hardware. To access an uncore perfmon register, CPU software writes the ARI request registers to specify * whether the operation is a read or a write, * which uncore perfmon register to access, * the uncore perfmon unit, group, and counter number (if necessary), * the data to write (if the operation is a write). It then initiates an ARI request to run the uncore perfmon sequence in the MCE and reads the resulting value of the uncore perfmon register and any status information from the ARI response registers. The NS world's MCE driver issues MCE_CMD_UNCORE_PERFMON_REQ command for the EL3 layer to start the entire sequence. Once the request completes, the NS world would receive the command status in the X0 register and the command data in the X1 register. Change-Id: I20bf2eca2385f7c8baa81e9445617ae711ecceea Signed-off-by: Varun Wadekar --- .../tegra/soc/t186/drivers/include/mce.h | 57 +++++++++++++++++++ plat/nvidia/tegra/soc/t186/drivers/mce/ari.c | 38 +++++++++++++ plat/nvidia/tegra/soc/t186/drivers/mce/mce.c | 16 +++++- plat/nvidia/tegra/soc/t186/plat_sip_calls.c | 2 + 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/mce.h b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h index 38ca32c37..66e212bff 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/include/mce.h +++ b/plat/nvidia/tegra/soc/t186/drivers/include/mce.h @@ -95,6 +95,7 @@ typedef enum mce_cmd { MCE_CMD_ROC_FLUSH_CACHE, MCE_CMD_ROC_CLEAN_CACHE, MCE_CMD_ENABLE_LATIC, + MCE_CMD_UNCORE_PERFMON_REQ, MCE_CMD_IS_CCX_ALLOWED = 0xFE, MCE_CMD_MAX = 0xFF, } mce_cmd_t; @@ -201,6 +202,54 @@ typedef union mca_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 + /******************************************************************************* * Structure populated by arch specific code to export routines which perform * common low level MCE functions @@ -331,6 +380,12 @@ typedef struct arch_mce_ops { * reset the entire system */ void (*enter_ccplex_state)(uint32_t ari_base, uint32_t state_idx); + /* + * This ARI request reads/writes data from/to Uncore PERFMON + * registers + */ + int (*read_write_uncore_perfmon)(uint32_t ari_base, + uncore_perfmon_req_t req, uint64_t *data); } arch_mce_ops_t; int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, @@ -363,6 +418,8 @@ 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 ari_read_write_uncore_perfmon(uint32_t ari_base, + uncore_perfmon_req_t req, uint64_t *data); 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, diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c index 147a358ae..e11d16000 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c @@ -389,3 +389,41 @@ void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx) */ (void)ari_request_wait(ari_base, 0, TEGRA_ARI_MISC_CCPLEX, state_idx, 0); } + +int ari_read_write_uncore_perfmon(uint32_t ari_base, + uncore_perfmon_req_t req, uint64_t *data) +{ + int ret; + uint32_t val; + + /* sanity check input parameters */ + if (req.perfmon_command.cmd == UNCORE_PERFMON_CMD_READ && !data) { + ERROR("invalid parameters\n"); + return EINVAL; + } + + /* + * For "write" commands get the value that has to be written + * to the uncore perfmon registers + */ + val = (req.perfmon_command.cmd == UNCORE_PERFMON_CMD_WRITE) ? + *data : 0; + + ret = ari_request_wait(ari_base, 0, TEGRA_ARI_PERFMON, val, req.data); + if (ret) + return ret; + + /* read the command status value */ + req.perfmon_status.val = ari_get_response_high(ari_base) & + UNCORE_PERFMON_RESP_STATUS_MASK; + + /* + * For "read" commands get the data from the uncore + * perfmon registers + */ + if ((req.perfmon_status.val == 0) && (req.perfmon_command.cmd == + UNCORE_PERFMON_CMD_READ)) + *data = ari_get_response_low(ari_base); + + return (int)req.perfmon_status.val; +} diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c index 1a712dcca..981545d3f 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c @@ -61,7 +61,8 @@ static arch_mce_ops_t nvg_mce_ops = { .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 + .enter_ccplex_state = ari_enter_ccplex_state, + .read_write_uncore_perfmon = ari_read_write_uncore_perfmon }; /* ARI functions handlers */ @@ -82,7 +83,8 @@ static arch_mce_ops_t ari_mce_ops = { .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 + .enter_ccplex_state = ari_enter_ccplex_state, + .read_write_uncore_perfmon = ari_read_write_uncore_perfmon }; typedef struct mce_config { @@ -173,6 +175,7 @@ int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, 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); @@ -374,6 +377,15 @@ int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, break; #endif + + case MCE_CMD_UNCORE_PERFMON_REQ: + memcpy(&req, &arg0, sizeof(arg0)); + ret = ops->read_write_uncore_perfmon(cpu_ari_base, req, &arg1); + + /* update context to return data */ + write_ctx_reg(gp_regs, CTX_GPREG_X1, arg1); + break; + default: ERROR("unknown MCE command (%d)\n", cmd); return EINVAL; diff --git a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c index c7a2c4167..9f48ddd90 100644 --- a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c +++ b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c @@ -65,6 +65,7 @@ extern uint32_t tegra186_system_powerdn_state; #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 /******************************************************************************* * This function is responsible for handling all T186 SiP calls @@ -102,6 +103,7 @@ int plat_sip_handler(uint32_t smc_fid, 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: /* clean up the high bits */ smc_fid &= MCE_CMD_MASK; From 1eed3838b37113d11dafd072a25ec8cd8871330b Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Wed, 18 May 2016 13:39:16 -0700 Subject: [PATCH 04/14] Tegra186: Enable ECC and Parity Protection for A02p SKUs This patch enables ECC and Parity Protection for Cortex-A57 CPUs during boot, for Tegra186 A02p SKUs. Change-Id: I8522a6cb61f5e4fa9e0471f558a0c3ee8078370e Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/include/t186/tegra_def.h | 7 +++ plat/nvidia/tegra/soc/t186/plat_setup.c | 63 +++++++++++++++++++--- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h index 7f85351eb..f0bd5d57a 100644 --- a/plat/nvidia/tegra/include/t186/tegra_def.h +++ b/plat/nvidia/tegra/include/t186/tegra_def.h @@ -105,6 +105,13 @@ #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 0xFF + /******************************************************************************* * GICv2 & interrupt handling related constants ******************************************************************************/ diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c index 49f45892f..1dd0d6ee7 100644 --- a/plat/nvidia/tegra/soc/t186/plat_setup.c +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,9 @@ #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 @@ -74,6 +78,8 @@ static const mmap_region_t tegra_mmap[] = { MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000, /* 128KB */ 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 */ @@ -142,6 +148,55 @@ uint32_t plat_get_console_from_id(int id) 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_minor, chip_major, 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_major = (mmio_read_32(TEGRA_MISC_BASE + + HARDWARE_REVISION_OFFSET) >> + MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK; + chip_minor = (mmio_read_32(TEGRA_MISC_BASE + + HARDWARE_REVISION_OFFSET) >> + MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK; + chip_subrev = mmio_read_32(TEGRA_FUSE_BASE + OPT_SUBREVISION) & + SUBREVISION_MASK; + + /* prepare chip version number */ + val = (chip_major << 12) | (chip_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[] = { { @@ -171,11 +226,3 @@ void plat_gic_setup(void) if (sizeof(tegra186_sec_irqs) > 0) tegra_fiq_handler_setup(); } - -/******************************************************************************* - * Handler for early platform setup - ******************************************************************************/ -void plat_early_platform_setup(void) -{ - mce_verify_firmware_version(); -} From 512da21af1524d56a617de2b42dbe5b356b26506 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Fri, 29 Apr 2016 16:21:36 -0700 Subject: [PATCH 05/14] Tegra186: modify the return type for `plat_get_syscnt_freq()` Commit c073fda1c692d7c74415d26fb483d6336330fcc0 upstream changed the return type for `plat_get_syscnt_freq()` from uint64_t to unsigned long long. This patch modifies the return type for the Tegra186 platform. Change-Id: Ic9e5c364b90972265576e271582a4347e5eaa6eb Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/soc/t186/plat_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c index 1dd0d6ee7..ac36a14b9 100644 --- a/plat/nvidia/tegra/soc/t186/plat_setup.c +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -113,7 +113,7 @@ const mmap_region_t *plat_get_mmio_map(void) /******************************************************************************* * Handler to get the System Counter Frequency ******************************************************************************/ -unsigned int plat_get_syscnt_freq2(void) +unsigned long long plat_get_syscnt_freq(void) { return 31250000; } From 2f583f8e6d6f337d2f1b757bba1f6d5d16660947 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Wed, 25 May 2016 16:35:04 -0700 Subject: [PATCH 06/14] Tegra: memctrl_v2: TZRAM aperture configuration settings This patch enables the configuration settings for the TZRAM aperture by programming the base/size of the aperture and restricting access to it. We allow only the CPU to read/write by programming the access configuration registers to 0. Change-Id: Ie16ad29f4c5ec7aafa972b0a0230b4790ad5619e Signed-off-by: Varun Wadekar --- .../tegra/common/drivers/memctrl/memctrl_v2.c | 56 +++++++++++++------ .../nvidia/tegra/include/drivers/memctrl_v2.h | 38 ++++++++++--- plat/nvidia/tegra/include/t186/tegra_def.h | 2 +- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c index a03b6ef74..6f1d69475 100644 --- a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c +++ b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c @@ -641,33 +641,55 @@ void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes) */ void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes) { - uint64_t tzram_end = phys_base + size_in_bytes - 1; + uint32_t index; + uint32_t total_128kb_blocks = size_in_bytes >> 17; + uint32_t residual_4kb_blocks = (size_in_bytes & 0x1FFFF) >> 12; uint32_t val; /* - * Check if the TZRAM is locked already. + * Reset the access configuration registers to restrict access + * to the TZRAM aperture */ - if (tegra_mc_read_32(MC_TZRAM_REG_CTRL) == DISABLE_TZRAM_ACCESS) - return; + for (index = MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG0; + index <= MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS5; + index += 4) + tegra_mc_write_32(index, 0); /* - * Setup the Memory controller to allow only secure accesses to - * the TZRAM carveout + * Allow CPU read/write access to the aperture */ - INFO("Configuring TrustZone RAM (SysRAM) Memory Carveout\n"); + tegra_mc_write_32(MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG1, + TZRAM_CARVEOUT_CPU_WRITE_ACCESS_BIT | + TZRAM_CARVEOUT_CPU_READ_ACCESS_BIT); - /* Program the base and end values */ - tegra_mc_write_32(MC_TZRAM_BASE, (uint32_t)phys_base); - tegra_mc_write_32(MC_TZRAM_END, (uint32_t)tzram_end); + /* + * Set the TZRAM base. TZRAM base must be 4k aligned, at least. + */ + assert(!(phys_base & 0xFFF)); + tegra_mc_write_32(MC_TZRAM_BASE_LO, (uint32_t)phys_base); + tegra_mc_write_32(MC_TZRAM_BASE_HI, + (uint32_t)(phys_base >> 32) & TZRAM_BASE_HI_MASK); - /* Extract the high address bits from the base/end values */ - val = (uint32_t)(phys_base >> 32) & TZRAM_ADDR_HI_BITS_MASK; - val |= (((uint32_t)(tzram_end >> 32) & TZRAM_ADDR_HI_BITS_MASK) << - TZRAM_END_HI_BITS_SHIFT); - tegra_mc_write_32(MC_TZRAM_HI_ADDR_BITS, val); + /* + * Set the TZRAM size + * + * total size = (number of 128KB blocks) + (number of remaining 4KB + * blocks) + * + */ + val = (residual_4kb_blocks << TZRAM_SIZE_RANGE_4KB_SHIFT) | + total_128kb_blocks; + tegra_mc_write_32(MC_TZRAM_SIZE, val); - /* Disable further writes to the TZRAM setup registers */ - tegra_mc_write_32(MC_TZRAM_REG_CTRL, DISABLE_TZRAM_ACCESS); + /* + * Lock the configuration settings by disabling TZ-only lock + * and locking the configuration against any future changes + * at all. + */ + val = tegra_mc_read_32(MC_TZRAM_CARVEOUT_CFG); + val &= ~TZRAM_ENABLE_TZ_LOCK_BIT; + val |= TZRAM_LOCK_CFG_SETTINGS_BIT; + tegra_mc_write_32(MC_TZRAM_CARVEOUT_CFG, val); /* * MCE propogates the security configuration values across the diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v2.h b/plat/nvidia/tegra/include/drivers/memctrl_v2.h index a7ab6503c..e1abe1434 100644 --- a/plat/nvidia/tegra/include/drivers/memctrl_v2.h +++ b/plat/nvidia/tegra/include/drivers/memctrl_v2.h @@ -350,7 +350,7 @@ typedef struct mc_streamid_security_cfg { .override_enable = OVERRIDE_ ## access \ } -#endif /* __ASSMEBLY__ */ +#endif /* __ASSEMBLY__ */ /******************************************************************************* * TZDRAM carveout configuration registers @@ -367,15 +367,35 @@ typedef struct mc_streamid_security_cfg { #define MC_VIDEO_PROTECT_SIZE_MB 0x64c /******************************************************************************* - * TZRAM carveout configuration registers + * TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers ******************************************************************************/ -#define MC_TZRAM_BASE 0x1850 -#define MC_TZRAM_END 0x1854 -#define MC_TZRAM_HI_ADDR_BITS 0x1588 - #define TZRAM_ADDR_HI_BITS_MASK 0x3 - #define TZRAM_END_HI_BITS_SHIFT 8 -#define MC_TZRAM_REG_CTRL 0x185c - #define DISABLE_TZRAM_ACCESS 1 +#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 0x21B8 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS1 0x21BC +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS2 0x21C0 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS3 0x21C4 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS4 0x21C8 +#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS5 0x21CC /******************************************************************************* * Memory Controller Reset Control registers diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h index f0bd5d57a..277b479e0 100644 --- a/plat/nvidia/tegra/include/t186/tegra_def.h +++ b/plat/nvidia/tegra/include/t186/tegra_def.h @@ -165,6 +165,6 @@ * Tegra TZRAM constants ******************************************************************************/ #define TEGRA_TZRAM_BASE 0x30000000 -#define TEGRA_TZRAM_SIZE 0x50000 +#define TEGRA_TZRAM_SIZE 0x40000 #endif /* __TEGRA_DEF_H__ */ From 962014f535034cf4b875ebb17aa209a5dcb090b3 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Wed, 1 Jun 2016 12:48:13 -0700 Subject: [PATCH 07/14] Tegra186: delete 'Video Memory Carveout' handling This patch removes duplicate code from the platform's SiP handler routine for processing Video Memory Carveout region requests and uses the common SiP handler instead. Change-Id: Ib307de017fd88d5ed3c816288327cae750a67806 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/soc/t186/plat_sip_calls.c | 26 --------------------- 1 file changed, 26 deletions(-) diff --git a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c index 9f48ddd90..8e3371845 100644 --- a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c +++ b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c @@ -114,32 +114,6 @@ int plat_sip_handler(uint32_t smc_fid, return 0; - case TEGRA_SIP_NEW_VIDEOMEM_REGION: - /* clean up the high bits */ - x1 = (uint32_t)x1; - x2 = (uint32_t)x2; - - /* - * Check if Video Memory overlaps TZDRAM (contains bl31/bl32) - * or falls outside of the valid DRAM range - */ - mce_ret = bl31_check_ns_address(x1, x2); - if (mce_ret) - return -ENOTSUP; - - /* - * Check if Video Memory is aligned to 1MB. - */ - if ((x1 & 0xFFFFF) || (x2 & 0xFFFFF)) { - ERROR("Unaligned Video Memory base address!\n"); - return -ENOTSUP; - } - - /* new video memory carveout settings */ - tegra_memctrl_videomem_setup(x1, x2); - - return 0; - case TEGRA_SIP_SYSTEM_SHUTDOWN_STATE: /* clean up the high bits */ From 48afb167b3a06b15da11241496b7ff09af755f85 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 23 May 2016 11:47:34 -0700 Subject: [PATCH 08/14] Tegra186: handlers to get BL31 arguments from previous bootloader This patch overrides the default handlers to get BL31 arguments from the previous bootloader. The previous bootloader stores the pointer to the arguments in PMC secure scratch register #53. BL31 is the first component running on the CPU, as there isn't a previous bootloader. We set the RESET_TO_BL31 flag to enable the path which assumes that there are no input parameters passed by the previous bootloader. Change-Id: Idacc1df292a70c9c1cb4d5c3a774bd796175d5e8 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/include/t186/tegra_def.h | 2 ++ plat/nvidia/tegra/soc/t186/plat_setup.c | 25 +++++++++++++++++++++ plat/nvidia/tegra/soc/t186/platform_t186.mk | 9 ++++++++ 3 files changed, 36 insertions(+) diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h index 277b479e0..9a5d8a511 100644 --- a/plat/nvidia/tegra/include/t186/tegra_def.h +++ b/plat/nvidia/tegra/include/t186/tegra_def.h @@ -150,6 +150,8 @@ #define SECURE_SCRATCH_RSV6 0x680 #define SECURE_SCRATCH_RSV11_LO 0x6A8 #define SECURE_SCRATCH_RSV11_HI 0x6AC +#define SECURE_SCRATCH_RSV53_LO 0x7F8 +#define SECURE_SCRATCH_RSV53_HI 0x7FC /******************************************************************************* * Tegra Memory Mapped Control Register Access Bus constants diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c index ac36a14b9..261eeb084 100644 --- a/plat/nvidia/tegra/soc/t186/plat_setup.c +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -226,3 +227,27 @@ void plat_gic_setup(void) if (sizeof(tegra186_sec_irqs) > 0) tegra_fiq_handler_setup(); } + +/******************************************************************************* + * Return pointer to the BL31 params from previous bootloader + ******************************************************************************/ +bl31_params_t *plat_get_bl31_params(void) +{ + uint32_t val; + + val = mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV53_LO); + + return (bl31_params_t *)(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/t186/platform_t186.mk b/plat/nvidia/tegra/soc/t186/platform_t186.mk index 4a4d9bbda..b62d47da0 100644 --- a/plat/nvidia/tegra/soc/t186/platform_t186.mk +++ b/plat/nvidia/tegra/soc/t186/platform_t186.mk @@ -32,9 +32,18 @@ ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS := 1 $(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS)) +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)) +RESET_TO_BL31 := 1 + +PROGRAMMABLE_RESET_ADDRESS := 1 + +COLD_BOOT_SINGLE_CPU := 1 + # platform settings TZDRAM_BASE := 0x30000000 $(eval $(call add_define,TZDRAM_BASE)) From 698f4250288c2ee4dc016bb653d255f2c61d5ccb Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Wed, 20 Apr 2016 17:14:15 -0700 Subject: [PATCH 09/14] Tegra: smmu: disable TCU prefetch for all the 64 contexts This patch disables TCU prefetch for all the contexts in order to improve SMMU performance. Change-Id: I82ca49a0e396d9f064f5c62a5f00c4b2101d8459 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/include/drivers/smmu.h | 7 +++++ .../nvidia/tegra/soc/t186/drivers/smmu/smmu.c | 31 +++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/plat/nvidia/tegra/include/drivers/smmu.h b/plat/nvidia/tegra/include/drivers/smmu.h index 0867c11ad..0640846af 100644 --- a/plat/nvidia/tegra/include/drivers/smmu.h +++ b/plat/nvidia/tegra/include/drivers/smmu.h @@ -599,9 +599,16 @@ * SMMU Global Secure Aux. Configuration Register ******************************************************************************/ #define SMMU_GSR0_SECURE_ACR 0x10 +#define SMMU_GNSR_ACR (SMMU_GSR0_SECURE_ACR + 0x400) #define SMMU_GSR0_PGSIZE_SHIFT 16 #define SMMU_GSR0_PGSIZE_4K (0 << SMMU_GSR0_PGSIZE_SHIFT) #define SMMU_GSR0_PGSIZE_64K (1 << SMMU_GSR0_PGSIZE_SHIFT) +#define SMMU_ACR_CACHE_LOCK_ENABLE_BIT (1 << 26) + +/******************************************************************************* + * SMMU Global Aux. Control Register + ******************************************************************************/ +#define SMMU_CBn_ACTLR_CPRE_BIT (1 << 1) /******************************************************************************* * SMMU configuration constants diff --git a/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c b/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c index d1e1804e1..bca6f2ec3 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c +++ b/plat/nvidia/tegra/soc/t186/drivers/smmu/smmu.c @@ -465,15 +465,42 @@ void tegra_smmu_save_context(uint64_t smmu_ctx_addr) (uint32_t)(smmu_ctx_addr >> 32)); } +#define SMMU_NUM_CONTEXTS 64 +#define SMMU_CONTEXT_BANK_MAX_IDX 64 + /* * Init SMMU during boot or "System Suspend" exit */ void tegra_smmu_init(void) { - uint32_t val; + uint32_t val, i, ctx_base; - /* Program the SMMU pagesize */ + /* Program the SMMU pagesize and reset CACHE_LOCK bit */ val = tegra_smmu_read_32(SMMU_GSR0_SECURE_ACR); val |= SMMU_GSR0_PGSIZE_64K; + val &= ~SMMU_ACR_CACHE_LOCK_ENABLE_BIT; + tegra_smmu_write_32(SMMU_GSR0_SECURE_ACR, val); + + /* reset CACHE LOCK bit for NS Aux. Config. Register */ + val = tegra_smmu_read_32(SMMU_GNSR_ACR); + val &= ~SMMU_ACR_CACHE_LOCK_ENABLE_BIT; + tegra_smmu_write_32(SMMU_GNSR_ACR, val); + + /* disable TCU prefetch for all contexts */ + ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS) + SMMU_CBn_ACTLR; + for (i = 0; i < SMMU_CONTEXT_BANK_MAX_IDX; i++) { + val = tegra_smmu_read_32(ctx_base + (SMMU_GSR0_PGSIZE_64K * i)); + val &= ~SMMU_CBn_ACTLR_CPRE_BIT; + tegra_smmu_write_32(ctx_base + (SMMU_GSR0_PGSIZE_64K * i), val); + } + + /* set CACHE LOCK bit for NS Aux. Config. Register */ + val = tegra_smmu_read_32(SMMU_GNSR_ACR); + val |= SMMU_ACR_CACHE_LOCK_ENABLE_BIT; + tegra_smmu_write_32(SMMU_GNSR_ACR, val); + + /* set CACHE LOCK bit for S Aux. Config. Register */ + val = tegra_smmu_read_32(SMMU_GSR0_SECURE_ACR); + val |= SMMU_ACR_CACHE_LOCK_ENABLE_BIT; tegra_smmu_write_32(SMMU_GSR0_SECURE_ACR, val); } From 9c2a3d8ab7f98dba0d13b552a33df9d9cae0ef6c Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Thu, 2 Jun 2016 14:26:13 -0700 Subject: [PATCH 10/14] Tegra186: implement plat_get_syscnt_freq2() Commit f3d3b316f82faa88e42f3d09c97cd9e52ac92599 replaced plat_get_syscnt_freq by plat_get_syscnt_freq2 on all the upstream platforms. This patch modifies the Tegra186 code which is not present usptream, yet. Change-Id: Ieda6168050a7769680a3a94513637fed03463a2d Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/soc/t186/plat_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c index 261eeb084..7b39e8244 100644 --- a/plat/nvidia/tegra/soc/t186/plat_setup.c +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -114,7 +114,7 @@ const mmap_region_t *plat_get_mmio_map(void) /******************************************************************************* * Handler to get the System Counter Frequency ******************************************************************************/ -unsigned long long plat_get_syscnt_freq(void) +unsigned int plat_get_syscnt_freq2(void) { return 31250000; } From 49cbbc4ea5bc317c8a29312e426f42eed8fb1d10 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Tue, 12 Jul 2016 10:04:28 -0700 Subject: [PATCH 11/14] Tegra186: memmap all UART controllers This patch adds all the UART controllers to the memory map. Change-Id: I035e55ca7bff0a96115102f2295981f9e3a5da6b Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/soc/t186/plat_setup.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c index 7b39e8244..16b20f5e5 100644 --- a/plat/nvidia/tegra/soc/t186/plat_setup.c +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -77,7 +77,11 @@ static const mmap_region_t tegra_mmap[] = { 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 */ + 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), From 2b04f9278706225431698723c28464192ae4c0cd Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Tue, 19 Jul 2016 11:29:40 -0700 Subject: [PATCH 12/14] Tegra186: use helper functions to get major/minor version This patch uses helper functions to read the chips's major and minor version values. Change-Id: I5b2530a31af5ab3778a8aa63380def4e9f9ee6ec Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/include/t186/tegra_def.h | 4 ---- plat/nvidia/tegra/soc/t186/plat_setup.c | 13 +++++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h index 9a5d8a511..e0eddfd34 100644 --- a/plat/nvidia/tegra/include/t186/tegra_def.h +++ b/plat/nvidia/tegra/include/t186/tegra_def.h @@ -76,10 +76,6 @@ ******************************************************************************/ #define TEGRA_MISC_BASE 0x00100000 #define HARDWARE_REVISION_OFFSET 0x4 -#define MAJOR_VERSION_SHIFT 0x4 -#define MAJOR_VERSION_MASK 0xF -#define MINOR_VERSION_SHIFT 0x10 -#define MINOR_VERSION_MASK 0xF #define MISCREG_PFCFG 0x200C diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c index 16b20f5e5..e848eabb7 100644 --- a/plat/nvidia/tegra/soc/t186/plat_setup.c +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -162,7 +163,7 @@ uint32_t plat_get_console_from_id(int id) void plat_early_platform_setup(void) { int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; - uint32_t chip_minor, chip_major, chip_subrev, val; + uint32_t chip_subrev, val; /* sanity check MCE firmware compatibility */ mce_verify_firmware_version(); @@ -174,17 +175,13 @@ void plat_early_platform_setup(void) if (impl != DENVER_IMPL) { /* get the major, minor and sub-version values */ - chip_major = (mmio_read_32(TEGRA_MISC_BASE + - HARDWARE_REVISION_OFFSET) >> - MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK; - chip_minor = (mmio_read_32(TEGRA_MISC_BASE + - HARDWARE_REVISION_OFFSET) >> - MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK; chip_subrev = mmio_read_32(TEGRA_FUSE_BASE + OPT_SUBREVISION) & SUBREVISION_MASK; /* prepare chip version number */ - val = (chip_major << 12) | (chip_minor << 8) | chip_subrev; + 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) { From 524bd09097d3d04ccfb3e1281a3105782bcf0d66 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 18 Jul 2016 17:42:02 -0700 Subject: [PATCH 13/14] Tegra186: mce: read MCE's firmware version on "real" platforms This patch runs the MCE firmware's version check only if the underlying platform has the capability to the run the firmware. MCE firmware is not running on simulation platforms, identified by v0.3 or v0.6, read from the Tegra Chip ID value. Change-Id: I3b1788b1ee2a0d4464017bb879ac5792cb7022b8 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/soc/t186/drivers/mce/mce.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c index 981545d3f..f87dfa4d3 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c @@ -42,6 +42,7 @@ #include #include #include +#include /* NVG functions handlers */ static arch_mce_ops_t nvg_mce_ops = { @@ -482,7 +483,13 @@ void mce_verify_firmware_version(void) arch_mce_ops_t *ops; uint32_t cpu_ari_base; uint64_t version; - uint32_t major, minor, chip_minor, chip_major; + uint32_t major, minor; + + /* + * MCE firmware is not running on simulation platforms. + */ + if (tegra_platform_is_emulation()) + return; /* get a pointer to the CPU's arch_mce_ops_t struct */ ops = mce_get_curr_cpu_ops(); @@ -501,17 +508,6 @@ void mce_verify_firmware_version(void) INFO("MCE Version - HW=%d:%d, SW=%d:%d\n", major, minor, TEGRA_ARI_VERSION_MAJOR, TEGRA_ARI_VERSION_MINOR); - /* - * MCE firmware is not running on simulation platforms. Simulation - * platforms are identified by v0.3 from the Tegra Chip ID value. - */ - chip_major = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >> - MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK; - chip_minor = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >> - MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK; - if ((chip_major == 0) && (chip_minor == 3)) - return; - /* * Verify that the MCE firmware version and the interface header * match From c61cd63802ff98d39719a2c68742c35484fb3ada Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 18 Jul 2016 17:43:41 -0700 Subject: [PATCH 14/14] Tegra: memctrl_v2: get chip revision using platform identifiers This patch switches to the functions which identify the underlying platform in order to calculate the chip SKU. Change-Id: I20cf5623465289ccfab28d6578efcf762bfeb456 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c index 6f1d69475..bd16b9916 100644 --- a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c +++ b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #define TEGRA_GPU_RESET_REG_OFFSET 0x30 @@ -495,7 +496,6 @@ void tegra_memctrl_setup(void) uint32_t num_overrides = sizeof(streamid_overrides) / sizeof(uint32_t); uint32_t num_sec_cfgs = sizeof(sec_cfgs) / sizeof(mc_streamid_security_cfg_t); uint32_t num_txn_overrides = sizeof(mc_override_cfgs) / sizeof(mc_txn_override_cfg_t); - uint32_t chip_minor, chip_major; int i; INFO("Tegra Memory Controller (v2)\n"); @@ -543,12 +543,8 @@ void tegra_memctrl_setup(void) /* * Set the MC_TXN_OVERRIDE registers for write clients. */ - chip_major = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >> - MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK; - chip_minor = (mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET) >> - MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK; - - if ((chip_major == 0) || (chip_major > 0 && chip_minor == 1)) { + if (!tegra_platform_is_silicon() || + (tegra_platform_is_silicon() && tegra_get_chipid_minor() == 1)) { /* GPU and NVENC settings for rev. A01 */ val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR);