xref: /rk3399_ARM-atf/plat/arm/board/fvp/fvp_topology.c (revision 3fc4124c7513554dc14a83a0b94010ce771e7e1c)
1*3fc4124cSDan Handley /*
2*3fc4124cSDan Handley  * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
3*3fc4124cSDan Handley  *
4*3fc4124cSDan Handley  * Redistribution and use in source and binary forms, with or without
5*3fc4124cSDan Handley  * modification, are permitted provided that the following conditions are met:
6*3fc4124cSDan Handley  *
7*3fc4124cSDan Handley  * Redistributions of source code must retain the above copyright notice, this
8*3fc4124cSDan Handley  * list of conditions and the following disclaimer.
9*3fc4124cSDan Handley  *
10*3fc4124cSDan Handley  * Redistributions in binary form must reproduce the above copyright notice,
11*3fc4124cSDan Handley  * this list of conditions and the following disclaimer in the documentation
12*3fc4124cSDan Handley  * and/or other materials provided with the distribution.
13*3fc4124cSDan Handley  *
14*3fc4124cSDan Handley  * Neither the name of ARM nor the names of its contributors may be used
15*3fc4124cSDan Handley  * to endorse or promote products derived from this software without specific
16*3fc4124cSDan Handley  * prior written permission.
17*3fc4124cSDan Handley  *
18*3fc4124cSDan Handley  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*3fc4124cSDan Handley  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*3fc4124cSDan Handley  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*3fc4124cSDan Handley  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*3fc4124cSDan Handley  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*3fc4124cSDan Handley  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*3fc4124cSDan Handley  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*3fc4124cSDan Handley  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*3fc4124cSDan Handley  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*3fc4124cSDan Handley  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*3fc4124cSDan Handley  * POSSIBILITY OF SUCH DAMAGE.
29*3fc4124cSDan Handley  */
30*3fc4124cSDan Handley 
31*3fc4124cSDan Handley #include <arch.h>
32*3fc4124cSDan Handley #include <assert.h>
33*3fc4124cSDan Handley #include <platform_def.h>
34*3fc4124cSDan Handley /* TODO: Reusing psci error codes & state information. Get our own! */
35*3fc4124cSDan Handley #include <psci.h>
36*3fc4124cSDan Handley #include "drivers/pwrc/fvp_pwrc.h"
37*3fc4124cSDan Handley #include "fvp_def.h"
38*3fc4124cSDan Handley 
39*3fc4124cSDan Handley /* We treat '255' as an invalid affinity instance */
40*3fc4124cSDan Handley #define AFFINST_INVAL	0xff
41*3fc4124cSDan Handley 
42*3fc4124cSDan Handley /*******************************************************************************
43*3fc4124cSDan Handley  * We support 3 flavours of the FVP: Foundation, Base AEM & Base Cortex. Each
44*3fc4124cSDan Handley  * flavour has a different topology. The common bit is that there can be a max.
45*3fc4124cSDan Handley  * of 2 clusters (affinity 1) and 4 cpus (affinity 0) per cluster. So we define
46*3fc4124cSDan Handley  * a tree like data structure which caters to these maximum bounds. It simply
47*3fc4124cSDan Handley  * marks the absent affinity level instances as PSCI_AFF_ABSENT e.g. there is no
48*3fc4124cSDan Handley  * cluster 1 on the Foundation FVP. The 'data' field is currently unused.
49*3fc4124cSDan Handley  ******************************************************************************/
50*3fc4124cSDan Handley typedef struct affinity_info {
51*3fc4124cSDan Handley 	unsigned char sibling;
52*3fc4124cSDan Handley 	unsigned char child;
53*3fc4124cSDan Handley 	unsigned char state;
54*3fc4124cSDan Handley 	unsigned int data;
55*3fc4124cSDan Handley } affinity_info_t;
56*3fc4124cSDan Handley 
57*3fc4124cSDan Handley /*******************************************************************************
58*3fc4124cSDan Handley  * The following two data structures store the topology tree for the fvp. There
59*3fc4124cSDan Handley  * is a separate array for each affinity level i.e. cpus and clusters. The child
60*3fc4124cSDan Handley  * and sibling references allow traversal inside and in between the two arrays.
61*3fc4124cSDan Handley  ******************************************************************************/
62*3fc4124cSDan Handley static affinity_info_t fvp_aff1_topology_map[ARM_CLUSTER_COUNT];
63*3fc4124cSDan Handley static affinity_info_t fvp_aff0_topology_map[PLATFORM_CORE_COUNT];
64*3fc4124cSDan Handley 
65*3fc4124cSDan Handley /* Simple global variable to safeguard us from stupidity */
66*3fc4124cSDan Handley static unsigned int topology_setup_done;
67*3fc4124cSDan Handley 
68*3fc4124cSDan Handley /*******************************************************************************
69*3fc4124cSDan Handley  * This function implements a part of the critical interface between the psci
70*3fc4124cSDan Handley  * generic layer and the platform to allow the former to detect the platform
71*3fc4124cSDan Handley  * topology. psci queries the platform to determine how many affinity instances
72*3fc4124cSDan Handley  * are present at a particular level for a given mpidr e.g. consider a dual
73*3fc4124cSDan Handley  * cluster platform where each cluster has 4 cpus. A call to this function with
74*3fc4124cSDan Handley  * (0, 0x100) will return the number of cpus implemented under cluster 1 i.e. 4.
75*3fc4124cSDan Handley  * Similarly a call with (1, 0x100) will return 2 i.e. the number of clusters.
76*3fc4124cSDan Handley  * This is 'cause we are effectively asking how many affinity level 1 instances
77*3fc4124cSDan Handley  * are implemented under affinity level 2 instance 0.
78*3fc4124cSDan Handley  ******************************************************************************/
79*3fc4124cSDan Handley unsigned int plat_get_aff_count(unsigned int aff_lvl,
80*3fc4124cSDan Handley 				unsigned long mpidr)
81*3fc4124cSDan Handley {
82*3fc4124cSDan Handley 	unsigned int aff_count = 1, ctr;
83*3fc4124cSDan Handley 	unsigned char parent_aff_id;
84*3fc4124cSDan Handley 
85*3fc4124cSDan Handley 	assert(topology_setup_done == 1);
86*3fc4124cSDan Handley 
87*3fc4124cSDan Handley 	switch (aff_lvl) {
88*3fc4124cSDan Handley 	case 3:
89*3fc4124cSDan Handley 	case 2:
90*3fc4124cSDan Handley 		/*
91*3fc4124cSDan Handley 		 * Assert if the parent affinity instance is not 0.
92*3fc4124cSDan Handley 		 * This also takes care of level 3 in an obfuscated way
93*3fc4124cSDan Handley 		 */
94*3fc4124cSDan Handley 		parent_aff_id = (mpidr >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK;
95*3fc4124cSDan Handley 		assert(parent_aff_id == 0);
96*3fc4124cSDan Handley 
97*3fc4124cSDan Handley 		/*
98*3fc4124cSDan Handley 		 * Report that we implement a single instance of
99*3fc4124cSDan Handley 		 * affinity levels 2 & 3 which are AFF_ABSENT
100*3fc4124cSDan Handley 		 */
101*3fc4124cSDan Handley 		break;
102*3fc4124cSDan Handley 	case 1:
103*3fc4124cSDan Handley 		/* Assert if the parent affinity instance is not 0. */
104*3fc4124cSDan Handley 		parent_aff_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
105*3fc4124cSDan Handley 		assert(parent_aff_id == 0);
106*3fc4124cSDan Handley 
107*3fc4124cSDan Handley 		/* Fetch the starting index in the aff1 array */
108*3fc4124cSDan Handley 		for (ctr = 0;
109*3fc4124cSDan Handley 		     fvp_aff1_topology_map[ctr].sibling != AFFINST_INVAL;
110*3fc4124cSDan Handley 		     ctr = fvp_aff1_topology_map[ctr].sibling) {
111*3fc4124cSDan Handley 			aff_count++;
112*3fc4124cSDan Handley 		}
113*3fc4124cSDan Handley 
114*3fc4124cSDan Handley 		break;
115*3fc4124cSDan Handley 	case 0:
116*3fc4124cSDan Handley 		/* Assert if the cluster id is anything apart from 0 or 1 */
117*3fc4124cSDan Handley 		parent_aff_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
118*3fc4124cSDan Handley 		assert(parent_aff_id < ARM_CLUSTER_COUNT);
119*3fc4124cSDan Handley 
120*3fc4124cSDan Handley 		/* Fetch the starting index in the aff0 array */
121*3fc4124cSDan Handley 		for (ctr = fvp_aff1_topology_map[parent_aff_id].child;
122*3fc4124cSDan Handley 		     fvp_aff0_topology_map[ctr].sibling != AFFINST_INVAL;
123*3fc4124cSDan Handley 		     ctr = fvp_aff0_topology_map[ctr].sibling) {
124*3fc4124cSDan Handley 			aff_count++;
125*3fc4124cSDan Handley 		}
126*3fc4124cSDan Handley 
127*3fc4124cSDan Handley 		break;
128*3fc4124cSDan Handley 	default:
129*3fc4124cSDan Handley 		assert(0);
130*3fc4124cSDan Handley 	}
131*3fc4124cSDan Handley 
132*3fc4124cSDan Handley 	return aff_count;
133*3fc4124cSDan Handley }
134*3fc4124cSDan Handley 
135*3fc4124cSDan Handley /*******************************************************************************
136*3fc4124cSDan Handley  * This function implements a part of the critical interface between the psci
137*3fc4124cSDan Handley  * generic layer and the platform to allow the former to detect the state of a
138*3fc4124cSDan Handley  * affinity instance in the platform topology. psci queries the platform to
139*3fc4124cSDan Handley  * determine whether an affinity instance is present or absent. This caters for
140*3fc4124cSDan Handley  * topologies where an intermediate affinity level instance is missing e.g.
141*3fc4124cSDan Handley  * consider a platform which implements a single cluster with 4 cpus and there
142*3fc4124cSDan Handley  * is another cpu sitting directly on the interconnect along with the cluster.
143*3fc4124cSDan Handley  * The mpidrs of the cluster would range from 0x0-0x3. The mpidr of the single
144*3fc4124cSDan Handley  * cpu would be 0x100 to highlight that it does not belong to cluster 0. Cluster
145*3fc4124cSDan Handley  * 1 is however missing but needs to be accounted to reach this single cpu in
146*3fc4124cSDan Handley  * the topology tree. Hence it will be marked as PSCI_AFF_ABSENT. This is not
147*3fc4124cSDan Handley  * applicable to the FVP but depicted as an example.
148*3fc4124cSDan Handley  ******************************************************************************/
149*3fc4124cSDan Handley unsigned int plat_get_aff_state(unsigned int aff_lvl,
150*3fc4124cSDan Handley 				unsigned long mpidr)
151*3fc4124cSDan Handley {
152*3fc4124cSDan Handley 	unsigned int aff_state = PSCI_AFF_ABSENT, idx;
153*3fc4124cSDan Handley 	idx = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
154*3fc4124cSDan Handley 
155*3fc4124cSDan Handley 	assert(topology_setup_done == 1);
156*3fc4124cSDan Handley 
157*3fc4124cSDan Handley 	switch (aff_lvl) {
158*3fc4124cSDan Handley 	case 3:
159*3fc4124cSDan Handley 	case 2:
160*3fc4124cSDan Handley 		/* Report affinity levels 2 & 3 as absent */
161*3fc4124cSDan Handley 		break;
162*3fc4124cSDan Handley 	case 1:
163*3fc4124cSDan Handley 		aff_state = fvp_aff1_topology_map[idx].state;
164*3fc4124cSDan Handley 		break;
165*3fc4124cSDan Handley 	case 0:
166*3fc4124cSDan Handley 		/*
167*3fc4124cSDan Handley 		 * First get start index of the aff0 in its array & then add
168*3fc4124cSDan Handley 		 * to it the affinity id that we want the state of
169*3fc4124cSDan Handley 		 */
170*3fc4124cSDan Handley 		idx = fvp_aff1_topology_map[idx].child;
171*3fc4124cSDan Handley 		idx += (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
172*3fc4124cSDan Handley 		aff_state = fvp_aff0_topology_map[idx].state;
173*3fc4124cSDan Handley 		break;
174*3fc4124cSDan Handley 	default:
175*3fc4124cSDan Handley 		assert(0);
176*3fc4124cSDan Handley 	}
177*3fc4124cSDan Handley 
178*3fc4124cSDan Handley 	return aff_state;
179*3fc4124cSDan Handley }
180*3fc4124cSDan Handley 
181*3fc4124cSDan Handley /*******************************************************************************
182*3fc4124cSDan Handley  * This function populates the FVP specific topology information depending upon
183*3fc4124cSDan Handley  * the FVP flavour its running on. We construct all the mpidrs we can handle
184*3fc4124cSDan Handley  * and rely on the PWRC.PSYSR to flag absent cpus when their status is queried.
185*3fc4124cSDan Handley  ******************************************************************************/
186*3fc4124cSDan Handley int plat_arm_topology_setup(void)
187*3fc4124cSDan Handley {
188*3fc4124cSDan Handley 	unsigned char aff0, aff1, aff_state, aff0_offset = 0;
189*3fc4124cSDan Handley 	unsigned long mpidr;
190*3fc4124cSDan Handley 
191*3fc4124cSDan Handley 	topology_setup_done = 0;
192*3fc4124cSDan Handley 
193*3fc4124cSDan Handley 	for (aff1 = 0; aff1 < ARM_CLUSTER_COUNT; aff1++) {
194*3fc4124cSDan Handley 
195*3fc4124cSDan Handley 		fvp_aff1_topology_map[aff1].child = aff0_offset;
196*3fc4124cSDan Handley 		fvp_aff1_topology_map[aff1].sibling = aff1 + 1;
197*3fc4124cSDan Handley 
198*3fc4124cSDan Handley 		for (aff0 = 0; aff0 < FVP_MAX_CPUS_PER_CLUSTER; aff0++) {
199*3fc4124cSDan Handley 
200*3fc4124cSDan Handley 			mpidr = aff1 << MPIDR_AFF1_SHIFT;
201*3fc4124cSDan Handley 			mpidr |= aff0 << MPIDR_AFF0_SHIFT;
202*3fc4124cSDan Handley 
203*3fc4124cSDan Handley 			if (fvp_pwrc_read_psysr(mpidr) != PSYSR_INVALID) {
204*3fc4124cSDan Handley 				/*
205*3fc4124cSDan Handley 				 * Presence of even a single aff0 indicates
206*3fc4124cSDan Handley 				 * presence of parent aff1 on the FVP.
207*3fc4124cSDan Handley 				 */
208*3fc4124cSDan Handley 				aff_state = PSCI_AFF_PRESENT;
209*3fc4124cSDan Handley 				fvp_aff1_topology_map[aff1].state =
210*3fc4124cSDan Handley 					PSCI_AFF_PRESENT;
211*3fc4124cSDan Handley 			} else {
212*3fc4124cSDan Handley 				aff_state = PSCI_AFF_ABSENT;
213*3fc4124cSDan Handley 			}
214*3fc4124cSDan Handley 
215*3fc4124cSDan Handley 			fvp_aff0_topology_map[aff0_offset].child = AFFINST_INVAL;
216*3fc4124cSDan Handley 			fvp_aff0_topology_map[aff0_offset].state = aff_state;
217*3fc4124cSDan Handley 			fvp_aff0_topology_map[aff0_offset].sibling =
218*3fc4124cSDan Handley 				aff0_offset + 1;
219*3fc4124cSDan Handley 
220*3fc4124cSDan Handley 			/* Increment the absolute number of aff0s traversed */
221*3fc4124cSDan Handley 			aff0_offset++;
222*3fc4124cSDan Handley 		}
223*3fc4124cSDan Handley 
224*3fc4124cSDan Handley 		/* Tie-off the last aff0 sibling to -1 to avoid overflow */
225*3fc4124cSDan Handley 		fvp_aff0_topology_map[aff0_offset - 1].sibling = AFFINST_INVAL;
226*3fc4124cSDan Handley 	}
227*3fc4124cSDan Handley 
228*3fc4124cSDan Handley 	/* Tie-off the last aff1 sibling to AFFINST_INVAL to avoid overflow */
229*3fc4124cSDan Handley 	fvp_aff1_topology_map[aff1 - 1].sibling = AFFINST_INVAL;
230*3fc4124cSDan Handley 
231*3fc4124cSDan Handley 	topology_setup_done = 1;
232*3fc4124cSDan Handley 	return 0;
233*3fc4124cSDan Handley }
234