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