mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-15 00:54:22 +00:00
PSCI: Remove platform compatibility layer
Change-Id: I40d040aa05bcbf11536a96ce59827711456b93a8 Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com> Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
This commit is contained in:
parent
dadb16eac2
commit
871de5373d
15 changed files with 0 additions and 1504 deletions
15
Makefile
15
Makefile
|
@ -327,19 +327,6 @@ ifeq (${ARM_ARCH_MAJOR},7)
|
|||
include make_helpers/armv7-a-cpus.mk
|
||||
endif
|
||||
|
||||
# Platform compatibility is not supported in AArch32
|
||||
ifneq (${ARCH},aarch32)
|
||||
# If the platform has not defined ENABLE_PLAT_COMPAT, then enable it by default
|
||||
ifndef ENABLE_PLAT_COMPAT
|
||||
ENABLE_PLAT_COMPAT := 1
|
||||
endif
|
||||
|
||||
# Include the platform compatibility helpers for PSCI
|
||||
ifneq (${ENABLE_PLAT_COMPAT}, 0)
|
||||
include plat/compat/plat_compat.mk
|
||||
endif
|
||||
endif
|
||||
|
||||
# Include the CPU specific operations makefile, which provides default
|
||||
# values for all CPU errata workarounds and CPU specific optimisations.
|
||||
# This can be overridden by the platform.
|
||||
|
@ -586,7 +573,6 @@ $(eval $(call assert_boolean,ENABLE_AMU))
|
|||
$(eval $(call assert_boolean,ENABLE_ASSERTIONS))
|
||||
$(eval $(call assert_boolean,ENABLE_BACKTRACE))
|
||||
$(eval $(call assert_boolean,ENABLE_MPAM_FOR_LOWER_ELS))
|
||||
$(eval $(call assert_boolean,ENABLE_PLAT_COMPAT))
|
||||
$(eval $(call assert_boolean,ENABLE_PMF))
|
||||
$(eval $(call assert_boolean,ENABLE_PSCI_STAT))
|
||||
$(eval $(call assert_boolean,ENABLE_RUNTIME_INSTRUMENTATION))
|
||||
|
@ -639,7 +625,6 @@ $(eval $(call add_define,ENABLE_AMU))
|
|||
$(eval $(call add_define,ENABLE_ASSERTIONS))
|
||||
$(eval $(call add_define,ENABLE_BACKTRACE))
|
||||
$(eval $(call add_define,ENABLE_MPAM_FOR_LOWER_ELS))
|
||||
$(eval $(call add_define,ENABLE_PLAT_COMPAT))
|
||||
$(eval $(call add_define,ENABLE_PMF))
|
||||
$(eval $(call add_define,ENABLE_PSCI_STAT))
|
||||
$(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION))
|
||||
|
|
|
@ -1,608 +0,0 @@
|
|||
Guide to migrate to new Platform porting interface
|
||||
==================================================
|
||||
|
||||
|
||||
.. section-numbering::
|
||||
:suffix: .
|
||||
|
||||
.. contents::
|
||||
|
||||
--------------
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The PSCI implementation in TF-A has undergone a redesign because of three
|
||||
requirements that the PSCI 1.0 specification introduced :
|
||||
|
||||
- Removing the framework assumption about the structure of the MPIDR, and
|
||||
its relation to the power topology enables support for deeper and more
|
||||
complex hierarchies.
|
||||
|
||||
- Reworking the power state coordination implementation in the framework
|
||||
to support the more detailed PSCI 1.0 requirements and reduce platform
|
||||
port complexity
|
||||
|
||||
- Enable the use of the extended power\_state parameter and the larger StateID
|
||||
field
|
||||
|
||||
The PSCI 1.0 implementation introduces new frameworks to fulfill the above
|
||||
requirements. These framework changes mean that the platform porting API must
|
||||
also be modified. This document is a guide to assist migration of the existing
|
||||
platform ports to the new platform API.
|
||||
|
||||
This document describes the new platform API and compares it with the
|
||||
deprecated API. It also describes the compatibility layer that enables the
|
||||
existing platform ports to work with the PSCI 1.0 implementation. The
|
||||
deprecated platform API is documented for reference.
|
||||
|
||||
Platform API modification due to PSCI framework changes
|
||||
-------------------------------------------------------
|
||||
|
||||
This section describes changes to the platform APIs.
|
||||
|
||||
Power domain topology framework platform API modifications
|
||||
----------------------------------------------------------
|
||||
|
||||
This removes the assumption in the PSCI implementation that MPIDR
|
||||
based affinity instances map directly to power domains. A power domain, as
|
||||
described in section 4.2 of `PSCI`_, could contain a core or a logical group
|
||||
of cores (a cluster) which share some state on which power management
|
||||
operations can be performed. The existing affinity instance based APIs
|
||||
``plat_get_aff_count()`` and ``plat_get_aff_state()`` are deprecated. The new
|
||||
platform interfaces that are introduced for this framework are:
|
||||
|
||||
- ``plat_core_pos_by_mpidr()``
|
||||
- ``plat_my_core_pos()``
|
||||
- ``plat_get_power_domain_tree_desc()``
|
||||
|
||||
``plat_my_core_pos()`` and ``plat_core_pos_by_mpidr()`` are mandatory
|
||||
and are meant to replace the existing ``platform_get_core_pos()`` API.
|
||||
The description of these APIs can be found in the `Porting Guide`_.
|
||||
These are used by the power domain topology framework such that:
|
||||
|
||||
#. The generic PSCI code does not generate MPIDRs or use them to query the
|
||||
platform about the number of power domains at a particular power level. The
|
||||
``plat_get_power_domain_tree_desc()`` provides a description of the power
|
||||
domain tree on the SoC through a pointer to the byte array containing the
|
||||
power domain topology tree description data structure.
|
||||
|
||||
#. The linear indices returned by ``plat_core_pos_by_mpidr()`` and
|
||||
``plat_my_core_pos()`` are used to retrieve core power domain nodes from
|
||||
the power domain tree. These core indices are unique for a core and it is a
|
||||
number between ``0`` and ``PLATFORM_CORE_COUNT - 1``. The platform can choose
|
||||
to implement a static mapping between ``MPIDR`` and core index or implement
|
||||
a dynamic mapping, choosing to skip the unavailable/unused cores to compact
|
||||
the core indices.
|
||||
|
||||
In addition, the platforms must define the macros ``PLAT_NUM_PWR_DOMAINS`` and
|
||||
``PLAT_MAX_PWR_LVL`` which replace the macros ``PLAT_NUM_AFFS`` and
|
||||
``PLATFORM_MAX_AFFLVL`` respectively. On platforms where the affinity instances
|
||||
correspond to power domains, the values of new macros remain the same as the
|
||||
old ones.
|
||||
|
||||
More details on the power domain topology description and its platform
|
||||
interface can be found in `psci pd tree`_.
|
||||
|
||||
Composite power state framework platform API modifications
|
||||
----------------------------------------------------------
|
||||
|
||||
The state-ID field in the power-state parameter of a CPU\_SUSPEND call can be
|
||||
used to describe the composite power states specific to a platform. The existing
|
||||
PSCI state coordination had the limitation that it operates on a run/off
|
||||
granularity of power states and it did not interpret the state-ID field. This
|
||||
was acceptable as the specification requirement in PSCI 0.2 and the framework's
|
||||
approach to coordination only required maintaining a reference
|
||||
count of the number of cores that have requested the cluster to remain powered.
|
||||
|
||||
In the PSCI 1.0 specification, this approach is non optimal. If composite
|
||||
power states are used, the PSCI implementation cannot make global
|
||||
decisions about state coordination required because it does not understand the
|
||||
platform specific states.
|
||||
|
||||
The PSCI 1.0 implementation now defines a generic representation of the
|
||||
power-state parameter :
|
||||
|
||||
.. code:: c
|
||||
|
||||
typedef struct psci_power_state {
|
||||
plat_local_state_t pwr_domain_state[PLAT_MAX_PWR_LVL + 1];
|
||||
} psci_power_state_t;
|
||||
|
||||
``pwr_domain_state`` is an array where each index corresponds to a power level.
|
||||
Each entry in the array contains the local power state the power domain at
|
||||
that power level could enter. The meaning of the local power state value is
|
||||
platform defined, and can vary between levels in a single platform. The PSCI
|
||||
implementation constraints the values only so that it can classify the state
|
||||
as RUN, RETENTION or OFF as required by the specification:
|
||||
|
||||
#. Zero means RUN
|
||||
|
||||
#. All OFF state values at all levels must be higher than all
|
||||
RETENTION state values at all levels
|
||||
|
||||
The platform is required to define the macros ``PLAT_MAX_RET_STATE`` and
|
||||
``PLAT_MAX_OFF_STATE`` to the framework. The requirement for these macros can
|
||||
be found in the `Porting Guide <porting-guide.rst>`__.
|
||||
|
||||
The PSCI 1.0 implementation adds support to involve the platform in state
|
||||
coordination. This enables the platform to decide the final target state.
|
||||
During a request to place a power domain in a low power state, the platform
|
||||
is passed an array of requested ``plat_local_state_t`` for that power domain by
|
||||
each core within it through the ``plat_get_target_pwr_state()`` API. This API
|
||||
coordinates amongst these requested states to determine a target
|
||||
``plat_local_state_t`` for that power domain. A default weak implementation of
|
||||
this API is provided in the platform layer which returns the minimum of the
|
||||
requested local states back to the PSCI state coordination. More details
|
||||
of ``plat_get_target_pwr_state()`` API can be found in the
|
||||
`Porting Guide <porting-guide.rst#user-content-function--plat_get_target_pwr_state-optional>`__.
|
||||
|
||||
The PSCI Generic implementation expects platform ports to populate the handlers
|
||||
for the ``plat_psci_ops`` structure which is declared as :
|
||||
|
||||
.. code:: c
|
||||
|
||||
typedef struct plat_psci_ops {
|
||||
void (*cpu_standby)(plat_local_state_t cpu_state);
|
||||
int (*pwr_domain_on)(u_register_t mpidr);
|
||||
void (*pwr_domain_off)(const psci_power_state_t *target_state);
|
||||
void (*pwr_domain_suspend_early)(const psci_power_state_t *target_state);
|
||||
void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
|
||||
void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
|
||||
void (*pwr_domain_suspend_finish)(
|
||||
const psci_power_state_t *target_state);
|
||||
void (*system_off)(void) __dead2;
|
||||
void (*system_reset)(void) __dead2;
|
||||
int (*validate_power_state)(unsigned int power_state,
|
||||
psci_power_state_t *req_state);
|
||||
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
|
||||
void (*get_sys_suspend_power_state)(
|
||||
psci_power_state_t *req_state);
|
||||
int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state,
|
||||
int pwrlvl);
|
||||
int (*translate_power_state_by_mpidr)(u_register_t mpidr,
|
||||
unsigned int power_state,
|
||||
psci_power_state_t *output_state);
|
||||
int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
|
||||
int (*mem_protect_chk)(uintptr_t base, u_register_t length);
|
||||
int (*read_mem_protect)(int *val);
|
||||
int (*write_mem_protect)(int val);
|
||||
int (*system_reset2)(int is_vendor,
|
||||
int reset_type, u_register_t cookie);
|
||||
} plat_psci_ops_t;
|
||||
|
||||
The description of these handlers can be found in the `Porting Guide <porting-guide.rst#user-content-function--plat_setup_psci_ops-mandatory>`__.
|
||||
The previous ``plat_pm_ops`` structure is deprecated. Compared with the previous
|
||||
handlers, the major differences are:
|
||||
|
||||
- Difference in parameters
|
||||
|
||||
The PSCI 1.0 implementation depends on the ``validate_power_state`` handler to
|
||||
convert the power-state parameter (possibly encoding a composite power state)
|
||||
passed in a PSCI ``CPU_SUSPEND`` to the ``psci_power_state`` format. This handler
|
||||
is now mandatory for PSCI ``CPU_SUSPEND`` support.
|
||||
|
||||
The ``plat_psci_ops`` handlers, ``pwr_domain_off``, ``pwr_domain_suspend_early``
|
||||
and ``pwr_domain_suspend``, are passed the target local state for each affected
|
||||
power domain. The platform must execute operations specific to these target
|
||||
states. Similarly, ``pwr_domain_on_finish`` and ``pwr_domain_suspend_finish``
|
||||
are passed the local states of the affected power domains before wakeup. The
|
||||
platform must execute actions to restore these power domains from these specific
|
||||
local states.
|
||||
|
||||
- Difference in invocation
|
||||
|
||||
Whereas the power management handlers in ``plat_pm_ops`` used to be invoked
|
||||
for each affinity level till the target affinity level, the new handlers
|
||||
are only invoked once. The ``target_state`` encodes the target low power
|
||||
state or the low power state woken up from for each affected power domain.
|
||||
|
||||
- Difference in semantics
|
||||
|
||||
Although the previous ``suspend`` handlers could be used for power down as well
|
||||
as retention at different affinity levels, the new handlers make this support
|
||||
explicit. The ``pwr_domain_suspend`` can be used to specify powerdown and
|
||||
retention at various power domain levels subject to the conditions mentioned
|
||||
in section 4.2.1 of `PSCI`_
|
||||
|
||||
Unlike the previous ``standby`` handler, the ``cpu_standby()`` handler is only used
|
||||
as a fast path for placing a core power domain into a standby or retention
|
||||
state.
|
||||
|
||||
The below diagram shows the sequence of a PSCI SUSPEND call and the interaction
|
||||
with the platform layer depicting the exchange of data between PSCI Generic
|
||||
layer and the platform layer.
|
||||
|
||||
|Image 1|
|
||||
|
||||
Refer `plat/arm/board/fvp/fvp\_pm.c`_ for the implementation details of
|
||||
these handlers for the FVP. The commit `38dce70f51fb83b27958ba3e2ad15f5635cb1061`_
|
||||
demonstrates the migration of Arm reference platforms to the new platform API.
|
||||
|
||||
Miscellaneous modifications
|
||||
---------------------------
|
||||
|
||||
In addition to the framework changes, unification of warm reset entry points on
|
||||
wakeup from low power modes has led to a change in the platform API. In the
|
||||
earlier implementation, the warm reset entry used to be programmed into the
|
||||
mailboxes by the 'ON' and 'SUSPEND' power management hooks. In the PSCI 1.0
|
||||
implementation, this information is not required, because it can figure that
|
||||
out by querying affinity info state whether to execute the 'suspend\_finisher\`
|
||||
or 'on\_finisher'.
|
||||
|
||||
As a result, the warm reset entry point must be programmed only once. The
|
||||
``plat_setup_psci_ops()`` API takes the secure entry point as an
|
||||
additional parameter to enable the platforms to configure their mailbox. The
|
||||
plat\_psci\_ops handlers ``pwr_domain_on`` and ``pwr_domain_suspend`` no longer take
|
||||
the warm reset entry point as a parameter.
|
||||
|
||||
Also, some platform APIs which took ``MPIDR`` as an argument were only ever
|
||||
invoked to perform actions specific to the caller core which makes the argument
|
||||
redundant. Therefore the platform APIs ``plat_get_my_entrypoint()``,
|
||||
``plat_is_my_cpu_primary()``, ``plat_set_my_stack()`` and
|
||||
``plat_get_my_stack()`` are defined which are meant to be invoked only for
|
||||
operations on the current caller core instead of ``platform_get_entrypoint()``,
|
||||
``platform_is_primary_cpu()``, ``platform_set_stack()`` and ``platform_get_stack()``.
|
||||
|
||||
Compatibility layer
|
||||
-------------------
|
||||
|
||||
To ease the migration of the platform ports to the new porting interface,
|
||||
a compatibility layer is introduced that essentially implements a glue layer
|
||||
between the old platform API and the new API. The build flag
|
||||
``ENABLE_PLAT_COMPAT`` (enabled by default), specifies whether to enable this
|
||||
layer or not. A platform port which has migrated to the new API can disable
|
||||
this flag within the platform specific makefile.
|
||||
|
||||
The compatibility layer works on the assumption that the onus of
|
||||
state coordination, in case multiple low power states are supported,
|
||||
is with the platform. The generic PSCI implementation only takes into
|
||||
account whether the suspend request is power down or not. This corresponds
|
||||
with the behavior of the PSCI implementation before the introduction of
|
||||
new frameworks. Also, it assumes that the affinity levels of the platform
|
||||
correspond directly to the power domain levels.
|
||||
|
||||
The compatibility layer dynamically constructs the new topology
|
||||
description array by querying the platform using ``plat_get_aff_count()``
|
||||
and ``plat_get_aff_state()`` APIs. The linear index returned by
|
||||
``platform_get_core_pos()`` is used as the core index for the cores. The
|
||||
higher level (non-core) power domain nodes must know the cores contained
|
||||
within its domain. It does so by storing the core index of first core
|
||||
within it and number of core indexes following it. This means that core
|
||||
indices returned by ``platform_get_core_pos()`` for cores within a particular
|
||||
power domain must be consecutive. We expect that this is the case for most
|
||||
platform ports including Arm reference platforms.
|
||||
|
||||
The old PSCI helpers like ``psci_get_suspend_powerstate()``,
|
||||
``psci_get_suspend_stateid()``, ``psci_get_suspend_stateid_by_mpidr()``,
|
||||
``psci_get_max_phys_off_afflvl()`` and ``psci_get_suspend_afflvl()`` are also
|
||||
implemented for the compatibility layer. This allows the existing
|
||||
platform ports to work with the new PSCI frameworks without significant
|
||||
rework.
|
||||
|
||||
Deprecated Platform API
|
||||
-----------------------
|
||||
|
||||
This section documents the deprecated platform porting API.
|
||||
|
||||
Common mandatory modifications
|
||||
------------------------------
|
||||
|
||||
The mandatory macros to be defined by the platform port in ``platform_def.h``
|
||||
|
||||
- **#define : PLATFORM\_NUM\_AFFS**
|
||||
|
||||
Defines the total number of nodes in the affinity hierarchy at all affinity
|
||||
levels used by the platform.
|
||||
|
||||
- **#define : PLATFORM\_MAX\_AFFLVL**
|
||||
|
||||
Defines the maximum affinity level that the power management operations
|
||||
should apply to. Armv8-A has support for four affinity levels. It is likely
|
||||
that hardware will implement fewer affinity levels. This macro allows the
|
||||
PSCI implementation to consider only those affinity levels in the system
|
||||
that the platform implements. For example, the Base AEM FVP implements two
|
||||
clusters with a configurable number of cores. It reports the maximum
|
||||
affinity level as 1, resulting in PSCI power control up to the cluster
|
||||
level.
|
||||
|
||||
The following functions must be implemented by the platform port to enable
|
||||
the reset vector code to perform the required tasks.
|
||||
|
||||
Function : platform\_get\_entrypoint() [mandatory]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned long
|
||||
Return : unsigned long
|
||||
|
||||
This function is called with the ``SCTLR.M`` and ``SCTLR.C`` bits disabled. The core
|
||||
is identified by its ``MPIDR``, which is passed as the argument. The function is
|
||||
responsible for distinguishing between a warm and cold reset using platform-
|
||||
specific means. If it is a warm reset, it returns the entrypoint into the
|
||||
BL31 image that the core must jump to. If it is a cold reset, this function
|
||||
must return zero.
|
||||
|
||||
This function is also responsible for implementing a platform-specific mechanism
|
||||
to handle the condition where the core has been warm reset but there is no
|
||||
entrypoint to jump to.
|
||||
|
||||
This function does not follow the Procedure Call Standard used by the
|
||||
Application Binary Interface for the Arm 64-bit architecture. The caller should
|
||||
not assume that callee saved registers are preserved across a call to this
|
||||
function.
|
||||
|
||||
Function : platform\_is\_primary\_cpu() [mandatory]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned long
|
||||
Return : unsigned int
|
||||
|
||||
This function identifies a core by its ``MPIDR``, which is passed as the argument,
|
||||
to determine whether this core is the primary core or a secondary core. A return
|
||||
value of zero indicates that the core is not the primary core, while a non-zero
|
||||
return value indicates that the core is the primary core.
|
||||
|
||||
Common optional modifications
|
||||
-----------------------------
|
||||
|
||||
Function : platform\_get\_core\_pos()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned long
|
||||
Return : int
|
||||
|
||||
A platform may need to convert the ``MPIDR`` of a core to an absolute number, which
|
||||
can be used as a core-specific linear index into blocks of memory (for example
|
||||
while allocating per-core stacks). This routine contains a simple mechanism
|
||||
to perform this conversion, using the assumption that each cluster contains a
|
||||
maximum of four cores:
|
||||
|
||||
::
|
||||
|
||||
linear index = cpu_id + (cluster_id * 4)
|
||||
|
||||
cpu_id = 8-bit value in MPIDR at affinity level 0
|
||||
cluster_id = 8-bit value in MPIDR at affinity level 1
|
||||
|
||||
Function : platform\_set\_stack()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned long
|
||||
Return : void
|
||||
|
||||
This function sets the current stack pointer to the normal memory stack that
|
||||
has been allocated for the core specified by MPIDR. For BL images that only
|
||||
require a stack for the primary core the parameter is ignored. The size of
|
||||
the stack allocated to each core is specified by the platform defined constant
|
||||
``PLATFORM_STACK_SIZE``.
|
||||
|
||||
Common implementations of this function for the UP and MP BL images are
|
||||
provided in `plat/common/aarch64/platform\_up\_stack.S`_ and
|
||||
`plat/common/aarch64/platform\_mp\_stack.S`_
|
||||
|
||||
Function : platform\_get\_stack()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned long
|
||||
Return : unsigned long
|
||||
|
||||
This function returns the base address of the normal memory stack that
|
||||
has been allocated for the core specificed by MPIDR. For BL images that only
|
||||
require a stack for the primary core the parameter is ignored. The size of
|
||||
the stack allocated to each core is specified by the platform defined constant
|
||||
``PLATFORM_STACK_SIZE``.
|
||||
|
||||
Common implementations of this function for the UP and MP BL images are
|
||||
provided in `plat/common/aarch64/platform\_up\_stack.S`_ and
|
||||
`plat/common/aarch64/platform\_mp\_stack.S`_
|
||||
|
||||
Modifications for Power State Coordination Interface (in BL31)
|
||||
--------------------------------------------------------------
|
||||
|
||||
The following functions must be implemented to initialize PSCI functionality in
|
||||
TF-A.
|
||||
|
||||
Function : plat\_get\_aff\_count() [mandatory]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned int, unsigned long
|
||||
Return : unsigned int
|
||||
|
||||
This function may execute with the MMU and data caches enabled if the platform
|
||||
port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only
|
||||
called by the primary core.
|
||||
|
||||
This function is called by the PSCI initialization code to detect the system
|
||||
topology. Its purpose is to return the number of affinity instances implemented
|
||||
at a given ``affinity level`` (specified by the first argument) and a given
|
||||
``MPIDR`` (specified by the second argument). For example, on a dual-cluster
|
||||
system where first cluster implements two cores and the second cluster
|
||||
implements four cores, a call to this function with an ``MPIDR`` corresponding
|
||||
to the first cluster (``0x0``) and affinity level 0, would return 2. A call
|
||||
to this function with an ``MPIDR`` corresponding to the second cluster (``0x100``)
|
||||
and affinity level 0, would return 4.
|
||||
|
||||
Function : plat\_get\_aff\_state() [mandatory]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned int, unsigned long
|
||||
Return : unsigned int
|
||||
|
||||
This function may execute with the MMU and data caches enabled if the platform
|
||||
port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only
|
||||
called by the primary core.
|
||||
|
||||
This function is called by the PSCI initialization code. Its purpose is to
|
||||
return the state of an affinity instance. The affinity instance is determined by
|
||||
the affinity ID at a given ``affinity level`` (specified by the first argument)
|
||||
and an ``MPIDR`` (specified by the second argument). The state can be one of
|
||||
``PSCI_AFF_PRESENT`` or ``PSCI_AFF_ABSENT``. The latter state is used to cater for
|
||||
system topologies where certain affinity instances are unimplemented. For
|
||||
example, consider a platform that implements a single cluster with four cores and
|
||||
another core implemented directly on the interconnect with the cluster. The
|
||||
``MPIDR``\ s of the cluster would range from ``0x0-0x3``. The ``MPIDR`` of the single
|
||||
core is 0x100 to indicate that it does not belong to cluster 0. Cluster 1
|
||||
is missing but needs to be accounted for to reach this single core in the
|
||||
topology tree. Therefore it is marked as ``PSCI_AFF_ABSENT``.
|
||||
|
||||
Function : platform\_setup\_pm() [mandatory]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : const plat_pm_ops **
|
||||
Return : int
|
||||
|
||||
This function may execute with the MMU and data caches enabled if the platform
|
||||
port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only
|
||||
called by the primary core.
|
||||
|
||||
This function is called by PSCI initialization code. Its purpose is to export
|
||||
handler routines for platform-specific power management actions by populating
|
||||
the passed pointer with a pointer to the private ``plat_pm_ops`` structure of
|
||||
BL31.
|
||||
|
||||
A description of each member of this structure is given below. A platform port
|
||||
is expected to implement these handlers if the corresponding PSCI operation
|
||||
is to be supported and these handlers are expected to succeed if the return
|
||||
type is ``void``.
|
||||
|
||||
plat\_pm\_ops.affinst\_standby()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Perform the platform-specific setup to enter the standby state indicated by the
|
||||
passed argument. The generic code expects the handler to succeed.
|
||||
|
||||
plat\_pm\_ops.affinst\_on()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Perform the platform specific setup to power on an affinity instance, specified
|
||||
by the ``MPIDR`` (first argument) and ``affinity level`` (third argument). The
|
||||
``state`` (fourth argument) contains the current state of that affinity instance
|
||||
(ON or OFF). This is useful to determine whether any action must be taken. For
|
||||
example, while powering on a core, the cluster that contains this core might
|
||||
already be in the ON state. The platform decides what actions must be taken to
|
||||
transition from the current state to the target state (indicated by the power
|
||||
management operation). The generic code expects the platform to return
|
||||
E\_SUCCESS on success or E\_INTERN\_FAIL for any failure.
|
||||
|
||||
plat\_pm\_ops.affinst\_off()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Perform the platform specific setup to power off an affinity instance of the
|
||||
calling core. It is called by the PSCI ``CPU_OFF`` API implementation.
|
||||
|
||||
The ``affinity level`` (first argument) and ``state`` (second argument) have
|
||||
a similar meaning as described in the ``affinst_on()`` operation. They
|
||||
identify the affinity instance on which the call is made and its
|
||||
current state. This gives the platform port an indication of the
|
||||
state transition it must make to perform the requested action. For example, if
|
||||
the calling core is the last powered on core in the cluster, after powering down
|
||||
affinity level 0 (the core), the platform port should power down affinity
|
||||
level 1 (the cluster) as well. The generic code expects the handler to succeed.
|
||||
|
||||
plat\_pm\_ops.affinst\_suspend()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Perform the platform specific setup to power off an affinity instance of the
|
||||
calling core. It is called by the PSCI ``CPU_SUSPEND`` API and ``SYSTEM_SUSPEND``
|
||||
API implementation
|
||||
|
||||
The ``affinity level`` (second argument) and ``state`` (third argument) have a
|
||||
similar meaning as described in the ``affinst_on()`` operation. They are used to
|
||||
identify the affinity instance on which the call is made and its current state.
|
||||
This gives the platform port an indication of the state transition it must
|
||||
make to perform the requested action. For example, if the calling core is the
|
||||
last powered on core in the cluster, after powering down affinity level 0
|
||||
(the core), the platform port should power down affinity level 1 (the cluster)
|
||||
as well.
|
||||
|
||||
The difference between turning an affinity instance off and suspending it
|
||||
is that in the former case, the affinity instance is expected to re-initialize
|
||||
its state when it is next powered on (see ``affinst_on_finish()``). In the latter
|
||||
case, the affinity instance is expected to save enough state so that it can
|
||||
resume execution by restoring this state when it is powered on (see
|
||||
``affinst_suspend_finish()``).The generic code expects the handler to succeed.
|
||||
|
||||
plat\_pm\_ops.affinst\_on\_finish()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This function is called by the PSCI implementation after the calling core is
|
||||
powered on and released from reset in response to an earlier PSCI ``CPU_ON`` call.
|
||||
It performs the platform-specific setup required to initialize enough state for
|
||||
this core to enter the Normal world and also provide secure runtime firmware
|
||||
services.
|
||||
|
||||
The ``affinity level`` (first argument) and ``state`` (second argument) have a
|
||||
similar meaning as described in the previous operations. The generic code
|
||||
expects the handler to succeed.
|
||||
|
||||
plat\_pm\_ops.affinst\_suspend\_finish()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This function is called by the PSCI implementation after the calling core is
|
||||
powered on and released from reset in response to an asynchronous wakeup
|
||||
event, for example a timer interrupt that was programmed by the core during the
|
||||
``CPU_SUSPEND`` call or ``SYSTEM_SUSPEND`` call. It performs the platform-specific
|
||||
setup required to restore the saved state for this core to resume execution
|
||||
in the Normal world and also provide secure runtime firmware services.
|
||||
|
||||
The ``affinity level`` (first argument) and ``state`` (second argument) have a
|
||||
similar meaning as described in the previous operations. The generic code
|
||||
expects the platform to succeed.
|
||||
|
||||
plat\_pm\_ops.validate\_power\_state()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This function is called by the PSCI implementation during the ``CPU_SUSPEND``
|
||||
call to validate the ``power_state`` parameter of the PSCI API. If the
|
||||
``power_state`` is known to be invalid, the platform must return
|
||||
PSCI\_E\_INVALID\_PARAMS as an error, which is propagated back to the Normal
|
||||
world PSCI client.
|
||||
|
||||
plat\_pm\_ops.validate\_ns\_entrypoint()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This function is called by the PSCI implementation during the ``CPU_SUSPEND``,
|
||||
``SYSTEM_SUSPEND`` and ``CPU_ON`` calls to validate the Non-secure ``entry_point``
|
||||
parameter passed by the Normal world. If the ``entry_point`` is known to be
|
||||
invalid, the platform must return PSCI\_E\_INVALID\_PARAMS as an error, which is
|
||||
propagated back to the Normal world PSCI client.
|
||||
|
||||
plat\_pm\_ops.get\_sys\_suspend\_power\_state()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This function is called by the PSCI implementation during the ``SYSTEM_SUSPEND``
|
||||
call to return the ``power_state`` parameter. This allows the platform to encode
|
||||
the appropriate State-ID field within the ``power_state`` parameter which can be
|
||||
utilized in ``affinst_suspend()`` to suspend to system affinity level. The
|
||||
``power_state`` parameter should be in the same format as specified by the
|
||||
PSCI specification for the CPU\_SUSPEND API.
|
||||
|
||||
--------------
|
||||
|
||||
*Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.*
|
||||
|
||||
.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
|
||||
.. _Porting Guide: porting-guide.rst#user-content-function--plat_my_core_pos
|
||||
.. _psci pd tree: psci-pd-tree.rst
|
||||
.. _plat/arm/board/fvp/fvp\_pm.c: ../plat/arm/board/fvp/fvp_pm.c
|
||||
.. _38dce70f51fb83b27958ba3e2ad15f5635cb1061: https://github.com/ARM-software/arm-trusted-firmware/commit/38dce70f51fb83b27958ba3e2ad15f5635cb1061
|
||||
.. _plat/common/aarch64/platform\_up\_stack.S: ../plat/common/aarch64/platform_up_stack.S
|
||||
.. _plat/common/aarch64/platform\_mp\_stack.S: ../plat/common/aarch64/platform_mp_stack.S
|
||||
|
||||
.. |Image 1| image:: diagrams/psci-suspend-sequence.png?raw=true
|
|
@ -12,10 +12,6 @@ Trusted Firmware-A Porting Guide
|
|||
Introduction
|
||||
------------
|
||||
|
||||
Please note that this document has been updated for the new platform API
|
||||
as required by the PSCI v1.0 implementation. Please refer to the
|
||||
`Migration Guide`_ for the previous platform API.
|
||||
|
||||
Porting Trusted Firmware-A (TF-A) to a new platform involves making some
|
||||
mandatory and optional modifications for both the cold and warm boot paths.
|
||||
Modifications consist of:
|
||||
|
@ -2976,12 +2972,6 @@ The default implementation of this function calls
|
|||
Build flags
|
||||
-----------
|
||||
|
||||
- **ENABLE\_PLAT\_COMPAT**
|
||||
All the platforms ports conforming to this API specification should define
|
||||
the build flag ``ENABLE_PLAT_COMPAT`` to 0 as the compatibility layer should
|
||||
be disabled. For more details on compatibility layer, refer
|
||||
`Migration Guide`_.
|
||||
|
||||
There are some build flags which can be defined by the platform to control
|
||||
inclusion or exclusion of certain BL stages from the FIP image. These flags
|
||||
need to be defined in the platform makefile which will get included by the
|
||||
|
@ -3067,7 +3057,6 @@ amount of open resources per driver.
|
|||
|
||||
*Copyright (c) 2013-2018, Arm Limited and Contributors. All rights reserved.*
|
||||
|
||||
.. _Migration Guide: platform-migration-guide.rst
|
||||
.. _include/plat/common/platform.h: ../include/plat/common/platform.h
|
||||
.. _include/plat/arm/common/plat\_arm.h: ../include/plat/arm/common/plat_arm.h%5D
|
||||
.. _User Guide: user-guide.rst
|
||||
|
|
|
@ -110,23 +110,6 @@
|
|||
end_vector_entry \since
|
||||
.endm
|
||||
|
||||
#if ENABLE_PLAT_COMPAT
|
||||
/*
|
||||
* This macro calculates the base address of an MP stack using the
|
||||
* platform_get_core_pos() index, the name of the stack storage and
|
||||
* the size of each stack
|
||||
* In: X0 = MPIDR of CPU whose stack is wanted
|
||||
* Out: X0 = physical address of stack base
|
||||
* Clobber: X30, X1, X2
|
||||
*/
|
||||
.macro get_mp_stack _name, _size
|
||||
bl platform_get_core_pos
|
||||
ldr x2, =(\_name + \_size)
|
||||
mov x1, #\_size
|
||||
madd x0, x0, x1, x2
|
||||
.endm
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This macro calculates the base address of the current CPU's MP stack
|
||||
* using the plat_my_core_pos() index, the name of the stack storage
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
#include <bakery_lock.h>
|
||||
#include <bl_common.h>
|
||||
#include <platform_def.h> /* for PLAT_NUM_PWR_DOMAINS */
|
||||
#if ENABLE_PLAT_COMPAT
|
||||
#include <psci_compat.h>
|
||||
#endif
|
||||
#include <psci_lib.h> /* To maintain compatibility for SPDs */
|
||||
#include <utils_def.h>
|
||||
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef PSCI_COMPAT_H
|
||||
#define PSCI_COMPAT_H
|
||||
|
||||
#include <arch.h>
|
||||
#include <platform_def.h>
|
||||
#include <utils_def.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* The below declarations are to enable compatibility for the platform ports
|
||||
* using the old platform interface and psci helpers.
|
||||
*/
|
||||
#define PLAT_MAX_PWR_LVL PLATFORM_MAX_AFFLVL
|
||||
#define PLAT_NUM_PWR_DOMAINS PLATFORM_NUM_AFFS
|
||||
|
||||
/*******************************************************************************
|
||||
* PSCI affinity related constants. An affinity instance could
|
||||
* be present or absent physically to cater for asymmetric topologies.
|
||||
******************************************************************************/
|
||||
#define PSCI_AFF_ABSENT 0x0
|
||||
#define PSCI_AFF_PRESENT 0x1
|
||||
|
||||
#define PSCI_STATE_ON U(0x0)
|
||||
#define PSCI_STATE_OFF U(0x1)
|
||||
#define PSCI_STATE_ON_PENDING U(0x2)
|
||||
#define PSCI_STATE_SUSPEND U(0x3)
|
||||
|
||||
/*
|
||||
* Using the compatibility platform interfaces means that the local states
|
||||
* used in psci_power_state_t need to only convey whether its power down
|
||||
* or standby state. The onus is on the platform port to do the right thing
|
||||
* including the state coordination in case multiple power down states are
|
||||
* involved. Hence if we assume 3 generic states viz, run, standby and
|
||||
* power down, we can assign 1 and 2 to standby and power down respectively.
|
||||
*/
|
||||
#define PLAT_MAX_RET_STATE U(1)
|
||||
#define PLAT_MAX_OFF_STATE U(2)
|
||||
|
||||
/*
|
||||
* Macro to represent invalid affinity level within PSCI.
|
||||
*/
|
||||
#define PSCI_INVALID_DATA -1
|
||||
|
||||
#define psci_get_pstate_afflvl(pstate) psci_get_pstate_pwrlvl(pstate)
|
||||
|
||||
/*
|
||||
* This array stores the 'power_state' requests of each CPU during
|
||||
* CPU_SUSPEND and SYSTEM_SUSPEND which will be populated by the
|
||||
* compatibility layer when appropriate platform hooks are invoked.
|
||||
*/
|
||||
extern unsigned int psci_power_state_compat[PLATFORM_CORE_COUNT];
|
||||
|
||||
/*******************************************************************************
|
||||
* Structure populated by platform specific code to export routines which
|
||||
* perform common low level pm functions
|
||||
******************************************************************************/
|
||||
typedef struct plat_pm_ops {
|
||||
void (*affinst_standby)(unsigned int power_state);
|
||||
int (*affinst_on)(unsigned long mpidr,
|
||||
unsigned long sec_entrypoint,
|
||||
unsigned int afflvl,
|
||||
unsigned int state);
|
||||
void (*affinst_off)(unsigned int afflvl, unsigned int state);
|
||||
void (*affinst_suspend)(unsigned long sec_entrypoint,
|
||||
unsigned int afflvl,
|
||||
unsigned int state);
|
||||
void (*affinst_on_finish)(unsigned int afflvl, unsigned int state);
|
||||
void (*affinst_suspend_finish)(unsigned int afflvl,
|
||||
unsigned int state);
|
||||
void (*system_off)(void) __dead2;
|
||||
void (*system_reset)(void) __dead2;
|
||||
int (*validate_power_state)(unsigned int power_state);
|
||||
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
|
||||
unsigned int (*get_sys_suspend_power_state)(void);
|
||||
} plat_pm_ops_t;
|
||||
|
||||
/*******************************************************************************
|
||||
* Function & Data prototypes to enable compatibility for older platform ports
|
||||
******************************************************************************/
|
||||
int psci_get_suspend_stateid_by_mpidr(unsigned long);
|
||||
int psci_get_suspend_stateid(void);
|
||||
int psci_get_suspend_powerstate(void);
|
||||
unsigned int psci_get_max_phys_off_afflvl(void);
|
||||
int psci_get_suspend_afflvl(void);
|
||||
|
||||
#endif /* ____ASSEMBLY__ */
|
||||
#endif /* PSCI_COMPAT_H */
|
|
@ -370,34 +370,11 @@ void plat_flush_next_bl_params(void);
|
|||
|
||||
#endif /* LOAD_IMAGE_V2 */
|
||||
|
||||
#if ENABLE_PLAT_COMPAT
|
||||
/*
|
||||
* The below declarations are to enable compatibility for the platform ports
|
||||
* using the old platform interface.
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* Optional common functions (may be overridden)
|
||||
******************************************************************************/
|
||||
unsigned int platform_get_core_pos(unsigned long mpidr);
|
||||
|
||||
/*******************************************************************************
|
||||
* Mandatory PSCI Compatibility functions (BL31)
|
||||
******************************************************************************/
|
||||
int platform_setup_pm(const plat_pm_ops_t **);
|
||||
|
||||
unsigned int plat_get_aff_count(unsigned int, unsigned long);
|
||||
unsigned int plat_get_aff_state(unsigned int, unsigned long);
|
||||
|
||||
#else /* __ENABLE_PLAT_COMPAT__ */
|
||||
/*
|
||||
* The below function enable Trusted Firmware components like SPDs which
|
||||
* haven't migrated to the new platform API to compile on platforms which
|
||||
* have the compatibility layer disabled.
|
||||
*/
|
||||
unsigned int platform_core_pos_helper(unsigned long mpidr);
|
||||
unsigned int platform_get_core_pos(unsigned long mpidr) __deprecated;
|
||||
|
||||
#endif /* __ENABLE_PLAT_COMPAT__ */
|
||||
|
||||
#endif /* PLATFORM_H */
|
||||
|
|
|
@ -938,84 +938,6 @@ int psci_secondaries_brought_up(void)
|
|||
return (n_valid > 1U) ? 1 : 0;
|
||||
}
|
||||
|
||||
#if ENABLE_PLAT_COMPAT
|
||||
/*******************************************************************************
|
||||
* PSCI Compatibility helper function to return the 'power_state' parameter of
|
||||
* the PSCI CPU SUSPEND request for the current CPU. Returns PSCI_INVALID_DATA
|
||||
* if not invoked within CPU_SUSPEND for the current CPU.
|
||||
******************************************************************************/
|
||||
int psci_get_suspend_powerstate(void)
|
||||
{
|
||||
/* Sanity check to verify that CPU is within CPU_SUSPEND */
|
||||
if (psci_get_aff_info_state() == AFF_STATE_ON &&
|
||||
!is_local_state_run(psci_get_cpu_local_state()))
|
||||
return psci_power_state_compat[plat_my_core_pos()];
|
||||
|
||||
return PSCI_INVALID_DATA;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PSCI Compatibility helper function to return the state id of the current
|
||||
* cpu encoded in the 'power_state' parameter. Returns PSCI_INVALID_DATA
|
||||
* if not invoked within CPU_SUSPEND for the current CPU.
|
||||
******************************************************************************/
|
||||
int psci_get_suspend_stateid(void)
|
||||
{
|
||||
unsigned int power_state;
|
||||
power_state = psci_get_suspend_powerstate();
|
||||
if (power_state != PSCI_INVALID_DATA)
|
||||
return psci_get_pstate_id(power_state);
|
||||
|
||||
return PSCI_INVALID_DATA;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PSCI Compatibility helper function to return the state id encoded in the
|
||||
* 'power_state' parameter of the CPU specified by 'mpidr'. Returns
|
||||
* PSCI_INVALID_DATA if the CPU is not in CPU_SUSPEND.
|
||||
******************************************************************************/
|
||||
int psci_get_suspend_stateid_by_mpidr(unsigned long mpidr)
|
||||
{
|
||||
int cpu_idx = plat_core_pos_by_mpidr(mpidr);
|
||||
|
||||
if (cpu_idx == -1)
|
||||
return PSCI_INVALID_DATA;
|
||||
|
||||
/* Sanity check to verify that the CPU is in CPU_SUSPEND */
|
||||
if ((psci_get_aff_info_state_by_idx(cpu_idx) == AFF_STATE_ON) &&
|
||||
(!is_local_state_run(psci_get_cpu_local_state_by_idx(cpu_idx))))
|
||||
return psci_get_pstate_id(psci_power_state_compat[cpu_idx]);
|
||||
|
||||
return PSCI_INVALID_DATA;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns highest affinity level which is in OFF
|
||||
* state. The affinity instance with which the level is associated is
|
||||
* determined by the caller.
|
||||
******************************************************************************/
|
||||
unsigned int psci_get_max_phys_off_afflvl(void)
|
||||
{
|
||||
psci_power_state_t state_info;
|
||||
|
||||
zeromem(&state_info, sizeof(state_info));
|
||||
psci_get_target_local_pwr_states(PLAT_MAX_PWR_LVL, &state_info);
|
||||
|
||||
return psci_find_target_suspend_lvl(&state_info);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PSCI Compatibility helper function to return target affinity level requested
|
||||
* for the CPU_SUSPEND. This function assumes affinity levels correspond to
|
||||
* power domain levels on the platform.
|
||||
******************************************************************************/
|
||||
int psci_get_suspend_afflvl(void)
|
||||
{
|
||||
return psci_get_suspend_pwrlvl();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Initiate power down sequence, by calling power down operations registered for
|
||||
* this CPU.
|
||||
|
|
|
@ -40,7 +40,6 @@ void bl31_plat_runtime_setup(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if !ENABLE_PLAT_COMPAT
|
||||
/*
|
||||
* Helper function for platform_get_pos() when platform compatibility is
|
||||
* disabled. This is to enable SPDs using the older platform API to continue
|
||||
|
@ -52,8 +51,6 @@ unsigned int platform_core_pos_helper(unsigned long mpidr)
|
|||
assert(idx >= 0);
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !ERROR_DEPRECATED
|
||||
unsigned int plat_get_syscnt_freq2(void)
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
.weak plat_handle_double_fault
|
||||
.weak plat_handle_el3_ea
|
||||
|
||||
#if !ENABLE_PLAT_COMPAT
|
||||
.globl platform_get_core_pos
|
||||
|
||||
#define MPIDR_RES_BIT_MASK 0xff000000
|
||||
|
@ -49,7 +48,6 @@ func_deprecated platform_get_core_pos
|
|||
beq plat_my_core_pos
|
||||
b platform_core_pos_helper
|
||||
endfunc_deprecated platform_get_core_pos
|
||||
#endif
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* Placeholder function which should be redefined by
|
||||
|
|
|
@ -10,81 +10,11 @@
|
|||
#include <platform_def.h>
|
||||
|
||||
.local platform_normal_stacks
|
||||
#if ENABLE_PLAT_COMPAT
|
||||
.globl plat_get_my_stack
|
||||
.globl plat_set_my_stack
|
||||
.weak platform_get_stack
|
||||
.weak platform_set_stack
|
||||
#else
|
||||
.weak plat_get_my_stack
|
||||
.weak plat_set_my_stack
|
||||
.globl platform_get_stack
|
||||
.globl platform_set_stack
|
||||
#endif /* __ENABLE_PLAT_COMPAT__ */
|
||||
|
||||
#if ENABLE_PLAT_COMPAT
|
||||
/* ---------------------------------------------------------------------
|
||||
* When the compatility layer is enabled, the new platform APIs
|
||||
* viz plat_get_my_stack() and plat_set_my_stack() need to be
|
||||
* defined using the previous APIs platform_get_stack() and
|
||||
* platform_set_stack(). Also we need to provide weak definitions
|
||||
* of platform_get_stack() and platform_set_stack() for the platforms
|
||||
* to reuse.
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* unsigned long plat_get_my_stack ()
|
||||
*
|
||||
* For the current CPU, this function returns the stack
|
||||
* pointer for a stack allocated in device memory.
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
func plat_get_my_stack
|
||||
mrs x0, mpidr_el1
|
||||
b platform_get_stack
|
||||
endfunc plat_get_my_stack
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* void plat_set_my_stack ()
|
||||
*
|
||||
* For the current CPU, this function sets the stack
|
||||
* pointer to a stack allocated in normal memory.
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
func plat_set_my_stack
|
||||
mrs x0, mpidr_el1
|
||||
b platform_set_stack
|
||||
endfunc plat_set_my_stack
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* unsigned long platform_get_stack (unsigned long mpidr)
|
||||
*
|
||||
* For a given CPU, this function returns the stack
|
||||
* pointer for a stack allocated in device memory.
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
func platform_get_stack
|
||||
mov x10, x30 // lr
|
||||
get_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE
|
||||
ret x10
|
||||
endfunc platform_get_stack
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* void platform_set_stack (unsigned long mpidr)
|
||||
*
|
||||
* For a given CPU, this function sets the stack pointer
|
||||
* to a stack allocated in normal memory.
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
func platform_set_stack
|
||||
mov x9, x30 // lr
|
||||
bl platform_get_stack
|
||||
mov sp, x0
|
||||
ret x9
|
||||
endfunc platform_set_stack
|
||||
|
||||
#else
|
||||
/* ---------------------------------------------------------------------
|
||||
* When the compatility layer is disabled, the new platform APIs
|
||||
* viz plat_get_my_stack() and plat_set_my_stack() are
|
||||
|
@ -161,8 +91,6 @@ func plat_set_my_stack
|
|||
ret x9
|
||||
endfunc plat_set_my_stack
|
||||
|
||||
#endif /*__ENABLE_PLAT_COMPAT__*/
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* Per-cpu stacks in normal memory. Each cpu gets a
|
||||
* stack of PLATFORM_STACK_SIZE bytes.
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#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
|
|
@ -1,23 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
ifeq (${PSCI_EXTENDED_STATE_ID}, 1)
|
||||
$(error "PSCI Compatibility mode can be enabled only if \
|
||||
PSCI_EXTENDED_STATE_ID is not set")
|
||||
endif
|
||||
|
||||
ifneq (${ARCH}, aarch64)
|
||||
$(error "PSCI Compatibility mode is only supported for AArch64 platforms")
|
||||
endif
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += plat/compat/aarch64/plat_helpers_compat.S
|
||||
|
||||
BL31_SOURCES += plat/common/plat_psci_common.c \
|
||||
plat/compat/plat_pm_compat.c \
|
||||
plat/compat/plat_topology_compat.c
|
||||
|
||||
# Do not enable SVE
|
||||
ENABLE_SVE_FOR_NS := 0
|
|
@ -1,313 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#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,
|
||||
unsigned int cur_afflvl,
|
||||
unsigned 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;
|
||||
unsigned int 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 = (int) PLATFORM_MAX_AFFLVL;
|
||||
afflvl >= (int) MPIDR_AFFLVL0; afflvl--) {
|
||||
affmap_idx = init_pwr_domain_tree_desc(FIRST_MPIDR,
|
||||
affmap_idx,
|
||||
PLATFORM_MAX_AFFLVL,
|
||||
(unsigned int) 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);
|
||||
}
|
Loading…
Add table
Reference in a new issue