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
Makefile
15
Makefile
|
@ -327,19 +327,6 @@ ifeq (${ARM_ARCH_MAJOR},7)
|
||||||
include make_helpers/armv7-a-cpus.mk
|
include make_helpers/armv7-a-cpus.mk
|
||||||
endif
|
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
|
# Include the CPU specific operations makefile, which provides default
|
||||||
# values for all CPU errata workarounds and CPU specific optimisations.
|
# values for all CPU errata workarounds and CPU specific optimisations.
|
||||||
# This can be overridden by the platform.
|
# 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_ASSERTIONS))
|
||||||
$(eval $(call assert_boolean,ENABLE_BACKTRACE))
|
$(eval $(call assert_boolean,ENABLE_BACKTRACE))
|
||||||
$(eval $(call assert_boolean,ENABLE_MPAM_FOR_LOWER_ELS))
|
$(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_PMF))
|
||||||
$(eval $(call assert_boolean,ENABLE_PSCI_STAT))
|
$(eval $(call assert_boolean,ENABLE_PSCI_STAT))
|
||||||
$(eval $(call assert_boolean,ENABLE_RUNTIME_INSTRUMENTATION))
|
$(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_ASSERTIONS))
|
||||||
$(eval $(call add_define,ENABLE_BACKTRACE))
|
$(eval $(call add_define,ENABLE_BACKTRACE))
|
||||||
$(eval $(call add_define,ENABLE_MPAM_FOR_LOWER_ELS))
|
$(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_PMF))
|
||||||
$(eval $(call add_define,ENABLE_PSCI_STAT))
|
$(eval $(call add_define,ENABLE_PSCI_STAT))
|
||||||
$(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION))
|
$(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
|
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
|
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.
|
mandatory and optional modifications for both the cold and warm boot paths.
|
||||||
Modifications consist of:
|
Modifications consist of:
|
||||||
|
@ -2976,12 +2972,6 @@ The default implementation of this function calls
|
||||||
Build flags
|
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
|
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
|
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
|
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.*
|
*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/common/platform.h: ../include/plat/common/platform.h
|
||||||
.. _include/plat/arm/common/plat\_arm.h: ../include/plat/arm/common/plat_arm.h%5D
|
.. _include/plat/arm/common/plat\_arm.h: ../include/plat/arm/common/plat_arm.h%5D
|
||||||
.. _User Guide: user-guide.rst
|
.. _User Guide: user-guide.rst
|
||||||
|
|
|
@ -110,23 +110,6 @@
|
||||||
end_vector_entry \since
|
end_vector_entry \since
|
||||||
.endm
|
.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
|
* 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
|
* using the plat_my_core_pos() index, the name of the stack storage
|
||||||
|
|
|
@ -10,9 +10,6 @@
|
||||||
#include <bakery_lock.h>
|
#include <bakery_lock.h>
|
||||||
#include <bl_common.h>
|
#include <bl_common.h>
|
||||||
#include <platform_def.h> /* for PLAT_NUM_PWR_DOMAINS */
|
#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 <psci_lib.h> /* To maintain compatibility for SPDs */
|
||||||
#include <utils_def.h>
|
#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 */
|
#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
|
* The below function enable Trusted Firmware components like SPDs which
|
||||||
* haven't migrated to the new platform API to compile on platforms which
|
* haven't migrated to the new platform API to compile on platforms which
|
||||||
* have the compatibility layer disabled.
|
* have the compatibility layer disabled.
|
||||||
*/
|
*/
|
||||||
unsigned int platform_core_pos_helper(unsigned long mpidr);
|
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 */
|
#endif /* PLATFORM_H */
|
||||||
|
|
|
@ -938,84 +938,6 @@ int psci_secondaries_brought_up(void)
|
||||||
return (n_valid > 1U) ? 1 : 0;
|
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
|
* Initiate power down sequence, by calling power down operations registered for
|
||||||
* this CPU.
|
* this CPU.
|
||||||
|
|
|
@ -40,7 +40,6 @@ void bl31_plat_runtime_setup(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !ENABLE_PLAT_COMPAT
|
|
||||||
/*
|
/*
|
||||||
* Helper function for platform_get_pos() when platform compatibility is
|
* Helper function for platform_get_pos() when platform compatibility is
|
||||||
* disabled. This is to enable SPDs using the older platform API to continue
|
* 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);
|
assert(idx >= 0);
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if !ERROR_DEPRECATED
|
#if !ERROR_DEPRECATED
|
||||||
unsigned int plat_get_syscnt_freq2(void)
|
unsigned int plat_get_syscnt_freq2(void)
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
.weak plat_handle_double_fault
|
.weak plat_handle_double_fault
|
||||||
.weak plat_handle_el3_ea
|
.weak plat_handle_el3_ea
|
||||||
|
|
||||||
#if !ENABLE_PLAT_COMPAT
|
|
||||||
.globl platform_get_core_pos
|
.globl platform_get_core_pos
|
||||||
|
|
||||||
#define MPIDR_RES_BIT_MASK 0xff000000
|
#define MPIDR_RES_BIT_MASK 0xff000000
|
||||||
|
@ -49,7 +48,6 @@ func_deprecated platform_get_core_pos
|
||||||
beq plat_my_core_pos
|
beq plat_my_core_pos
|
||||||
b platform_core_pos_helper
|
b platform_core_pos_helper
|
||||||
endfunc_deprecated platform_get_core_pos
|
endfunc_deprecated platform_get_core_pos
|
||||||
#endif
|
|
||||||
|
|
||||||
/* -----------------------------------------------------
|
/* -----------------------------------------------------
|
||||||
* Placeholder function which should be redefined by
|
* Placeholder function which should be redefined by
|
||||||
|
|
|
@ -10,81 +10,11 @@
|
||||||
#include <platform_def.h>
|
#include <platform_def.h>
|
||||||
|
|
||||||
.local platform_normal_stacks
|
.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_get_my_stack
|
||||||
.weak plat_set_my_stack
|
.weak plat_set_my_stack
|
||||||
.globl platform_get_stack
|
.globl platform_get_stack
|
||||||
.globl platform_set_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
|
* When the compatility layer is disabled, the new platform APIs
|
||||||
* viz plat_get_my_stack() and plat_set_my_stack() are
|
* viz plat_get_my_stack() and plat_set_my_stack() are
|
||||||
|
@ -161,8 +91,6 @@ func plat_set_my_stack
|
||||||
ret x9
|
ret x9
|
||||||
endfunc plat_set_my_stack
|
endfunc plat_set_my_stack
|
||||||
|
|
||||||
#endif /*__ENABLE_PLAT_COMPAT__*/
|
|
||||||
|
|
||||||
/* -----------------------------------------------------
|
/* -----------------------------------------------------
|
||||||
* Per-cpu stacks in normal memory. Each cpu gets a
|
* Per-cpu stacks in normal memory. Each cpu gets a
|
||||||
* stack of PLATFORM_STACK_SIZE bytes.
|
* 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…
Reference in New Issue