diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h index a2c736c9903bb7ff50e621ba9ddebc68aa9c616c..d766490d17312825296e37c2bcacbd7cb9a3042f 100644 --- a/include/lib/aarch64/arch.h +++ b/include/lib/aarch64/arch.h @@ -419,6 +419,10 @@ #define EC_BITS(x) (x >> ESR_EC_SHIFT) & ESR_EC_MASK +/* Reset bit inside the Reset management register for EL3 (RMR_EL3) */ +#define RMR_RESET_REQUEST_SHIFT 0x1u +#define RMR_WARM_RESET_CPU (1u << RMR_RESET_REQUEST_SHIFT) + /******************************************************************************* * Definitions of register offsets, fields and macros for CPU system * instructions. diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index 5376d5231fa2e6f1374ba6a68ba41798a3775f44..d6329268954dab0cdef29c9eb42f72d6e93db5a6 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, 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: @@ -48,6 +48,14 @@ extern uint64_t tegra_bl31_phys_base; extern uint64_t tegra_sec_entry_point; extern uint64_t tegra_console_base; +/* + * tegra_fake_system_suspend acts as a boolean var controlling whether + * we are going to take fake system suspend code or normal system suspend code + * path. This variable is set inside the sip call handlers,when the kernel + * requests a SIP call to set the suspend debug flags. + */ +uint8_t tegra_fake_system_suspend; + /* * The following platform setup functions are weakly defined. They * provide typical implementations that will be overridden by a SoC. @@ -182,14 +190,31 @@ void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) { + uint8_t pwr_state = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; + uint64_t rmr_el3 = 0; + /* call the chip's power down handler */ tegra_soc_pwr_domain_power_down_wfi(target_state); - /* enter power down state */ - wfi(); + /* + * If we are in fake system suspend mode, ensure we start doing + * procedures that help in looping back towards system suspend exit + * instead of calling WFI by requesting a warm reset. + * Else, just call WFI to enter low power state. + */ + if ((tegra_fake_system_suspend != 0U) && + (pwr_state == (uint8_t)PSTATE_ID_SOC_POWERDN)) { + + /* warm reboot */ + rmr_el3 = read_rmr_el3(); + write_rmr_el3(rmr_el3 | RMR_WARM_RESET_CPU); + + } else { + /* enter power down state */ + wfi(); + } /* we can never reach here */ - ERROR("%s: operation not handled.\n", __func__); panic(); } diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c index 4dd43532b93fd2d415a69879e3c647f1d4720df1..b01dcb0cf69dd7764297ec5bb2a865e2cde0ea7d 100644 --- a/plat/nvidia/tegra/common/tegra_sip_calls.c +++ b/plat/nvidia/tegra/common/tegra_sip_calls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, 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: @@ -37,6 +37,7 @@ #include <memctrl.h> #include <runtime_svc.h> #include <tegra_private.h> +#include <tegra_platform.h> /******************************************************************************* * Common Tegra SiP SMCs @@ -44,6 +45,13 @@ #define TEGRA_SIP_NEW_VIDEOMEM_REGION 0x82000003 #define TEGRA_SIP_FIQ_NS_ENTRYPOINT 0x82000005 #define TEGRA_SIP_FIQ_NS_GET_CONTEXT 0x82000006 +#define TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND 0xC2000007 + +/******************************************************************************* + * Fake system suspend mode control var + ******************************************************************************/ +extern uint8_t tegra_fake_system_suspend; + /******************************************************************************* * SoC specific SiP handler @@ -144,6 +152,26 @@ uint64_t tegra_sip_handler(uint32_t smc_fid, SMC_RET0(handle); break; + case TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND: + /* + * System suspend fake mode is set if we are on VDK and we make + * a debug SIP call. This mode ensures that we excercise debug + * path instead of the regular code path to suit the pre-silicon + * platform needs. These include replacing the call to WFI by + * a warm reset request. + */ + if (tegra_platform_is_emulation() != 0U) { + + tegra_fake_system_suspend = 1; + SMC_RET1(handle, 0); + } + + /* + * We return to the external world as if this SIP is not + * implemented in case, we are not running on VDK. + */ + break; + default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index 39006f6faf24d6e954334490da9e8e05846b2e57..edd1f65d62375a8f60341d73b262f605061e6bcc 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -103,6 +103,8 @@ void tegra_security_setup(void); void tegra_security_setup_videomem(uintptr_t base, uint64_t size); /* Declarations for tegra_pm.c */ +extern uint8_t tegra_fake_system_suspend; + void tegra_pm_system_suspend_entry(void); void tegra_pm_system_suspend_exit(void); int tegra_system_suspended(void);