diff --git a/plat/nvidia/tegra/include/t194/tegra_def.h b/plat/nvidia/tegra/include/t194/tegra_def.h index 0037b49e3a81bf539e45dc0088be6b41b6a69320..bc98fa3ae4a3701e971025aba341b95650c10dd0 100644 --- a/plat/nvidia/tegra/include/t194/tegra_def.h +++ b/plat/nvidia/tegra/include/t194/tegra_def.h @@ -135,11 +135,13 @@ * Security Engine related constants ******************************************************************************/ #define TEGRA_SE0_BASE U(0x03AC0000) -#define SE_MUTEX_WATCHDOG_NS_LIMIT U(0x6C) +#define SE0_MUTEX_WATCHDOG_NS_LIMIT U(0x6C) +#define SE0_AES0_ENTROPY_SRC_AGE_CTRL U(0x2FC) #define TEGRA_PKA1_BASE U(0x03AD0000) -#define PKA_MUTEX_WATCHDOG_NS_LIMIT U(0x8144) +#define SE_PKA1_CTRL_SE_MUTEX_TMOUT_DFTVAL U(0x144) +#define PKA1_MUTEX_WATCHDOG_NS_LIMIT SE_PKA1_CTRL_SE_MUTEX_TMOUT_DFTVAL #define TEGRA_RNG1_BASE U(0x03AE0000) -#define RNG_MUTEX_WATCHDOG_NS_LIMIT U(0xFE0) +#define RNG1_MUTEX_WATCHDOG_NS_LIMIT U(0xFE0) /******************************************************************************* * Tegra micro-seconds timer constants diff --git a/plat/nvidia/tegra/soc/t194/drivers/include/se.h b/plat/nvidia/tegra/soc/t194/drivers/include/se.h new file mode 100644 index 0000000000000000000000000000000000000000..6e656f677513264a30a129f9011dfe8b12e8e0a6 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/include/se.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SE_H__ +#define __SE_H__ + +int32_t tegra_se_suspend(void); +void tegra_se_resume(void); + +#endif /* __SE_H__ */ diff --git a/plat/nvidia/tegra/soc/t194/drivers/se/se.c b/plat/nvidia/tegra/soc/t194/drivers/se/se.c new file mode 100644 index 0000000000000000000000000000000000000000..3df670c922a260c06841fb361c3c6b0e62ae10a4 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/se/se.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "se_private.h" + +/******************************************************************************* + * Constants and Macros + ******************************************************************************/ +#define ERR_STATUS_SW_CLEAR U(0xFFFFFFFF) +#define INT_STATUS_SW_CLEAR U(0xFFFFFFFF) +#define MAX_TIMEOUT_MS U(100) /* Timeout in 100ms */ +#define NUM_SE_REGS_TO_SAVE U(4) + +/******************************************************************************* + * Data structure and global variables + ******************************************************************************/ +static uint32_t se_regs[NUM_SE_REGS_TO_SAVE]; + +/* + * Check that SE operation has completed after kickoff. + * + * This function is invoked after an SE operation has been started, + * and it checks the following conditions: + * + * 1. SE_STATUS = IDLE + * 2. AHB bus data transfer is complete. + * 3. SE_ERR_STATUS is clean. + */ +static bool tegra_se_is_operation_complete(void) +{ + uint32_t val = 0, timeout = 0, sha_status, aes_status; + int32_t ret = 0; + bool se_is_busy, txn_has_errors, txn_successful; + + /* + * Poll the status register to check if the operation + * completed. + */ + do { + val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS); + se_is_busy = !!(val & CTX_SAVE_AUTO_SE_BUSY); + + /* sleep until SE finishes */ + if (se_is_busy) { + mdelay(1); + timeout++; + } + + } while (se_is_busy && (timeout < MAX_TIMEOUT_MS)); + + /* any transaction errors? */ + txn_has_errors = (tegra_se_read_32(SHA_ERR_STATUS) != 0U) || + (tegra_se_read_32(AES0_ERR_STATUS) != 0U); + + /* transaction successful? */ + sha_status = tegra_se_read_32(SHA_INT_STATUS) & SHA_SE_OP_DONE; + aes_status = tegra_se_read_32(AES0_INT_STATUS) & AES0_SE_OP_DONE; + txn_successful = (sha_status == SHA_SE_OP_DONE) && + (aes_status == AES0_SE_OP_DONE); + + if ((timeout == MAX_TIMEOUT_MS) || txn_has_errors || !txn_successful) { + ERROR("%s: Atomic context save operation failed!\n", + __func__); + ret = -ECANCELED; + } + + return (ret == 0); +} + +/* + * Wait for SE engine to be idle and clear any pending interrupts, before + * starting the next SE operation. + */ +static bool tegra_se_is_ready(void) +{ + int32_t ret = 0; + uint32_t val = 0, timeout = 0; + bool se_is_ready; + + /* Wait for previous operation to finish */ + do { + val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS); + se_is_ready = (val == CTX_SAVE_AUTO_SE_READY); + + /* sleep until SE is ready */ + if (!se_is_ready) { + mdelay(1); + timeout++; + } + + } while (!se_is_ready && (timeout < MAX_TIMEOUT_MS)); + + if (timeout == MAX_TIMEOUT_MS) { + ERROR("%s: SE is not ready!\n", __func__); + ret = -ETIMEDOUT; + } + + /* Clear any pending interrupts from previous operation */ + tegra_se_write_32(AES0_INT_STATUS, INT_STATUS_SW_CLEAR); + tegra_se_write_32(AES1_INT_STATUS, INT_STATUS_SW_CLEAR); + tegra_se_write_32(RSA_INT_STATUS, INT_STATUS_SW_CLEAR); + tegra_se_write_32(SHA_INT_STATUS, INT_STATUS_SW_CLEAR); + + /* Clear error status for each engine seen from current port */ + tegra_se_write_32(AES0_ERR_STATUS, ERR_STATUS_SW_CLEAR); + tegra_se_write_32(AES1_ERR_STATUS, ERR_STATUS_SW_CLEAR); + tegra_se_write_32(RSA_ERR_STATUS, ERR_STATUS_SW_CLEAR); + tegra_se_write_32(SHA_ERR_STATUS, ERR_STATUS_SW_CLEAR); + + return (ret == 0); +} + +/* + * During System Suspend, this handler triggers the hardware context + * save operation. + */ +static int32_t tegra_se_save_context(void) +{ + int32_t ret = -ECANCELED; + + /* + * 1. Ensure all SE Driver including RNG1/PKA1 are shut down. + * TSEC/R5s are powergated/idle. All tasks on SE1~SE4, RNG1, + * PKA1 are wrapped up. SE0 is ready for use. + * 2. Clear interrupt/error in SE0 status register. + * 3. Scrub SE0 register to avoid false failure for illegal + * configuration. Probably not needed, dependent on HW + * implementation. + * 4. Check SE is ready for HW CTX_SAVE by polling + * SE_CTX_SAVE_AUTO_STATUS.SE_READY. + * + * Steps 1-4 are executed by tegra_se_is_ready(). + * + * 5. Issue context save command. + * 6. Check SE is busy with CTX_SAVE, the command in step5 was not + * dropped for ongoing traffic in any of SE port/engine. + * 7. Poll SE register or wait for SE APB interrupt for task completion + * a. Polling: Read SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE + * b. Interrupt: After receiving interrupt from SE APB, read + * SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE. + * 8. Check AES0 and SHA ERR_STATUS to ensure no error case. + * 9. Check AES0 and SHA INT_STATUS to ensure operation has successfully + * completed. + * + * Steps 6-9 are executed by tegra_se_is_operation_complete(). + */ + if (tegra_se_is_ready()) { + + /* Issue context save command */ + tegra_se_write_32(AES0_OPERATION, SE_OP_CTX_SAVE); + + /* Wait for operation to finish */ + if (tegra_se_is_operation_complete()) { + ret = 0; + } + } + + return ret; +} + +/* + * Handler to power down the SE hardware blocks - SE, RNG1 and PKA1. This + * needs to be called only during System Suspend. + */ +int32_t tegra_se_suspend(void) +{ + int32_t ret = 0; + + /* save SE registers */ + se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[1] = mmio_read_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL); + se_regs[2] = mmio_read_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT); + se_regs[3] = mmio_read_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT); + + /* Save SE context. The BootROM restores it during System Resume */ + ret = tegra_se_save_context(); + if (ret != 0) { + ERROR("%s: context save failed (%d)\n", __func__, ret); + } + + return ret; +} + +/* + * Handler to power up the SE hardware block(s) during System Resume. + */ +void tegra_se_resume(void) +{ + /* + * When TZ takes over after System Resume, TZ should first reconfigure + * SE_MUTEX_WATCHDOG_NS_LIMIT, PKA1_MUTEX_WATCHDOG_NS_LIMIT, + * RNG1_MUTEX_WATCHDOG_NS_LIMIT and SE_ENTROPY_SRC_AGE_CTRL before + * other operations. + */ + mmio_write_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT, se_regs[0]); + mmio_write_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL, se_regs[1]); + mmio_write_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[2]); + mmio_write_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[3]); +} diff --git a/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h new file mode 100644 index 0000000000000000000000000000000000000000..7d531bb9de9606dd6f35b8b6252e5761fd958a30 --- /dev/null +++ b/plat/nvidia/tegra/soc/t194/drivers/se/se_private.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SE_PRIVATE_H__ +#define __SE_PRIVATE_H__ + +#include + +/* SE0_INT_ENABLE_0 */ +#define SE0_INT_ENABLE U(0x88) +#define SE0_DISABLE_ALL_INT U(0x0) + +/* SE0_INT_STATUS_0 */ +#define SE0_INT_STATUS U(0x8C) +#define SE0_CLEAR_ALL_INT_STATUS U(0x3F) + +/* SE0_SHA_INT_STATUS_0 */ +#define SHA_INT_STATUS U(0x184) +#define SHA_SE_OP_DONE (U(1) << 4) + +/* SE0_SHA_ERR_STATUS_0 */ +#define SHA_ERR_STATUS U(0x18C) + +/* SE0_AES0_INT_STATUS_0 */ +#define AES0_INT_STATUS U(0x2F0) +#define AES0_SE_OP_DONE (U(1) << 4) + +/* SE0_AES0_ERR_STATUS_0 */ +#define AES0_ERR_STATUS U(0x2F8) + +/* SE0_AES1_INT_STATUS_0 */ +#define AES1_INT_STATUS U(0x4F0) + +/* SE0_AES1_ERR_STATUS_0 */ +#define AES1_ERR_STATUS U(0x4F8) + +/* SE0_RSA_INT_STATUS_0 */ +#define RSA_INT_STATUS U(0x758) + +/* SE0_RSA_ERR_STATUS_0 */ +#define RSA_ERR_STATUS U(0x760) + +/* SE0_AES0_OPERATION_0 */ +#define AES0_OPERATION U(0x238) +#define OP_MASK_BITS U(0x7) +#define SE_OP_CTX_SAVE U(0x3) + +/* SE0_AES0_CTX_SAVE_CONFIG_0 */ +#define CTX_SAVE_CONFIG U(0x2D4) + +/* SE0_AES0_CTX_SAVE_AUTO_STATUS_0 */ +#define CTX_SAVE_AUTO_STATUS U(0x300) +#define CTX_SAVE_AUTO_SE_READY U(0xFF) +#define CTX_SAVE_AUTO_SE_BUSY (U(0x1) << 31) + +/* SE0_AES0_CTX_SAVE_AUTO_CTRL_0 */ +#define CTX_SAVE_AUTO_CTRL U(0x304) +#define SE_CTX_SAVE_AUTO_EN (U(0x1) << 0) +#define SE_CTX_SAVE_AUTO_LOCK_EN (U(0x1) << 1) + +/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_0 */ +#define CTX_SAVE_AUTO_START_ADDR U(0x308) + +/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_HI_0 */ +#define CTX_SAVE_AUTO_START_ADDR_HI U(0x30C) + +/******************************************************************************* + * Inline functions definition + ******************************************************************************/ + +static inline uint32_t tegra_se_read_32(uint32_t offset) +{ + return mmio_read_32(TEGRA_SE0_BASE + offset); +} + +static inline void tegra_se_write_32(uint32_t offset, uint32_t val) +{ + mmio_write_32(TEGRA_SE0_BASE + offset, val); +} + +#endif /* __SE_PRIVATE_H__ */ diff --git a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c index 0932061d01958b2b23ee5a121d5093e24c922916..51c3e957222b7456b6932c91d07800da7bb00075 100644 --- a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c @@ -5,21 +5,24 @@ */ #include -#include #include +#include +#include + +#include #include -#include -#include #include +#include #include +#include +#include #include #include -#include +#include #include -#include -#include #include -#include +#include +#include extern void tegra_secure_entrypoint(void); @@ -39,10 +42,7 @@ extern uint32_t __tegra186_cpu_reset_handler_data, #define TEGRA186_WAKE_TIME_SHIFT 4U /* default core wake mask for CPU_SUSPEND */ #define TEGRA194_CORE_WAKE_MASK 0x180cU -/* context size to save during system suspend */ -#define TEGRA186_SE_CONTEXT_SIZE 3U -static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE]; static struct t19x_psci_percpu_data { uint32_t wake_time; } __aligned(CACHE_WRITEBACK_GRANULE) t19x_percpu_data[PLATFORM_CORE_COUNT]; @@ -134,14 +134,6 @@ int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) } 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 + SCRATCH_SECURE_BOOTP_FCFG, val); @@ -157,6 +149,15 @@ int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) tegra_smmu_save_context(0); #endif + /* + * Suspend SE, RNG1 and PKA1 only on silcon and fpga, + * since VDK does not support atomic se ctx save + */ + if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) { + ret = tegra_se_suspend(); + assert(ret == 0); + } + if (!tegra_fake_system_suspend) { /* Prepare for system suspend */ @@ -345,18 +346,12 @@ int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) * 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 */ - tegra_smmu_init(); + /* Resume SE, RNG1 and PKA1 */ + tegra_se_resume(); + /* * Reset power state info for the last core doing SC7 * entry and exit, we set deepest power state as CC7 diff --git a/plat/nvidia/tegra/soc/t194/platform_t194.mk b/plat/nvidia/tegra/soc/t194/platform_t194.mk index faeaed35a770dd09149ce9f083624d4c0d844a9e..ef72eb7f8460b6c02dff5175088861cb0ba72c2a 100644 --- a/plat/nvidia/tegra/soc/t194/platform_t194.mk +++ b/plat/nvidia/tegra/soc/t194/platform_t194.mk @@ -54,6 +54,7 @@ BL31_SOURCES += lib/cpus/aarch64/denver.S \ ${SOC_DIR}/drivers/mce/mce.c \ ${SOC_DIR}/drivers/mce/nvg.c \ ${SOC_DIR}/drivers/mce/aarch64/nvg_helpers.S \ + ${SOC_DIR}/drivers/se/se.c \ ${SOC_DIR}/plat_memctrl.c \ ${SOC_DIR}/plat_psci_handlers.c \ ${SOC_DIR}/plat_setup.c \