summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2016-02-23 13:39:51 +0000
committerAndre Przywara <andre.przywara@arm.com>2016-06-02 01:25:06 +0100
commitaad594b5c633b1d0cfa884ba1b7cc947f259bcaf (patch)
tree949f892f06d96df57a92728e9d707ccbe95fbc1a
parentfc1e255c846bc0a0c72c8e6f822e64e24704e136 (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.c11
-rw-r--r--plat/sun50iw1p1/plat_topology.c231
-rw-r--r--plat/sun50iw1p1/sunxi_private.h2
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);