psci_private.h 8.84 KB
Newer Older
1
/*
2
 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of ARM nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __PSCI_PRIVATE_H__
#define __PSCI_PRIVATE_H__

34
#include <arch.h>
35
#include <bakery_lock.h>
36
#include <bl_common.h>
37
#include <cpu_data.h>
38
#include <psci.h>
39
#include <spinlock.h>
40

41
42
43
44
/*
 * The following helper macros abstract the interface to the Bakery
 * Lock API.
 */
45
46
47
#define psci_lock_init(non_cpu_pd_node, idx)			\
	((non_cpu_pd_node)[(idx)].lock_index = (idx))
#define psci_lock_get(non_cpu_pd_node)				\
48
	bakery_lock_get(&psci_locks[(non_cpu_pd_node)->lock_index])
49
#define psci_lock_release(non_cpu_pd_node)			\
50
	bakery_lock_release(&psci_locks[(non_cpu_pd_node)->lock_index])
51

Soby Mathew's avatar
Soby Mathew committed
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
 * The PSCI capability which are provided by the generic code but does not
 * depend on the platform or spd capabilities.
 */
#define PSCI_GENERIC_CAP	\
			(define_psci_cap(PSCI_VERSION) |		\
			define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) |	\
			define_psci_cap(PSCI_FEATURES))

/*
 * The PSCI capabilities mask for 64 bit functions.
 */
#define PSCI_CAP_64BIT_MASK	\
			(define_psci_cap(PSCI_CPU_SUSPEND_AARCH64) |	\
			define_psci_cap(PSCI_CPU_ON_AARCH64) |		\
			define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) |	\
			define_psci_cap(PSCI_MIG_AARCH64) |		\
69
70
			define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) |	\
			define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64))
Soby Mathew's avatar
Soby Mathew committed
71

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Helper macros to get/set the fields of PSCI per-cpu data.
 */
#define psci_set_aff_info_state(aff_state) \
		set_cpu_data(psci_svc_cpu_data.aff_info_state, aff_state)
#define psci_get_aff_info_state() \
		get_cpu_data(psci_svc_cpu_data.aff_info_state)
#define psci_get_aff_info_state_by_idx(idx) \
		get_cpu_data_by_index(idx, psci_svc_cpu_data.aff_info_state)
#define psci_get_suspend_pwrlvl() \
		get_cpu_data(psci_svc_cpu_data.target_pwrlvl)
#define psci_set_suspend_pwrlvl(target_lvl) \
		set_cpu_data(psci_svc_cpu_data.target_pwrlvl, target_lvl)
#define psci_set_cpu_local_state(state) \
		set_cpu_data(psci_svc_cpu_data.local_state, state)
#define psci_get_cpu_local_state() \
		get_cpu_data(psci_svc_cpu_data.local_state)
#define psci_get_cpu_local_state_by_idx(idx) \
		get_cpu_data_by_index(idx, psci_svc_cpu_data.local_state)

/*
 * Helper macros for the CPU level spinlocks
 */
#define psci_spin_lock_cpu(idx)	spin_lock(&psci_cpu_pd_nodes[idx].cpu_lock)
#define psci_spin_unlock_cpu(idx) spin_unlock(&psci_cpu_pd_nodes[idx].cpu_lock)

/* Helper macro to identify a CPU standby request in PSCI Suspend call */
#define is_cpu_standby_req(is_power_down_state, retn_lvl) \
		(((!(is_power_down_state)) && ((retn_lvl) == 0)) ? 1 : 0)
Soby Mathew's avatar
Soby Mathew committed
101

102
/*******************************************************************************
103
104
105
106
107
 * The following two data structures implement the power domain tree. The tree
 * is used to track the state of all the nodes i.e. power domain instances
 * described by the platform. The tree consists of nodes that describe CPU power
 * domains i.e. leaf nodes and all other power domains which are parents of a
 * CPU power domain i.e. non-leaf nodes.
108
 ******************************************************************************/
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
typedef struct non_cpu_pwr_domain_node {
	/*
	 * Index of the first CPU power domain node level 0 which has this node
	 * as its parent.
	 */
	unsigned int cpu_start_idx;

	/*
	 * Number of CPU power domains which are siblings of the domain indexed
	 * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
	 * -> cpu_start_idx + ncpus' have this node as their parent.
	 */
	unsigned int ncpus;

	/*
	 * Index of the parent power domain node.
	 * TODO: Figure out whether to whether using pointer is more efficient.
	 */
	unsigned int parent_node;

	plat_local_state_t local_state;

131
	unsigned char level;
132
133

	/* For indexing the psci_lock array*/
134
135
	unsigned char lock_index;
} non_cpu_pd_node_t;
136

