blob: 47c902828c492445bc011807f070f966108c8172 [file] [log] [blame]
Aaron Durbinbda35772014-09-19 15:52:31 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2014 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
18 */
19
20#ifndef __ARCH_PSCI_H__
21#define __ARCH_PSCI_H__
22
Aaron Durbinb777f3e2014-10-28 15:38:17 -050023#include <stdint.h>
24#include <arch/cpu.h>
Aaron Durbinbda35772014-09-19 15:52:31 -050025#include <arch/smc.h>
26
27/* Return Values */
28enum {
29 PSCI_RET_SUCCESS = 0,
30 PSCI_RET_NOT_SUPPORTED = -1,
31 PSCI_RET_INVALID_PARAMETERS = -2,
32 PSCI_RET_DENIED = -3,
33 PSCI_RET_ALREADY_ON = -4,
34 PSCI_RET_ON_PENDING = -5,
35 PSCI_RET_INTERNAL_FAILURE = -6,
36 PSCI_RET_NOT_PRESENT = -7,
37 PSCI_RET_DISABLED = -8,
38};
39
Aaron Durbinb777f3e2014-10-28 15:38:17 -050040/* Generic PSCI state. */
41enum {
42 PSCI_STATE_OFF = 0,
43 PSCI_STATE_ON_PENDING,
44 PSCI_STATE_ON,
45};
46
47/* Affinity level support. */
48enum {
49 PSCI_AFFINITY_LEVEL_0,
50 PSCI_AFFINITY_LEVEL_1,
51 PSCI_AFFINITY_LEVEL_2,
52 PSCI_AFFINITY_LEVEL_3,
53 PSCI_AFFINITY_ROOT,
54 PSCI_AFFINITY_LEVEL_HIGHEST = PSCI_AFFINITY_ROOT,
55};
56
57static inline int psci_level_below(int level)
58{
59 return level - 1;
60}
61
62struct psci_node;
63
64struct psci_cpu_state {
65 struct cpu_info *ci;
Aaron Durbin9fd7b1c2014-11-05 10:45:05 -060066 struct cpu_action startup;
Aaron Durbinb777f3e2014-10-28 15:38:17 -050067 /* Ancestor of target to update state in CPU_ON case. */
68 struct psci_node *ancestor;
69};
70
71struct psci_node_group {
72 size_t num;
73 struct psci_node *nodes;
74};
75
76struct psci_node {
77 uint64_t mpidr;
78 /* Affinity level of node. */
79 int level;
80 /* Generic power state of this entity. */
81 int state;
82 /* The SoC can stash its own state accounting in here. */
83 int soc_state;
84 /* Parent of curernt entity. */
85 struct psci_node *parent;
86 /*
87 * CPUs are leaves in the tree. They don't have children. The
88 * CPU-specific bits of storage can be shared with the children
89 * storage.
90 */
91 union {
92 struct psci_node_group children;
93 struct psci_cpu_state cpu_state;
94 };
95};
96
97static inline struct psci_node *psci_node_parent(const struct psci_node *n)
98{
99 return n->parent;
100}
101
102static inline int psci_root_node(const struct psci_node *n)
103{
104 return psci_node_parent(n) == NULL;
105}
106
Aaron Durbin0179fcf2014-10-30 13:13:50 -0500107enum {
108 PSCI_CMD_ON,
109 PSCI_CMD_OFF,
110 PSCI_CMD_STANDBY,
111};
112
113/*
114 * PSCI actions are serialized into a command for the SoC to process. There are
115 * 2 phases of a command being processed: prepare and commit. The prepare() is
116 * called with the PSCI locks held for the state of the PSCI nodes. If
117 * successful, the appropriate locks will be dropped and commit() will be
118 * called with the same structure. It is permissible for the SoC support code
119 * to modify the struture passed in (e.g. to update the requested state_id to
120 * reflect dynamic constraints on how deep of a state to enter).
121 */
122struct psci_cmd {
123 /* Command type. */
124 int type;
125 /*
126 * PSCI state id for PSCI_CMD_OFF and PSCI_CMD_STANDBY commands.
127 * A value of -1 indicates a CPU_OFF request.
128 */
129 int state_id;
130 /*
131 * target is the command's target, but it can affect up to the
132 * ancestor entity. If target == ancestor then it only affects
133 * target, otherwise all entites up the hierarchy including ancestor.
134 */
135 struct psci_node *target;
136 struct psci_node *ancestor;
137};
138
Aaron Durbinb777f3e2014-10-28 15:38:17 -0500139struct psci_soc_ops {
140 /*
141 * Return number of entities one level below given parent affinitly
142 * level and mpidr.
143 */
144 size_t (*children_at_level)(int parent_level, uint64_t mpidr);
Aaron Durbin0179fcf2014-10-30 13:13:50 -0500145
146 int (*cmd_prepare)(struct psci_cmd *cmd);
147 int (*cmd_commit)(struct psci_cmd *cmd);
Aaron Durbinb777f3e2014-10-28 15:38:17 -0500148};
149
150/* Each SoC needs to provide the functions in the psci_soc_ops structure. */
151extern struct psci_soc_ops soc_psci_ops;
152
Aaron Durbinbda35772014-09-19 15:52:31 -0500153/* PSCI Functions. */
154enum {
155 /* 32-bit System level functions. */
156 PSCI_VERSION = SMC_FUNC_FAST32(0x4, 0x0),
157 PSCI_SYSTEM_OFF = SMC_FUNC_FAST32(0x4, 0x8),
158 PSCI_SYSTEM_RESET = SMC_FUNC_FAST32(0x4, 0x9),
159
160 /* 32-bit CPU support functions. */
161 PSCI_CPU_SUSPEND32 = SMC_FUNC_FAST32(0x4, 0x1),
162 PSCI_CPU_OFF32 = SMC_FUNC_FAST32(0x4, 0x2),
163 PSCI_CPU_ON32 = SMC_FUNC_FAST32(0x4, 0x3),
164
165 /* 64-bit CPU support functions. */
166 PSCI_CPU_SUSPEND64 = SMC_FUNC_FAST64(0x4, 0x1),
Aaron Durbinbda35772014-09-19 15:52:31 -0500167 PSCI_CPU_ON64 = SMC_FUNC_FAST64(0x4, 0x3),
168};
169
170/* Parameter arguments. */
171enum {
172 PSCI_PARAM_0 = 1,
173 PSCI_PARAM_1,
174 PSCI_PARAM_2,
175 PSCI_PARAM_3,
176 PSCI_RETURN_0 = 1,
177 PSCI_RETURN_1,
178 PSCI_RETURN_2,
179 PSCI_RETURN_3,
180};
181
182struct psci_func {
183 uint32_t id;
184 struct smc_call *smc;
185};
186
187static inline void psci_func_init(struct psci_func *pf, struct smc_call *smc)
188{
189 pf->id = smc_function_id(smc);
190 pf->smc = smc;
191}
192
193static inline uint64_t psci64_arg(struct psci_func *pf, unsigned i)
194{
195 return smc64_arg(pf->smc, i);
196}
197
198static inline uint32_t psci32_arg(struct psci_func *pf, unsigned i)
199{
200 return psci64_arg(pf, i);
201}
202
203static inline void psci64_result(struct psci_func *pf, unsigned i, uint64_t v)
204{
205 smc64_result(pf->smc, i, v);
206}
207
208static inline void psci32_result(struct psci_func *pf, unsigned i, uint32_t v)
209{
210 uint64_t v64 = v;
211 psci64_result(pf, i, v64);
212}
213
214static inline void psci32_return(struct psci_func *pf, int32_t val)
215{
216 psci32_result(pf, 0, val);
217}
218
219static inline void psci64_return(struct psci_func *pf, int64_t val)
220{
221 psci64_result(pf, 0, val);
222}
223
Aaron Durbin6cdacb32014-11-06 15:17:33 -0600224void psci_init(uintptr_t cpu_on_entry);
225void psci_soc_init(uintptr_t cpu_on_entry);
Aaron Durbinbda35772014-09-19 15:52:31 -0500226
227/* Turn on the current CPU within the PSCI subsystem. */
Aaron Durbin9fd7b1c2014-11-05 10:45:05 -0600228void psci_turn_on_self(const struct cpu_action *action);
Aaron Durbinb777f3e2014-10-28 15:38:17 -0500229int psci_turn_off_self(void);
Aaron Durbin6cdacb32014-11-06 15:17:33 -0600230/* Entry point for CPUs just turning on or waking up. */
231void psci_cpu_entry(void);
Aaron Durbinbda35772014-09-19 15:52:31 -0500232
233#endif /* __ARCH_PSCI_H__ */