diff options
author | Andre Przywara <andre.przywara@arm.com> | 2016-02-23 13:39:51 +0000 |
---|---|---|
committer | Andre Przywara <andre.przywara@arm.com> | 2016-06-02 01:25:06 +0100 |
commit | aad594b5c633b1d0cfa884ba1b7cc947f259bcaf (patch) | |
tree | 949f892f06d96df57a92728e9d707ccbe95fbc1a | |
parent | fc1e255c846bc0a0c72c8e6f822e64e24704e136 (diff) |
sun50i: simplify topology setup
The topology code was apparently copied from the ARM FVP model, which
is very versatile and allows for a sophisticated, configurable topology
setup.
Allwinner SoC on the other hand are at best multi-cluster - the A64 in
fact has only one cluster.
Simplify the sunxi specific topology code to support two affinity
levels at most - this drastically reduces the code size and makes
it much more readable.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
-rw-r--r-- | plat/sun50iw1p1/bl31_sunxi_setup.c | 11 | ||||
-rw-r--r-- | plat/sun50iw1p1/plat_topology.c | 231 | ||||
-rw-r--r-- | plat/sun50iw1p1/sunxi_private.h | 2 |
3 files changed, 28 insertions, 216 deletions
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c index dbabcf4..93a2305 100644 --- a/plat/sun50iw1p1/bl31_sunxi_setup.c +++ b/plat/sun50iw1p1/bl31_sunxi_setup.c @@ -217,18 +217,11 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, ******************************************************************************/ void bl31_platform_setup(void) { - - //unsigned int reg_val; - /* Initialize the gic cpu and distributor interfaces */ gic_setup(); - /* Intialize the power controller */ - //sunxi_pwrc_setup(); - - /* Topologies are best known to the platform. */ - sunxi_setup_topology(); - + /* Detect if this SoC is a multi-cluster one. */ + plat_setup_topology(); } /******************************************************************************* diff --git a/plat/sun50iw1p1/plat_topology.c b/plat/sun50iw1p1/plat_topology.c index 7b2426a..200d0fe 100644 --- a/plat/sun50iw1p1/plat_topology.c +++ b/plat/sun50iw1p1/plat_topology.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,226 +28,45 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <assert.h> #include <platform_def.h> -/* TODO: Reusing psci error codes & state information. Get our own! */ #include <psci.h> -/* We treat '255' as an invalid affinity instance */ -#define AFFINST_INVAL 0xff - -/******************************************************************************* - * We support 3 flavours of the FVP: Foundation, Base AEM & Base Cortex. Each - * flavour has a different topology. The common bit is that there can be a max. - * of 2 clusters (affinity 1) and 4 cpus (affinity 0) per cluster. So we define - * a tree like data structure which caters to these maximum bounds. It simply - * marks the absent affinity level instances as PSCI_AFF_ABSENT e.g. there is no - * cluster 1 on the Foundation FVP. The 'data' field is currently unused. - ******************************************************************************/ -typedef struct affinity_info { - unsigned char sibling; - unsigned char child; - unsigned char state; - unsigned int data; -} affinity_info_t; - -/******************************************************************************* - * The following two data structures store the topology tree for the fvp. There - * is a separate array for each affinity level i.e. cpus and clusters. The child - * and sibling references allow traversal inside and in between the two arrays. - ******************************************************************************/ -static affinity_info_t sunxi_aff2_topology_map[1]; -static affinity_info_t sunxi_aff1_topology_map[PLATFORM_CLUSTER_COUNT]; -static affinity_info_t sunxi_aff0_topology_map[PLATFORM_CORE_COUNT]; - -/* Simple global variable to safeguard us from stupidity */ -static unsigned int topology_setup_done; - -/******************************************************************************* - * This function implements a part of the critical interface between the psci - * generic layer and the platform to allow the former to detect the platform - * topology. psci queries the platform to determine how many affinity instances - * are present at a particular level for a given mpidr e.g. consider a dual - * cluster platform where each cluster has 4 cpus. A call to this function with - * (0, 0x100) will return the number of cpus implemented under cluster 1 i.e. 4. - * Similarly a call with (1, 0x100) will return 2 i.e. the number of clusters. - * This is 'cause we are effectively asking how many affinity level 1 instances - * are implemented under affinity level 2 instance 0. - ******************************************************************************/ -unsigned int plat_get_aff_count(unsigned int aff_lvl, - unsigned long mpidr) +unsigned int plat_get_aff_count(unsigned int aff_lvl, unsigned long mpidr) { - unsigned int aff_count = 1, ctr; - unsigned char parent_aff_id; - - assert(topology_setup_done == 1); - - switch (aff_lvl) { - case 3: - case 2: - /* - * Assert if the parent affinity instance is not 0. - * This also takes care of level 3 in an obfuscated way - */ - parent_aff_id = (mpidr >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK; - assert(parent_aff_id == 0); - - /* Fetch the starting index in the aff1 array */ - for (ctr = 0; - sunxi_aff2_topology_map[ctr].sibling != AFFINST_INVAL; - ctr = sunxi_aff2_topology_map[ctr].sibling) { - aff_count++; - } + /* Report 1 (absent) instance at levels higher that the cluster level */ + if (aff_lvl > MPIDR_AFFLVL1) + return 1; - /* - * Report that we implement a single instance of - * affinity levels 2 & 3 which are AFF_ABSENT - */ - break; - case 1: - /* Assert if the parent affinity instance is not 0. */ - parent_aff_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; - assert(parent_aff_id == 0); + if (aff_lvl == MPIDR_AFFLVL1) + return PLATFORM_CLUSTER_COUNT; - /* Fetch the starting index in the aff1 array */ - for (ctr = 0; - sunxi_aff1_topology_map[ctr].sibling != AFFINST_INVAL; - ctr = sunxi_aff1_topology_map[ctr].sibling) { - aff_count++; - } - - break; - case 0: - /* Assert if the cluster id is anything apart from 0 or 1 */ - parent_aff_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; - assert(parent_aff_id < PLATFORM_CLUSTER_COUNT); - - /* Fetch the starting index in the aff0 array */ - for (ctr = sunxi_aff1_topology_map[parent_aff_id].child; - sunxi_aff0_topology_map[ctr].sibling != AFFINST_INVAL; - ctr = sunxi_aff0_topology_map[ctr].sibling) { - aff_count++; - } - - break; - default: - assert(0); - } - - return aff_count; + return PLATFORM_MAX_CPUS_PER_CLUSTER; } -/******************************************************************************* - * This function implements a part of the critical interface between the psci - * generic layer and the platform to allow the former to detect the state of a - * affinity instance in the platform topology. psci queries the platform to - * determine whether an affinity instance is present or absent. This caters for - * topologies where an intermediate affinity level instance is missing e.g. - * consider a platform which implements a single cluster with 4 cpus and there - * is another cpu sitting directly on the interconnect along with the cluster. - * The mpidrs of the cluster would range from 0x0-0x3. The mpidr of the single - * cpu would be 0x100 to highlight that it does not belong to cluster 0. Cluster - * 1 is however missing but needs to be accounted to reach this single cpu in - * the topology tree. Hence it will be marked as PSCI_AFF_ABSENT. This is not - * applicable to the FVP but depicted as an example. - ******************************************************************************/ -unsigned int plat_get_aff_state(unsigned int aff_lvl, - unsigned long mpidr) +unsigned int plat_get_aff_state(unsigned int aff_lvl, unsigned long mpidr) { - unsigned int aff_state = PSCI_AFF_ABSENT, idx; - idx = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; - - assert(topology_setup_done == 1); - - switch (aff_lvl) { - case 3: - case 2: - aff_state = sunxi_aff2_topology_map[0].state; - /* Report affinity levels 2 & 3 as absent */ - break; - case 1: - aff_state = sunxi_aff1_topology_map[idx].state; - break; - case 0: - /* - * First get start index of the aff0 in its array & then add - * to it the affinity id that we want the state of - */ - idx = sunxi_aff1_topology_map[idx].child; - idx += (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; - aff_state = sunxi_aff0_topology_map[idx].state; - break; - default: - assert(0); - } - - return aff_state; +#if (PLATFORM_CLUSTER_COUNT == 1) + return aff_lvl <= MPIDR_AFFLVL0 ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT; +#else + return aff_lvl <= MPIDR_AFFLVL1 ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT; +#endif } -/******************************************************************************* - * Handy optimization to prevent the psci implementation from traversing through - * affinity levels which are not present while detecting the platform topology. - ******************************************************************************/ int plat_get_max_afflvl(void) { - return MPIDR_MAX_AFFLVL; +#if (PLATFORM_CLUSTER_COUNT == 1) + return MPIDR_AFFLVL0; +#else + return MPIDR_AFFLVL1; +#endif } -/******************************************************************************* - * This function populates the FVP specific topology information depending upon - * the FVP flavour its running on. We construct all the mpidrs we can handle - * and rely on the PWRC.PSYSR to flag absent cpus when their status is queried. - ******************************************************************************/ -int sunxi_setup_topology(void) +int plat_setup_topology() { - unsigned char aff0, aff1, aff_state, aff0_offset = 0; - unsigned long mpidr; - - topology_setup_done = 0; - - sunxi_aff2_topology_map[0].child = 0; - sunxi_aff2_topology_map[0].sibling = AFFINST_INVAL; - sunxi_aff2_topology_map[0].state = PSCI_AFF_PRESENT; - - - for (aff1 = 0; aff1 < PLATFORM_CLUSTER_COUNT; aff1++) { - - sunxi_aff1_topology_map[aff1].child = aff0_offset; - sunxi_aff1_topology_map[aff1].sibling = aff1 + 1; - - for (aff0 = 0; aff0 < PLATFORM_MAX_CPUS_PER_CLUSTER; aff0++) { - - mpidr = aff1 << MPIDR_AFF1_SHIFT; - mpidr |= aff0 << MPIDR_AFF0_SHIFT; - - if (1) { - /* - * Presence of even a single aff0 indicates - * presence of parent aff1 on the FVP. - */ - aff_state = PSCI_AFF_PRESENT; - sunxi_aff1_topology_map[aff1].state = - PSCI_AFF_PRESENT; - } else { - aff_state = PSCI_AFF_ABSENT; - } - - sunxi_aff0_topology_map[aff0_offset].child = AFFINST_INVAL; - sunxi_aff0_topology_map[aff0_offset].state = aff_state; - sunxi_aff0_topology_map[aff0_offset].sibling = - aff0_offset + 1; - - /* Increment the absolute number of aff0s traversed */ - aff0_offset++; - } - - /* Tie-off the last aff0 sibling to -1 to avoid overflow */ - sunxi_aff0_topology_map[aff0_offset - 1].sibling = AFFINST_INVAL; - } - - /* Tie-off the last aff1 sibling to AFFINST_INVAL to avoid overflow */ - sunxi_aff1_topology_map[aff1 - 1].sibling = AFFINST_INVAL; - - topology_setup_done = 1; + /* + * Once we see multiple cluster SoCs appearing, we can read some + * ID register here and set the number of clusters at runtime. + * For now there is nothing to do. + */ return 0; } diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h index 31e479e..82f3cfc 100644 --- a/plat/sun50iw1p1/sunxi_private.h +++ b/plat/sun50iw1p1/sunxi_private.h @@ -84,7 +84,7 @@ void sunxi_configure_mmu_el3(unsigned long total_base, int sunxi_config_setup(void); /* Declarations for sunxi_topology.c */ -int sunxi_setup_topology(void); +int plat_setup_topology(void); /* Declarations for sunxi_io_storage.c */ void sunxi_io_setup(void); |