blob: d6c989afe3dea42a5838bbca7d68eff18a4b48b5 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <arm_gic.h>
Sandrine Bailleuxcbc45162018-12-18 16:07:57 +01009#include <console.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020010#include <debug.h>
11#include <platform.h>
12#include <power_management.h>
13#include <psci.h>
14#include <sgi.h>
15#include <stdint.h>
16#include <tftf.h>
17#include <tftf_lib.h>
18#include "suspend_private.h"
19
20int32_t tftf_enter_suspend(const suspend_info_t *info,
21 tftf_suspend_ctx_t *ctx)
22{
23 smc_args cpu_suspend_args = {
24 info->psci_api,
25 info->power_state,
26 (uintptr_t)__tftf_cpu_resume_ep,
27 (u_register_t)ctx
28 };
29
30 smc_args system_suspend_args = {
31 info->psci_api,
32 (uintptr_t)__tftf_cpu_resume_ep,
33 (u_register_t)ctx
34 };
35
36 smc_ret_values rc;
37
38 if (info->save_system_context) {
39 ctx->save_system_context = 1;
40 tftf_save_system_ctx(ctx);
41 } else
42 ctx->save_system_context = 0;
43
44 /*
45 * Save the CPU context. It will be restored in resume path in
46 * __tftf_cpu_resume_ep().
47 */
48 __tftf_save_arch_context(ctx);
49
50 /*
51 * Flush the context that must be retrieved with MMU off
52 */
53 flush_dcache_range((u_register_t)ctx, sizeof(*ctx));
54
Sandrine Bailleuxcbc45162018-12-18 16:07:57 +010055 /* Make sure any outstanding message is printed. */
56 console_flush();
57
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020058 if (info->psci_api == SMC_PSCI_CPU_SUSPEND)
59 rc = tftf_smc(&cpu_suspend_args);
60 else
61 rc = tftf_smc(&system_suspend_args);
62
63 /*
64 * If execution reaches this point, The above SMC call was an invalid
65 * call or a suspend to standby call. In both cases the CPU does not
66 * power down so there is no need to restore the context.
67 */
68 return rc.ret0;
69}
70
71void tftf_restore_system_ctx(tftf_suspend_ctx_t *ctx)
72{
73 assert(ctx != NULL);
74 assert(ctx->save_system_context);
75
76 /*
77 * TODO: Check if there is a need for separate platform
78 * API for resume.
79 */
80
81 tftf_early_platform_setup();
82
83 INFO("Restoring system context\n");
84
85 /* restore the global GIC context */
86 arm_gic_restore_context_global();
87 tftf_timer_gic_state_restore();
88}
89
90void tftf_save_system_ctx(tftf_suspend_ctx_t *ctx)
91{
92 assert(ctx != NULL);
93 assert(ctx->save_system_context);
94
95 /* Nothing to do here currently */
96 INFO("Saving system context\n");
97
98 /* Save the global GIC context */
99 arm_gic_save_context_global();
100}
101
102int tftf_suspend(const suspend_info_t *info)
103{
104 int32_t rc;
105 uint64_t flags;
106
107 flags = read_daif();
108
109 disable_irq();
110
111 INFO("Going into suspend state\n");
112
113 /* Save the local GIC context */
114 arm_gic_save_context_local();
115
116 rc = __tftf_suspend(info);
117
118 /* Restore the local GIC context */
119 arm_gic_restore_context_local();
120
121 /*
122 * DAIF flags should be restored last because it could be an issue
123 * to unmask exceptions before that point, e.g. if GIC must be
124 * reconfigured upon resume from suspend.
125 */
126 write_daif(flags);
127
128 INFO("Resumed from suspend state\n");
129
130 return rc;
131}