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