blob: 168864a8140f649ed479977102b1199332451514 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Dan Handley2b6b5742015-03-19 19:17:53 +00002 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
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
Dan Handley2b6b5742015-03-19 19:17:53 +000031#include <arch.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010032#include <assert.h>
Dan Handleyed6ff952014-05-14 17:44:19 +010033#include <platform_def.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010034/* TODO: Reusing psci error codes & state information. Get our own! */
35#include <psci.h>
Dan Handley4d2e49d2014-04-11 11:52:12 +010036#include "drivers/pwrc/fvp_pwrc.h"
Dan Handley2b6b5742015-03-19 19:17:53 +000037#include "fvp_def.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010038
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 ******************************************************************************/
Dan Handleye2712bc2014-04-10 15:37:22 +010050typedef struct affinity_info {
Achin Gupta4f6ad662013-10-25 09:08:21 +010051 unsigned char sibling;
52 unsigned char child;
53 unsigned char state;
54 unsigned int data;
Dan Handleye2712bc2014-04-10 15:37:22 +010055} affinity_info_t;
Achin Gupta4f6ad662013-10-25 09:08:21 +010056
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 ******************************************************************************/
Dan Handley2b6b5742015-03-19 19:17:53 +000062static affinity_info_t fvp_aff1_topology_map[ARM_CLUSTER_COUNT];
Dan Handleye2712bc2014-04-10 15:37:22 +010063static affinity_info_t fvp_aff0_topology_map[PLATFORM_CORE_COUNT];
Achin Gupta4f6ad662013-10-25 09:08:21 +010064
65/* Simple global variable to safeguard us from stupidity */
66static 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 ******************************************************************************/
79unsigned 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;
Dan Handley2b6b5742015-03-19 19:17:53 +0000118 assert(parent_aff_id < ARM_CLUSTER_COUNT);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100119
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 ******************************************************************************/
149unsigned 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/*******************************************************************************
Achin Gupta4f6ad662013-10-25 09:08:21 +0100182 * 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 ******************************************************************************/
Dan Handley2b6b5742015-03-19 19:17:53 +0000186int plat_arm_topology_setup(void)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100187{
188 unsigned char aff0, aff1, aff_state, aff0_offset = 0;
189 unsigned long mpidr;
190
191 topology_setup_done = 0;
192
Dan Handley2b6b5742015-03-19 19:17:53 +0000193 for (aff1 = 0; aff1 < ARM_CLUSTER_COUNT; aff1++) {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100194
195 fvp_aff1_topology_map[aff1].child = aff0_offset;
196 fvp_aff1_topology_map[aff1].sibling = aff1 + 1;
197
Dan Handley2b6b5742015-03-19 19:17:53 +0000198 for (aff0 = 0; aff0 < FVP_MAX_CPUS_PER_CLUSTER; aff0++) {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100199
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 return 0;
233}