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