blob: cf0d5f08d3607cf83e6efae364c5a49186d983d4 [file] [log] [blame]
Soren Brinkmann76fcae32016-03-06 20:16:27 -08001/*
Sandrine Bailleux7659a262016-07-05 09:55:03 +01002 * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
Soren Brinkmann76fcae32016-03-06 20:16:27 -08003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * APU specific definition of processors in the subsystem as well as functions
33 * for getting information about and changing state of the APU.
34 */
35
Stefan Krsmanovic2b783662016-05-20 15:51:09 +020036#include <bakery_lock.h>
Soren Brinkmann76fcae32016-03-06 20:16:27 -080037#include <gicv2.h>
38#include <bl_common.h>
39#include <mmio.h>
Sandrine Bailleux7659a262016-07-05 09:55:03 +010040#include <utils.h>
Soren Brinkmann76fcae32016-03-06 20:16:27 -080041#include "pm_api_sys.h"
42#include "pm_client.h"
43#include "pm_ipi.h"
44#include "../zynqmp_def.h"
45
46#define OCM_BANK_0 0xFFFC0000
47#define OCM_BANK_1 (OCM_BANK_0 + 0x10000)
48#define OCM_BANK_2 (OCM_BANK_1 + 0x10000)
49#define OCM_BANK_3 (OCM_BANK_2 + 0x10000)
50
51#define UNDEFINED_CPUID (~0)
Stefan Krsmanovic2b783662016-05-20 15:51:09 +020052DEFINE_BAKERY_LOCK(pm_client_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -080053
54/* Declaration of linker defined symbol */
55extern unsigned long __BL31_END__;
56extern const struct pm_ipi apu_ipi;
57
58/* Order in pm_procs_all array must match cpu ids */
59static const struct pm_proc const pm_procs_all[] = {
60 {
61 .node_id = NODE_APU_0,
62 .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
63 .ipi = &apu_ipi,
64 },
65 {
66 .node_id = NODE_APU_1,
67 .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
68 .ipi = &apu_ipi,
69 },
70 {
71 .node_id = NODE_APU_2,
72 .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK,
73 .ipi = &apu_ipi,
74 },
75 {
76 .node_id = NODE_APU_3,
77 .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK,
78 .ipi = &apu_ipi,
79 },
80};
81
82/**
83 * set_ocm_retention() - Configure OCM memory banks for retention
84 *
85 * APU specific requirements for suspend action:
86 * OCM has to enter retention state in order to preserve saved
87 * context after suspend request. OCM banks are determined by
88 * __BL31_END__ linker symbol.
89 *
90 * Return: Returns status, either success or error+reason
91 */
92enum pm_ret_status set_ocm_retention(void)
93{
94 enum pm_ret_status ret;
95
96 /* OCM_BANK_0 will always be occupied */
97 ret = pm_set_requirement(NODE_OCM_BANK_0, PM_CAP_CONTEXT, 0,
98 REQ_ACK_NO);
99
100 /* Check for other OCM banks */
101 if ((unsigned long)&__BL31_END__ >= OCM_BANK_1)
102 ret = pm_set_requirement(NODE_OCM_BANK_1, PM_CAP_CONTEXT, 0,
103 REQ_ACK_NO);
104 if ((unsigned long)&__BL31_END__ >= OCM_BANK_2)
105 ret = pm_set_requirement(NODE_OCM_BANK_2, PM_CAP_CONTEXT, 0,
106 REQ_ACK_NO);
107 if ((unsigned long)&__BL31_END__ >= OCM_BANK_3)
108 ret = pm_set_requirement(NODE_OCM_BANK_3, PM_CAP_CONTEXT, 0,
109 REQ_ACK_NO);
110
111 return ret;
112}
113
114/**
115 * pm_get_proc() - returns pointer to the proc structure
116 * @cpuid: id of the cpu whose proc struct pointer should be returned
117 *
118 * Return: pointer to a proc structure if proc is found, otherwise NULL
119 */
120const struct pm_proc *pm_get_proc(unsigned int cpuid)
121{
122 if (cpuid < ARRAY_SIZE(pm_procs_all))
123 return &pm_procs_all[cpuid];
124
125 return NULL;
126}
127
128/**
129 * pm_get_proc_by_node() - returns pointer to the proc structure
130 * @nid: node id of the processor
131 *
132 * Return: pointer to a proc structure if proc is found, otherwise NULL
133 */
134const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid)
135{
136 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
137 if (nid == pm_procs_all[i].node_id)
138 return &pm_procs_all[i];
139 }
140 return NULL;
141}
142
143/**
144 * pm_get_cpuid() - get the local cpu ID for a global node ID
145 * @nid: node id of the processor
146 *
147 * Return: the cpu ID (starting from 0) for the subsystem
148 */
149static unsigned int pm_get_cpuid(enum pm_node_id nid)
150{
151 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
152 if (pm_procs_all[i].node_id == nid)
153 return i;
154 }
155 return UNDEFINED_CPUID;
156}
157
158const struct pm_proc *primary_proc = &pm_procs_all[0];
159
160/**
161 * pm_client_suspend() - Client-specific suspend actions
162 *
163 * This function should contain any PU-specific actions
164 * required prior to sending suspend request to PMU
165 */
166void pm_client_suspend(const struct pm_proc *proc)
167{
Stefan Krsmanovic2b783662016-05-20 15:51:09 +0200168 bakery_lock_get(&pm_client_secure_lock);
169
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800170 /* Set powerdown request */
171 mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
Stefan Krsmanovic2b783662016-05-20 15:51:09 +0200172
173 bakery_lock_release(&pm_client_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800174}
175
176
177/**
178 * pm_client_abort_suspend() - Client-specific abort-suspend actions
179 *
180 * This function should contain any PU-specific actions
181 * required for aborting a prior suspend request
182 */
183void pm_client_abort_suspend(void)
184{
185 /* Enable interrupts at processor level (for current cpu) */
186 gicv2_cpuif_enable();
Stefan Krsmanovic2b783662016-05-20 15:51:09 +0200187
188 bakery_lock_get(&pm_client_secure_lock);
189
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800190 /* Clear powerdown request */
191 mmio_write_32(APU_PWRCTL,
192 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask);
Stefan Krsmanovic2b783662016-05-20 15:51:09 +0200193
194 bakery_lock_release(&pm_client_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800195}
196
197/**
198 * pm_client_wakeup() - Client-specific wakeup actions
199 *
200 * This function should contain any PU-specific actions
201 * required for waking up another APU core
202 */
203void pm_client_wakeup(const struct pm_proc *proc)
204{
205 unsigned int cpuid = pm_get_cpuid(proc->node_id);
206
207 if (cpuid == UNDEFINED_CPUID)
208 return;
209
Stefan Krsmanovic2b783662016-05-20 15:51:09 +0200210 bakery_lock_get(&pm_client_secure_lock);
211
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800212 /* clear powerdown bit for affected cpu */
213 uint32_t val = mmio_read_32(APU_PWRCTL);
214 val &= ~(proc->pwrdn_mask);
215 mmio_write_32(APU_PWRCTL, val);
Stefan Krsmanovic2b783662016-05-20 15:51:09 +0200216
217 bakery_lock_release(&pm_client_secure_lock);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800218}