summaryrefslogtreecommitdiff
path: root/plat/compat
diff options
context:
space:
mode:
authorSoby Mathew <soby.mathew@arm.com>2015-06-10 13:49:59 +0100
committerAchin Gupta <achin.gupta@arm.com>2015-08-13 20:08:19 +0100
commit32bc85f2d5234fbc4d1f724db3d033b8e1be5dd3 (patch)
tree3f225586e975d04f768dc3126e0544abe929f39d /plat/compat
parenteb975f52ea2e70216d214efcff3154f3cf081cb0 (diff)
PSCI: Implement platform compatibility layer
The new PSCI topology framework and PSCI extended State framework introduces a breaking change in the platform port APIs. To ease the migration of the platform ports to the new porting interface, a compatibility layer is introduced which essentially defines the new platform API in terms of the old API. The old PSCI helpers to retrieve the power-state, its associated fields and the highest coordinated physical OFF affinity level of a core are also implemented for compatibility. This allows the existing platform ports to work with the new PSCI framework without significant rework. This layer will be enabled by default once the switch to the new PSCI framework is done and is controlled by the build flag ENABLE_PLAT_COMPAT. Change-Id: I4b17cac3a4f3375910a36dba6b03d8f1700d07e3
Diffstat (limited to 'plat/compat')
-rw-r--r--plat/compat/aarch64/plat_helpers_compat.S71
-rw-r--r--plat/compat/plat_compat.mk41
-rw-r--r--plat/compat/plat_pm_compat.c337
-rw-r--r--plat/compat/plat_topology_compat.c218
4 files changed, 667 insertions, 0 deletions
diff --git a/plat/compat/aarch64/plat_helpers_compat.S b/plat/compat/aarch64/plat_helpers_compat.S
new file mode 100644
index 00000000..6d83d236
--- /dev/null
+++ b/plat/compat/aarch64/plat_helpers_compat.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 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:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .globl plat_my_core_pos
+ .globl plat_is_my_cpu_primary
+ .globl plat_get_my_entrypoint
+ .weak platform_get_core_pos
+
+ /* -----------------------------------------------------
+ * Compatibility wrappers for new platform APIs.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b platform_get_core_pos
+endfunc plat_my_core_pos
+
+func plat_is_my_cpu_primary
+ mrs x0, mpidr_el1
+ b platform_is_primary_cpu
+endfunc plat_is_my_cpu_primary
+
+func plat_get_my_entrypoint
+ mrs x0, mpidr_el1
+ b platform_get_entrypoint
+endfunc plat_get_my_entrypoint
+
+ /* -----------------------------------------------------
+ * int platform_get_core_pos(int mpidr);
+ * With this function: CorePos = (ClusterId * 4) +
+ * CoreId
+ * -----------------------------------------------------
+ */
+func platform_get_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+endfunc platform_get_core_pos
diff --git a/plat/compat/plat_compat.mk b/plat/compat/plat_compat.mk
new file mode 100644
index 00000000..c0c8ecef
--- /dev/null
+++ b/plat/compat/plat_compat.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2015, 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:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# Neither the name of ARM nor the names of its contributors may be used
+# to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+ifeq (${PSCI_EXTENDED_STATE_ID}, 1)
+ $(error "PSCI Compatibility mode can be enabled only if \
+ PSCI_EXTENDED_STATE_ID is not set")
+endif
+
+
+PLAT_BL_COMMON_SOURCES += plat/compat/aarch64/plat_helpers_compat.S
+
+BL31_SOURCES += plat/common/aarch64/plat_psci_common.c \
+ plat/compat/plat_pm_compat.c \
+ plat/compat/plat_topology_compat.c
diff --git a/plat/compat/plat_pm_compat.c b/plat/compat/plat_pm_compat.c
new file mode 100644
index 00000000..f51bb558
--- /dev/null
+++ b/plat/compat/plat_pm_compat.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2015, 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:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <errno.h>
+#include <platform.h>
+#include <psci.h>
+
+/*
+ * The platform hooks exported by the platform using the earlier version of
+ * platform interface
+ */
+const plat_pm_ops_t *pm_ops;
+
+/*
+ * The hooks exported by the compatibility layer
+ */
+static plat_psci_ops_t compat_psci_ops;
+
+/*
+ * The secure entry point to be used on warm reset.
+ */
+static unsigned long secure_entrypoint;
+
+/*
+ * This array stores the 'power_state' requests of each CPU during
+ * CPU_SUSPEND and SYSTEM_SUSPEND to support querying of state-ID
+ * by the platform.
+ */
+unsigned int psci_power_state_compat[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * The PSCI compatibility helper to parse the power state and populate the
+ * 'pwr_domain_state' for each power level. It is assumed that, when in
+ * compatibility mode, the PSCI generic layer need to know only whether the
+ * affinity level will be OFF or in RETENTION and if the platform supports
+ * multiple power down and retention states, it will be taken care within
+ * the platform layer.
+ ******************************************************************************/
+static int parse_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ int i;
+ int pstate = psci_get_pstate_type(power_state);
+ int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+
+ if (aff_lvl > PLATFORM_MAX_AFFLVL)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Sanity check the requested state */
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ /*
+ * Set the CPU local state as retention and ignore the higher
+ * levels. This allows the generic PSCI layer to invoke
+ * plat_psci_ops 'cpu_standby' hook and the compatibility
+ * layer invokes the 'affinst_standby' handler with the
+ * correct power_state parameter thus preserving the correct
+ * behavior.
+ */
+ req_state->pwr_domain_state[0] =
+ PLAT_MAX_RET_STATE;
+ } else {
+ for (i = 0; i <= aff_lvl; i++)
+ req_state->pwr_domain_state[i] =
+ PLAT_MAX_OFF_STATE;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper to set the 'power_state' in
+ * psci_power_state_compat[] at index corresponding to the current core.
+ ******************************************************************************/
+static void set_psci_power_state_compat(unsigned int power_state)
+{
+ unsigned int my_core_pos = plat_my_core_pos();
+
+ psci_power_state_compat[my_core_pos] = power_state;
+ flush_dcache_range((uintptr_t) &psci_power_state_compat[my_core_pos],
+ sizeof(psci_power_state_compat[my_core_pos]));
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'validate_power_state'
+ * hook.
+ ******************************************************************************/
+static int validate_power_state_compat(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ int rc;
+ assert(req_state);
+
+ if (pm_ops->validate_power_state) {
+ rc = pm_ops->validate_power_state(power_state);
+ if (rc != PSCI_E_SUCCESS)
+ return rc;
+ }
+
+ /* Store the 'power_state' parameter for the current CPU. */
+ set_psci_power_state_compat(power_state);
+
+ return parse_power_state(power_state, req_state);
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t
+ * 'get_sys_suspend_power_state' hook.
+ ******************************************************************************/
+void get_sys_suspend_power_state_compat(psci_power_state_t *req_state)
+{
+ unsigned int power_state;
+ assert(req_state);
+
+ power_state = pm_ops->get_sys_suspend_power_state();
+
+ /* Store the 'power_state' parameter for the current CPU. */
+ set_psci_power_state_compat(power_state);
+
+ if (parse_power_state(power_state, req_state) != PSCI_E_SUCCESS)
+ assert(0);
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'validate_ns_entrypoint'
+ * hook.
+ ******************************************************************************/
+static int validate_ns_entrypoint_compat(uintptr_t ns_entrypoint)
+{
+ return pm_ops->validate_ns_entrypoint(ns_entrypoint);
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'affinst_standby' hook.
+ ******************************************************************************/
+static void cpu_standby_compat(plat_local_state_t cpu_state)
+{
+ unsigned int powerstate = psci_get_suspend_powerstate();
+
+ assert(powerstate != PSCI_INVALID_DATA);
+
+ pm_ops->affinst_standby(powerstate);
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'affinst_on' hook.
+ ******************************************************************************/
+static int pwr_domain_on_compat(u_register_t mpidr)
+{
+ int level, rc;
+
+ /*
+ * The new PSCI framework does not hold the locks for higher level
+ * power domain nodes when this hook is invoked. Hence figuring out the
+ * target state of the parent power domains does not make much sense.
+ * Hence we hard-code the state as PSCI_STATE_OFF for all the levels.
+ * We expect the platform to perform the necessary CPU_ON operations
+ * when the 'affinst_on' is invoked only for level 0.
+ */
+ for (level = PLATFORM_MAX_AFFLVL; level >= 0; level--) {
+ rc = pm_ops->affinst_on((unsigned long)mpidr, secure_entrypoint,
+ level, PSCI_STATE_OFF);
+ if (rc != PSCI_E_SUCCESS)
+ break;
+ }
+
+ return rc;
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'affinst_off' hook.
+ ******************************************************************************/
+static void pwr_domain_off_compat(const psci_power_state_t *target_state)
+{
+ int level;
+ unsigned int plat_state;
+
+ for (level = 0; level <= PLATFORM_MAX_AFFLVL; level++) {
+ plat_state = (is_local_state_run(
+ target_state->pwr_domain_state[level]) ?
+ PSCI_STATE_ON : PSCI_STATE_OFF);
+ pm_ops->affinst_off(level, plat_state);
+ }
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'affinst_suspend' hook.
+ ******************************************************************************/
+static void pwr_domain_suspend_compat(const psci_power_state_t *target_state)
+{
+ int level;
+ unsigned int plat_state;
+
+ for (level = 0; level <= psci_get_suspend_afflvl(); level++) {
+ plat_state = (is_local_state_run(
+ target_state->pwr_domain_state[level]) ?
+ PSCI_STATE_ON : PSCI_STATE_OFF);
+ pm_ops->affinst_suspend(secure_entrypoint, level, plat_state);
+ }
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'affinst_on_finish'
+ * hook.
+ ******************************************************************************/
+static void pwr_domain_on_finish_compat(const psci_power_state_t *target_state)
+{
+ int level;
+ unsigned int plat_state;
+
+ for (level = PLATFORM_MAX_AFFLVL; level >= 0; level--) {
+ plat_state = (is_local_state_run(
+ target_state->pwr_domain_state[level]) ?
+ PSCI_STATE_ON : PSCI_STATE_OFF);
+ pm_ops->affinst_on_finish(level, plat_state);
+ }
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t
+ * 'affinst_suspend_finish' hook.
+ ******************************************************************************/
+static void pwr_domain_suspend_finish_compat(
+ const psci_power_state_t *target_state)
+{
+ int level;
+ unsigned int plat_state;
+
+ for (level = psci_get_suspend_afflvl(); level >= 0; level--) {
+ plat_state = (is_local_state_run(
+ target_state->pwr_domain_state[level]) ?
+ PSCI_STATE_ON : PSCI_STATE_OFF);
+ pm_ops->affinst_suspend_finish(level, plat_state);
+ }
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'system_off' hook.
+ ******************************************************************************/
+static void __dead2 system_off_compat(void)
+{
+ pm_ops->system_off();
+}
+
+/*******************************************************************************
+ * The PSCI compatibility helper for plat_pm_ops_t 'system_reset' hook.
+ ******************************************************************************/
+static void __dead2 system_reset_compat(void)
+{
+ pm_ops->system_reset();
+}
+
+/*******************************************************************************
+ * Export the compatibility compat_psci_ops. The assumption made is that the
+ * power domains correspond to affinity instances on the platform.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const plat_psci_ops_t **psci_ops)
+{
+ platform_setup_pm(&pm_ops);
+
+ secure_entrypoint = (unsigned long) sec_entrypoint;
+
+ /*
+ * It is compulsory for the platform ports using the new porting
+ * interface to export a hook to validate the power state parameter
+ */
+ compat_psci_ops.validate_power_state = validate_power_state_compat;
+
+ /*
+ * Populate the compatibility plat_psci_ops_t hooks if available
+ */
+ if (pm_ops->validate_ns_entrypoint)
+ compat_psci_ops.validate_ns_entrypoint =
+ validate_ns_entrypoint_compat;
+
+ if (pm_ops->affinst_standby)
+ compat_psci_ops.cpu_standby = cpu_standby_compat;
+
+ if (pm_ops->affinst_on)
+ compat_psci_ops.pwr_domain_on = pwr_domain_on_compat;
+
+ if (pm_ops->affinst_off)
+ compat_psci_ops.pwr_domain_off = pwr_domain_off_compat;
+
+ if (pm_ops->affinst_suspend)
+ compat_psci_ops.pwr_domain_suspend = pwr_domain_suspend_compat;
+
+ if (pm_ops->affinst_on_finish)
+ compat_psci_ops.pwr_domain_on_finish =
+ pwr_domain_on_finish_compat;
+
+ if (pm_ops->affinst_suspend_finish)
+ compat_psci_ops.pwr_domain_suspend_finish =
+ pwr_domain_suspend_finish_compat;
+
+ if (pm_ops->system_off)
+ compat_psci_ops.system_off = system_off_compat;
+
+ if (pm_ops->system_reset)
+ compat_psci_ops.system_reset = system_reset_compat;
+
+ if (pm_ops->get_sys_suspend_power_state)
+ compat_psci_ops.get_sys_suspend_power_state =
+ get_sys_suspend_power_state_compat;
+
+ *psci_ops = &compat_psci_ops;
+ return 0;
+}
diff --git a/plat/compat/plat_topology_compat.c b/plat/compat/plat_topology_compat.c
new file mode 100644
index 00000000..f65ad9d3
--- /dev/null
+++ b/plat/compat/plat_topology_compat.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2015, 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:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <psci.h>
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc
+ [PLATFORM_NUM_AFFS - PLATFORM_CORE_COUNT + 1];
+
+/*******************************************************************************
+ * Simple routine to set the id of an affinity instance at a given level
+ * in the mpidr. The assumption is that the affinity level and the power
+ * domain level are the same.
+ ******************************************************************************/
+unsigned long mpidr_set_aff_inst(unsigned long mpidr,
+ unsigned char aff_inst,
+ int aff_lvl)
+{
+ unsigned long aff_shift;
+
+ assert(aff_lvl <= MPIDR_AFFLVL3);
+
+ /*
+ * Decide the number of bits to shift by depending upon
+ * the power level
+ */
+ aff_shift = get_afflvl_shift(aff_lvl);
+
+ /* Clear the existing power instance & set the new one*/
+ mpidr &= ~((unsigned long)MPIDR_AFFLVL_MASK << aff_shift);
+ mpidr |= (unsigned long)aff_inst << aff_shift;
+
+ return mpidr;
+}
+
+/******************************************************************************
+ * This function uses insertion sort to sort a given list of mpidr's in the
+ * ascending order of the index returned by platform_get_core_pos.
+ *****************************************************************************/
+void sort_mpidr_by_cpu_idx(unsigned int aff_count, unsigned long mpidr_list[])
+{
+ int i, j;
+ unsigned long temp_mpidr;
+
+ for (i = 1; i < aff_count; i++) {
+ temp_mpidr = mpidr_list[i];
+
+ for (j = i;
+ j > 0 &&
+ platform_get_core_pos(mpidr_list[j-1]) >
+ platform_get_core_pos(temp_mpidr);
+ j--)
+ mpidr_list[j] = mpidr_list[j-1];
+
+ mpidr_list[j] = temp_mpidr;
+ }
+}
+
+/*******************************************************************************
+ * The compatibility routine to construct the power domain tree description.
+ * The assumption made is that the power domains correspond to affinity
+ * instances on the platform. This routine's aim is to traverse to the target
+ * affinity level and populate the number of siblings at that level in
+ * 'power_domain_tree_desc' array. It uses the current affinity level to keep
+ * track of how many levels from the root of the tree have been traversed.
+ * If the current affinity level != target affinity level, then the platform
+ * is asked to return the number of children that each affinity instance has
+ * at the current affinity level. Traversal is then done for each child at the
+ * next lower level i.e. current affinity level - 1.
+ *
+ * The power domain description needs to be constructed in such a way that
+ * affinity instances containing CPUs with lower cpu indices need to be
+ * described first. Hence when traversing the power domain levels, the list
+ * of mpidrs at that power domain level is sorted in the ascending order of CPU
+ * indices before the lower levels are recursively described.
+ *
+ * CAUTION: This routine assumes that affinity instance ids are allocated in a
+ * monotonically increasing manner at each affinity level in a mpidr starting
+ * from 0. If the platform breaks this assumption then this code will have to
+ * be reworked accordingly.
+ ******************************************************************************/
+static unsigned int init_pwr_domain_tree_desc(unsigned long mpidr,
+ unsigned int affmap_idx,
+ int cur_afflvl,
+ int tgt_afflvl)
+{
+ unsigned int ctr, aff_count;
+
+ /*
+ * Temporary list to hold the MPIDR list at a particular power domain
+ * level so as to sort them.
+ */
+ unsigned long mpidr_list[PLATFORM_CORE_COUNT];
+
+ assert(cur_afflvl >= tgt_afflvl);
+
+ /*
+ * Find the number of siblings at the current power level &
+ * assert if there are none 'cause then we have been invoked with
+ * an invalid mpidr.
+ */
+ aff_count = plat_get_aff_count(cur_afflvl, mpidr);
+ assert(aff_count);
+
+ if (tgt_afflvl < cur_afflvl) {
+ for (ctr = 0; ctr < aff_count; ctr++) {
+ mpidr_list[ctr] = mpidr_set_aff_inst(mpidr, ctr,
+ cur_afflvl);
+ }
+
+ /* Need to sort mpidr list according to CPU index */
+ sort_mpidr_by_cpu_idx(aff_count, mpidr_list);
+ for (ctr = 0; ctr < aff_count; ctr++) {
+ affmap_idx = init_pwr_domain_tree_desc(mpidr_list[ctr],
+ affmap_idx,
+ cur_afflvl - 1,
+ tgt_afflvl);
+ }
+ } else {
+ power_domain_tree_desc[affmap_idx++] = aff_count;
+ }
+ return affmap_idx;
+}
+
+
+/*******************************************************************************
+ * This function constructs the topology tree description at runtime
+ * and returns it. The assumption made is that the power domains correspond
+ * to affinity instances on the platform.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ int afflvl, affmap_idx;
+
+ /*
+ * We assume that the platform allocates affinity instance ids from
+ * 0 onwards at each affinity level in the mpidr. FIRST_MPIDR = 0.0.0.0
+ */
+ affmap_idx = 0;
+ for (afflvl = PLATFORM_MAX_AFFLVL; afflvl >= MPIDR_AFFLVL0; afflvl--) {
+ affmap_idx = init_pwr_domain_tree_desc(FIRST_MPIDR,
+ affmap_idx,
+ PLATFORM_MAX_AFFLVL,
+ afflvl);
+ }
+
+ assert(affmap_idx == (PLATFORM_NUM_AFFS - PLATFORM_CORE_COUNT + 1));
+
+ return power_domain_tree_desc;
+}
+
+/******************************************************************************
+ * The compatibility helper function for plat_core_pos_by_mpidr(). It
+ * validates the 'mpidr' by making sure that it is within acceptable bounds
+ * for the platform and queries the platform layer whether the CPU specified
+ * by the mpidr is present or not. If present, it returns the index of the
+ * core corresponding to the 'mpidr'. Else it returns -1.
+ *****************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ unsigned long shift, aff_inst;
+ int i;
+
+ /* Ignore the Reserved bits and U bit in MPIDR */
+ mpidr &= MPIDR_AFFINITY_MASK;
+
+ /*
+ * Check if any affinity field higher than
+ * the PLATFORM_MAX_AFFLVL is set.
+ */
+ shift = get_afflvl_shift(PLATFORM_MAX_AFFLVL + 1);
+ if (mpidr >> shift)
+ return -1;
+
+ for (i = PLATFORM_MAX_AFFLVL; i >= 0; i--) {
+ shift = get_afflvl_shift(i);
+ aff_inst = ((mpidr &
+ ((unsigned long)MPIDR_AFFLVL_MASK << shift)) >> shift);
+ if (aff_inst >= plat_get_aff_count(i, mpidr))
+ return -1;
+ }
+
+ if (plat_get_aff_state(0, mpidr) == PSCI_AFF_ABSENT)
+ return -1;
+
+ return platform_get_core_pos(mpidr);
+}