blob: eb986bca40d9006f66acd0035607612909b718e4 [file] [log] [blame]
Soren Brinkmann76fcae32016-03-06 20:16:27 -08001/*
2 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
3 *
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
36#include <gicv2.h>
37#include <bl_common.h>
38#include <mmio.h>
39#include "pm_api_sys.h"
40#include "pm_client.h"
41#include "pm_ipi.h"
42#include "../zynqmp_def.h"
43
44#define OCM_BANK_0 0xFFFC0000
45#define OCM_BANK_1 (OCM_BANK_0 + 0x10000)
46#define OCM_BANK_2 (OCM_BANK_1 + 0x10000)
47#define OCM_BANK_3 (OCM_BANK_2 + 0x10000)
48
49#define UNDEFINED_CPUID (~0)
50
51/* Declaration of linker defined symbol */
52extern unsigned long __BL31_END__;
53extern const struct pm_ipi apu_ipi;
54
55/* Order in pm_procs_all array must match cpu ids */
56static const struct pm_proc const pm_procs_all[] = {
57 {
58 .node_id = NODE_APU_0,
59 .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
60 .ipi = &apu_ipi,
61 },
62 {
63 .node_id = NODE_APU_1,
64 .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
65 .ipi = &apu_ipi,
66 },
67 {
68 .node_id = NODE_APU_2,
69 .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK,
70 .ipi = &apu_ipi,
71 },
72 {
73 .node_id = NODE_APU_3,
74 .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK,
75 .ipi = &apu_ipi,
76 },
77};
78
79/**
80 * set_ocm_retention() - Configure OCM memory banks for retention
81 *
82 * APU specific requirements for suspend action:
83 * OCM has to enter retention state in order to preserve saved
84 * context after suspend request. OCM banks are determined by
85 * __BL31_END__ linker symbol.
86 *
87 * Return: Returns status, either success or error+reason
88 */
89enum pm_ret_status set_ocm_retention(void)
90{
91 enum pm_ret_status ret;
92
93 /* OCM_BANK_0 will always be occupied */
94 ret = pm_set_requirement(NODE_OCM_BANK_0, PM_CAP_CONTEXT, 0,
95 REQ_ACK_NO);
96
97 /* Check for other OCM banks */
98 if ((unsigned long)&__BL31_END__ >= OCM_BANK_1)
99 ret = pm_set_requirement(NODE_OCM_BANK_1, PM_CAP_CONTEXT, 0,
100 REQ_ACK_NO);
101 if ((unsigned long)&__BL31_END__ >= OCM_BANK_2)
102 ret = pm_set_requirement(NODE_OCM_BANK_2, PM_CAP_CONTEXT, 0,
103 REQ_ACK_NO);
104 if ((unsigned long)&__BL31_END__ >= OCM_BANK_3)
105 ret = pm_set_requirement(NODE_OCM_BANK_3, PM_CAP_CONTEXT, 0,
106 REQ_ACK_NO);
107
108 return ret;
109}
110
111/**
112 * pm_get_proc() - returns pointer to the proc structure
113 * @cpuid: id of the cpu whose proc struct pointer should be returned
114 *
115 * Return: pointer to a proc structure if proc is found, otherwise NULL
116 */
117const struct pm_proc *pm_get_proc(unsigned int cpuid)
118{
119 if (cpuid < ARRAY_SIZE(pm_procs_all))
120 return &pm_procs_all[cpuid];
121
122 return NULL;
123}
124
125/**
126 * pm_get_proc_by_node() - returns pointer to the proc structure
127 * @nid: node id of the processor
128 *
129 * Return: pointer to a proc structure if proc is found, otherwise NULL
130 */
131const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid)
132{
133 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
134 if (nid == pm_procs_all[i].node_id)
135 return &pm_procs_all[i];
136 }
137 return NULL;
138}
139
140/**
141 * pm_get_cpuid() - get the local cpu ID for a global node ID
142 * @nid: node id of the processor
143 *
144 * Return: the cpu ID (starting from 0) for the subsystem
145 */
146static unsigned int pm_get_cpuid(enum pm_node_id nid)
147{
148 for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
149 if (pm_procs_all[i].node_id == nid)
150 return i;
151 }
152 return UNDEFINED_CPUID;
153}
154
155const struct pm_proc *primary_proc = &pm_procs_all[0];
156
157/**
158 * pm_client_suspend() - Client-specific suspend actions
159 *
160 * This function should contain any PU-specific actions
161 * required prior to sending suspend request to PMU
162 */
163void pm_client_suspend(const struct pm_proc *proc)
164{
165 /* Set powerdown request */
166 mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
167}
168
169
170/**
171 * pm_client_abort_suspend() - Client-specific abort-suspend actions
172 *
173 * This function should contain any PU-specific actions
174 * required for aborting a prior suspend request
175 */
176void pm_client_abort_suspend(void)
177{
178 /* Enable interrupts at processor level (for current cpu) */
179 gicv2_cpuif_enable();
180 /* Clear powerdown request */
181 mmio_write_32(APU_PWRCTL,
182 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask);
183}
184
185/**
186 * pm_client_wakeup() - Client-specific wakeup actions
187 *
188 * This function should contain any PU-specific actions
189 * required for waking up another APU core
190 */
191void pm_client_wakeup(const struct pm_proc *proc)
192{
193 unsigned int cpuid = pm_get_cpuid(proc->node_id);
194
195 if (cpuid == UNDEFINED_CPUID)
196 return;
197
198 /* clear powerdown bit for affected cpu */
199 uint32_t val = mmio_read_32(APU_PWRCTL);
200 val &= ~(proc->pwrdn_mask);
201 mmio_write_32(APU_PWRCTL, val);
202}