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