xref: /rk3399_ARM-atf/plat/arm/board/fvp/fvp_topology.c (revision 31833aff6802a4b5bdc3b7007ce8b1871991e796)
1 /*
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 #include <arch.h>
32 #include <assert.h>
33 #include <platform_def.h>
34 /* TODO: Reusing psci error codes & state information. Get our own! */
35 #include <psci.h>
36 #include "drivers/pwrc/fvp_pwrc.h"
37 #include "fvp_def.h"
38 
39 /* We treat '255' as an invalid affinity instance */
40 #define AFFINST_INVAL	0xff
41 
42 /*******************************************************************************
43  * We support 3 flavours of the FVP: Foundation, Base AEM & Base Cortex. Each
44  * flavour has a different topology. The common bit is that there can be a max.
45  * of 2 clusters (affinity 1) and 4 cpus (affinity 0) per cluster. So we define
46  * a tree like data structure which caters to these maximum bounds. It simply
47  * marks the absent affinity level instances as PSCI_AFF_ABSENT e.g. there is no
48  * cluster 1 on the Foundation FVP. The 'data' field is currently unused.
49  ******************************************************************************/
50 typedef struct affinity_info {
51 	unsigned char sibling;
52 	unsigned char child;
53 	unsigned char state;
54 	unsigned int data;
55 } affinity_info_t;
56 
57 /*******************************************************************************
58  * The following two data structures store the topology tree for the fvp. There
59  * is a separate array for each affinity level i.e. cpus and clusters. The child
60  * and sibling references allow traversal inside and in between the two arrays.
61  ******************************************************************************/
62 static affinity_info_t fvp_aff1_topology_map[ARM_CLUSTER_COUNT];
63 static affinity_info_t fvp_aff0_topology_map[PLATFORM_CORE_COUNT];
64 
65 /* Simple global variable to safeguard us from stupidity */
66 static unsigned int topology_setup_done;
67 
68 /*******************************************************************************
69  * This function implements a part of the critical interface between the psci
70  * generic layer and the platform to allow the former to detect the platform
71  * topology. psci queries the platform to determine how many affinity instances
72  * are present at a particular level for a given mpidr e.g. consider a dual
73  * cluster platform where each cluster has 4 cpus. A call to this function with
74  * (0, 0x100) will return the number of cpus implemented under cluster 1 i.e. 4.
75  * Similarly a call with (1, 0x100) will return 2 i.e. the number of clusters.
76  * This is 'cause we are effectively asking how many affinity level 1 instances
77  * are implemented under affinity level 2 instance 0.
78  ******************************************************************************/
79 unsigned int plat_get_aff_count(unsigned int aff_lvl,
80 				unsigned long mpidr)
81 {
82 	unsigned int aff_count = 1, ctr;
83 	unsigned char parent_aff_id;
84 
85 	assert(topology_setup_done == 1);
86 
87 	switch (aff_lvl) {
88 	case 3:
89 	case 2:
90 		/*
91 		 * Assert if the parent affinity instance is not 0.
92 		 * This also takes care of level 3 in an obfuscated way
93 		 */
94 		parent_aff_id = (mpidr >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK;
95 		assert(parent_aff_id == 0);
96 
97 		/*
98 		 * Report that we implement a single instance of
99 		 * affinity levels 2 & 3 which are AFF_ABSENT
100 		 */
101 		break;
102 	case 1:
103 		/* Assert if the parent affinity instance is not 0. */
104 		parent_aff_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
105 		assert(parent_aff_id == 0);
106 
107 		/* Fetch the starting index in the aff1 array */
108 		for (ctr = 0;
109 		     fvp_aff1_topology_map[ctr].sibling != AFFINST_INVAL;
110 		     ctr = fvp_aff1_topology_map[ctr].sibling) {
111 			aff_count++;
112 		}
113 
114 		break;
115 	case 0:
116 		/* Assert if the cluster id is anything apart from 0 or 1 */
117 		parent_aff_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
118 		assert(parent_aff_id < ARM_CLUSTER_COUNT);
119 
120 		/* Fetch the starting index in the aff0 array */
121 		for (ctr = fvp_aff1_topology_map[parent_aff_id].child;
122 		     fvp_aff0_topology_map[ctr].sibling != AFFINST_INVAL;
123 		     ctr = fvp_aff0_topology_map[ctr].sibling) {
124 			aff_count++;
125 		}
126 
127 		break;
128 	default:
129 		assert(0);
130 	}
131 
132 	return aff_count;
133 }
134 
135 /*******************************************************************************
136  * This function implements a part of the critical interface between the psci
137  * generic layer and the platform to allow the former to detect the state of a
138  * affinity instance in the platform topology. psci queries the platform to
139  * determine whether an affinity instance is present or absent. This caters for
140  * topologies where an intermediate affinity level instance is missing e.g.
141  * consider a platform which implements a single cluster with 4 cpus and there
142  * is another cpu sitting directly on the interconnect along with the cluster.
143  * The mpidrs of the cluster would range from 0x0-0x3. The mpidr of the single
144  * cpu would be 0x100 to highlight that it does not belong to cluster 0. Cluster
145  * 1 is however missing but needs to be accounted to reach this single cpu in
146  * the topology tree. Hence it will be marked as PSCI_AFF_ABSENT. This is not
147  * applicable to the FVP but depicted as an example.
148  ******************************************************************************/
149 unsigned int plat_get_aff_state(unsigned int aff_lvl,
150 				unsigned long mpidr)
151 {
152 	unsigned int aff_state = PSCI_AFF_ABSENT, idx;
153 	idx = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
154 
155 	assert(topology_setup_done == 1);
156 
157 	switch (aff_lvl) {
158 	case 3:
159 	case 2:
160 		/* Report affinity levels 2 & 3 as absent */
161 		break;
162 	case 1:
163 		aff_state = fvp_aff1_topology_map[idx].state;
164 		break;
165 	case 0:
166 		/*
167 		 * First get start index of the aff0 in its array & then add
168 		 * to it the affinity id that we want the state of
169 		 */
170 		idx = fvp_aff1_topology_map[idx].child;
171 		idx += (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
172 		aff_state = fvp_aff0_topology_map[idx].state;
173 		break;
174 	default:
175 		assert(0);
176 	}
177 
178 	return aff_state;
179 }
180 
181 /*******************************************************************************
182  * This function populates the FVP specific topology information depending upon
183  * the FVP flavour its running on. We construct all the mpidrs we can handle
184  * and rely on the PWRC.PSYSR to flag absent cpus when their status is queried.
185  ******************************************************************************/
186 void plat_arm_topology_setup(void)
187 {
188 	unsigned char aff0, aff1, aff_state, aff0_offset = 0;
189 	unsigned long mpidr;
190 
191 	topology_setup_done = 0;
192 
193 	for (aff1 = 0; aff1 < ARM_CLUSTER_COUNT; aff1++) {
194 
195 		fvp_aff1_topology_map[aff1].child = aff0_offset;
196 		fvp_aff1_topology_map[aff1].sibling = aff1 + 1;
197 
198 		for (aff0 = 0; aff0 < FVP_MAX_CPUS_PER_CLUSTER; aff0++) {
199 
200 			mpidr = aff1 << MPIDR_AFF1_SHIFT;
201 			mpidr |= aff0 << MPIDR_AFF0_SHIFT;
202 
203 			if (fvp_pwrc_read_psysr(mpidr) != PSYSR_INVALID) {
204 				/*
205 				 * Presence of even a single aff0 indicates
206 				 * presence of parent aff1 on the FVP.
207 				 */
208 				aff_state = PSCI_AFF_PRESENT;
209 				fvp_aff1_topology_map[aff1].state =
210 					PSCI_AFF_PRESENT;
211 			} else {
212 				aff_state = PSCI_AFF_ABSENT;
213 			}
214 
215 			fvp_aff0_topology_map[aff0_offset].child = AFFINST_INVAL;
216 			fvp_aff0_topology_map[aff0_offset].state = aff_state;
217 			fvp_aff0_topology_map[aff0_offset].sibling =
218 				aff0_offset + 1;
219 
220 			/* Increment the absolute number of aff0s traversed */
221 			aff0_offset++;
222 		}
223 
224 		/* Tie-off the last aff0 sibling to -1 to avoid overflow */
225 		fvp_aff0_topology_map[aff0_offset - 1].sibling = AFFINST_INVAL;
226 	}
227 
228 	/* Tie-off the last aff1 sibling to AFFINST_INVAL to avoid overflow */
229 	fvp_aff1_topology_map[aff1 - 1].sibling = AFFINST_INVAL;
230 
231 	topology_setup_done = 1;
232 }
233