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:
Roberto Vargas 2018-09-24 17:14:46 +01:00 committed by Antonio Nino Diaz
parent dadb16eac2
commit 871de5373d
15 changed files with 0 additions and 1504 deletions

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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 */

View File

@ -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 */

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}