diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h index 0732993d9..f3fbb891e 100644 --- a/plat/nvidia/tegra/include/t186/tegra_def.h +++ b/plat/nvidia/tegra/include/t186/tegra_def.h @@ -81,6 +81,7 @@ #define HARDWARE_MINOR_REVISION_MASK 0xf0000 #define HARDWARE_MINOR_REVISION_SHIFT 0x10 #define HARDWARE_REVISION_A01 1 +#define MISCREG_PFCFG 0x200C /******************************************************************************* * Tegra Memory Controller constants @@ -105,6 +106,16 @@ #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 Clock and Reset Controller constants ******************************************************************************/ @@ -124,6 +135,9 @@ * Tegra scratch registers constants ******************************************************************************/ #define TEGRA_SCRATCH_BASE 0x0C390000 +#define SECURE_SCRATCH_RSV6 0x680 +#define SECURE_SCRATCH_RSV11_LO 0x6A8 +#define SECURE_SCRATCH_RSV11_HI 0x6AC /******************************************************************************* * Tegra Memory Mapped Control Register Access Bus constants diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c index 981510708..745b6f4e5 100644 --- a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c +++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c @@ -262,7 +262,6 @@ int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, /* update context to return SC7 status value */ write_ctx_reg(gp_regs, CTX_GPREG_X1, ret); write_ctx_reg(gp_regs, CTX_GPREG_X3, ret); - ret = 0; break; diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c index 20c0f4c12..7e35cc6b2 100644 --- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,10 @@ extern void prepare_cpu_pwr_dwn(void); /* constants to get power state's wake time */ #define TEGRA186_WAKE_TIME_MASK 0xFFFFFF #define TEGRA186_WAKE_TIME_SHIFT 4 +/* context size to save during system suspend */ +#define TEGRA186_SE_CONTEXT_SIZE 3 +static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE]; static unsigned int wake_time[PLATFORM_CORE_COUNT]; /* System power down state */ @@ -89,9 +93,15 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state, 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; + 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); + uint32_t val; + + assert(ctx); + assert(gp_regs); if (impl == DENVER_IMPL) cpu |= 0x4; @@ -100,6 +110,8 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) 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) { @@ -113,6 +125,42 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) (void)mce_command_handler(MCE_CMD_ENTER_CSTATE, TEGRA_ARI_CORE_C7, wake_time[cpu], 0); + } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { + + /* loop until SC7 is allowed */ + do { + val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED, + TEGRA_ARI_CORE_C7, + MCE_CORE_SLEEP_TIME_INFINITE, + 0); + } while (val == 0); + + /* 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); + + /* save SMMU context */ + tegra_smmu_save_context(); + + /* 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); + + /* 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; @@ -140,6 +188,29 @@ int tegra_soc_pwr_domain_on(u_register_t mpidr) return PSCI_E_SUCCESS; } +int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + int state_id = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; + + /* + * Check if we are exiting from deep sleep and restore SE + * context if we are. + */ + if (state_id == PSTATE_ID_SOC_POWERDN) { + mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[0]); + mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[1]); + mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT, + se_regs[2]); + + /* Init SMMU */ + tegra_smmu_init(); + } + + return PSCI_E_SUCCESS; +} + int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { cpu_context_t *ctx = cm_get_context(NON_SECURE); diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c index 44faefef0..d6b8bc3f8 100644 --- a/plat/nvidia/tegra/soc/t186/plat_setup.c +++ b/plat/nvidia/tegra/soc/t186/plat_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -73,13 +73,21 @@ static const mmap_region_t tegra_mmap[] = { 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, 0x10000, /* 64KB */ + MAP_REGION_FLAT(TEGRA_SMMU_BASE, 0x1000000, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), {0} }; diff --git a/plat/nvidia/tegra/soc/t186/platform_t186.mk b/plat/nvidia/tegra/soc/t186/platform_t186.mk index 272074c55..adc4a9ee9 100644 --- a/plat/nvidia/tegra/soc/t186/platform_t186.mk +++ b/plat/nvidia/tegra/soc/t186/platform_t186.mk @@ -42,10 +42,10 @@ $(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 := 12 +MAX_XLAT_TABLES := 15 $(eval $(call add_define,MAX_XLAT_TABLES)) -MAX_MMAP_REGIONS := 12 +MAX_MMAP_REGIONS := 15 $(eval $(call add_define,MAX_MMAP_REGIONS)) # platform files