137
typedef struct cpu_pwr_domain_node {
138
	u_register_t mpidr;
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
	/*
	 * Index of the parent power domain node.
	 * TODO: Figure out whether to whether using pointer is more efficient.
	 */
	unsigned int parent_node;

	/*
	 * A CPU power domain does not require state coordination like its
	 * parent power domains. Hence this node does not include a bakery
	 * lock. A spinlock is required by the CPU_ON handler to prevent a race
	 * when multiple CPUs try to turn ON the same target CPU.
	 */
	spinlock_t cpu_lock;
} cpu_pd_node_t;
154
155
156
157

/*******************************************************************************
 * Data prototypes
 ******************************************************************************/
158
159
160
extern const plat_psci_ops_t *psci_plat_pm_ops;
extern non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
extern cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
161
extern unsigned int psci_caps;
162

163
164
165
/* One bakery lock is required for each non-cpu power domain */
DECLARE_BAKERY_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]);

166
/*******************************************************************************
167
 * SPD's power management hooks registered with PSCI
168
 ******************************************************************************/
169
extern const spd_pm_ops_t *psci_spd_pm;
170

171
172
173
174
/*******************************************************************************
 * Function prototypes
 ******************************************************************************/
/* Private exported functions from psci_common.c */
175
176
177
int psci_validate_power_state(unsigned int power_state,
			      psci_power_state_t *state_info);
void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info);
178
int psci_validate_mpidr(u_register_t mpidr);
179
180
void psci_init_req_local_pwr_states(void);
void psci_power_up_finish(void);
181
int psci_validate_entry_point(entry_point_info_t *ep,
182
			uintptr_t entrypoint, u_register_t context_id);
183
void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx,
184
				      unsigned int end_lvl,
185
				      unsigned int node_index[]);
186
void psci_do_state_coordination(unsigned int end_pwrlvl,
187
				psci_power_state_t *state_info);
188
void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl,
189
				   unsigned int cpu_idx);
190
void psci_release_pwr_domain_locks(unsigned int end_pwrlvl,
191
192
193
194
195
				   unsigned int cpu_idx);
int psci_validate_suspend_req(const psci_power_state_t *state_info,
			      unsigned int is_power_down_state_req);
unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info);
unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info);
196
void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl);
197
void psci_print_power_domain_map(void);
198
unsigned int psci_is_last_on_cpu(void);
199
int psci_spd_migrate_info(u_register_t *mpidr);
200

201
202
203
/* Private exported functions from psci_on.c */
int psci_cpu_on_start(unsigned long target_cpu,
		      entry_point_info_t *ep,
204
		      unsigned int end_pwrlvl);
205

206
207
void psci_cpu_on_finish(unsigned int cpu_idx,
			psci_power_state_t *state_info);
208

209
/* Private exported functions from psci_off.c */
210
int psci_do_cpu_off(unsigned int end_pwrlvl);
211

212
/* Private exported functions from psci_suspend.c */
213
void psci_cpu_suspend_start(entry_point_info_t *ep,
214
			unsigned int end_pwrlvl,
215
216
			psci_power_state_t *state_info,
			unsigned int is_power_down_state_req);
217

218
219
void psci_cpu_suspend_finish(unsigned int cpu_idx,
			psci_power_state_t *state_info);
220

221
/* Private exported functions from psci_helpers.S */
222
void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level);
223
void psci_do_pwrup_cache_maintenance(void);
224

225
226
227
228
/* Private exported functions from psci_system_off.c */
void __dead2 psci_system_off(void);
void __dead2 psci_system_reset(void);

229
#endif /* __PSCI_PRIVATE_H__ */