Home | History | Annotate | Download | only in fvp
      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