/** @file * * Copyright (c) 2014-2016, ARM Limited. All rights reserved. * * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * **/ #include #include #include #include #include #include #include #include #include #include #include "suspend_private.h" int32_t tftf_enter_suspend(const suspend_info_t *info, tftf_suspend_ctx_t *ctx) { smc_args cpu_suspend_args = { info->psci_api, info->power_state, (uintptr_t)__tftf_cpu_resume_ep, (u_register_t)ctx }; smc_args system_suspend_args = { info->psci_api, (uintptr_t)__tftf_cpu_resume_ep, (u_register_t)ctx }; smc_ret_values rc; if (info->save_system_context) { ctx->save_system_context = 1; tftf_save_system_ctx(ctx); } else ctx->save_system_context = 0; /* * Save the CPU context. It will be restored in resume path in * __tftf_cpu_resume_ep(). */ __tftf_save_arch_context(ctx); /* * Flush the context that must be retrieved with MMU off */ flush_dcache_range((u_register_t)ctx, sizeof(*ctx)); if (info->psci_api == SMC_PSCI_CPU_SUSPEND) rc = tftf_smc(&cpu_suspend_args); else rc = tftf_smc(&system_suspend_args); /* * If execution reaches this point, The above SMC call was an invalid * call or a suspend to standby call. In both cases the CPU does not * power down so there is no need to restore the context. */ return rc.ret0; } void tftf_restore_system_ctx(tftf_suspend_ctx_t *ctx) { assert(ctx != NULL); assert(ctx->save_system_context); /* * TODO: Check if there is a need for separate platform * API for resume. */ tftf_early_platform_setup(); INFO("Restoring system context\n"); /* restore the global GIC context */ arm_gic_restore_context_global(); tftf_timer_gic_state_restore(); } void tftf_save_system_ctx(tftf_suspend_ctx_t *ctx) { assert(ctx != NULL); assert(ctx->save_system_context); /* Nothing to do here currently */ INFO("Saving system context\n"); /* Save the global GIC context */ arm_gic_save_context_global(); } int tftf_suspend(const suspend_info_t *info) { int32_t rc; uint64_t flags; flags = read_daif(); disable_irq(); INFO("Going into suspend state\n"); /* Save the local GIC context */ arm_gic_save_context_local(); #if PLAT == warp7 /* Add this ugly workaround because warp7 does not support it yet */ rc = PSCI_E_SUCCESS; #else rc = __tftf_suspend(info); #endif /* Restore the local GIC context */ arm_gic_restore_context_local(); /* * DAIF flags should be restored last because it could be an issue * to unmask exceptions before that point, e.g. if GIC must be * reconfigured upon resume from suspend. */ write_daif(flags); INFO("Resumed from suspend state\n"); return rc; }