mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-19 02:54:24 +00:00
PSCI: Add documentation and fix plat_is_my_cpu_primary()
This patch adds the necessary documentation updates to porting_guide.md for the changes in the platform interface mandated as a result of the new PSCI Topology and power state management frameworks. It also adds a new document `platform-migration-guide.md` to aid the migration of existing platform ports to the new API. The patch fixes the implementation and callers of plat_is_my_cpu_primary() to use w0 as the return parameter as implied by the function signature rather than x0 which was used previously. Change-Id: Ic11e73019188c8ba2bd64c47e1729ff5acdcdd5b
This commit is contained in:
parent
f9e858b1f7
commit
58523c076a
7 changed files with 842 additions and 197 deletions
BIN
docs/diagrams/psci-suspend-sequence.png
Normal file
BIN
docs/diagrams/psci-suspend-sequence.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 418 KiB |
574
docs/platform-migration-guide.md
Normal file
574
docs/platform-migration-guide.md
Normal file
|
@ -0,0 +1,574 @@
|
|||
Guide to migrate to new Platform porting interface
|
||||
==================================================
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
1. [Introduction](#1--introduction)
|
||||
2. [Platform API modification due to PSCI framework changes](#2--platform-api-modification-due-to-psci-framework-changes)
|
||||
* [Power domain topology framework platform API modifications](#21-power-domain-topology-framework-platform-api-modifications)
|
||||
* [Composite power state framework platform API modifications](#22-composite-power-state-framework-platform-api-modifications)
|
||||
* [Miscellaneous modifications](#23-miscellaneous-modifications)
|
||||
3. [Compatibility layer](#3--compatibility-layer)
|
||||
4. [Deprecated Platform API](#4--deprecated-platform-api)
|
||||
|
||||
- - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
1. Introduction
|
||||
----------------
|
||||
|
||||
The PSCI implementation in Trusted Firmware 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.
|
||||
|
||||
|
||||
2. Platform API modification due to PSCI framework changes
|
||||
-----------------------------------------------------------
|
||||
|
||||
This section describes changes to the platform APIs.
|
||||
|
||||
|
||||
2.1 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_count()` 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][my_core_pos].
|
||||
These are used by the power domain topology framework such that:
|
||||
|
||||
1. 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.
|
||||
|
||||
2. 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].
|
||||
|
||||
|
||||
2.2 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. The framework's
|
||||
approach to coordination only requires 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 :
|
||||
|
||||
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:
|
||||
|
||||
1. Zero means RUN
|
||||
|
||||
2. 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].
|
||||
|
||||
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][get_target_pwr_state].
|
||||
|
||||
The PSCI Generic implementation expects platform ports to populate the handlers
|
||||
for the `plat_psci_ops` structure which is declared as :
|
||||
|
||||
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)(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);
|
||||
} plat_psci_ops_t;
|
||||
|
||||
The description of these handlers can be found in the [Porting Guide][psci_ops].
|
||||
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.
|
||||
|
||||
The `plat_psci_ops` handlers, `pwr_domain_off` 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.
|
||||
|
||||

|
||||
|
||||
Refer [plat/arm/board/fvp/fvp_pm.c] for the implementation details of
|
||||
these handlers for the FVP. The commit b6df6ccbc88cc14592f5e603ef580d3cbf4733c3
|
||||
demonstrates the migration of ARM reference platforms to the new platform API.
|
||||
|
||||
|
||||
2.3 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()`.
|
||||
|
||||
|
||||
3. 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_count()` 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.
|
||||
|
||||
|
||||
4. 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
|
||||
BL3-1 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 BL3-1)
|
||||
|
||||
The following functions must be implemented to initialize PSCI functionality in
|
||||
the ARM Trusted Firmware.
|
||||
|
||||
|
||||
### 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
|
||||
BL3-1.
|
||||
|
||||
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, ARM Limited and Contributors. All rights reserved._
|
||||
|
||||
|
||||
[Porting Guide]: porting-guide.md
|
||||
[Power Domain Topology Design]: psci-pd-tree.md
|
||||
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
|
||||
[psci pd tree]: psci-pd-tree.md
|
||||
[my_core_pos]: porting-guide.md#function--plat_my_core_pos
|
||||
[get_target_pwr_state]: porting-guide.md#function--plat_get_target_pwr_state-optional
|
||||
[psci_ops]: porting-guide.md#function--plat_setup_psci_ops-mandatory
|
||||
[plat/arm/board/fvp/fvp_pm.c]: ../plat/arm/board/fvp/fvp_pm.c
|
||||
[plat/common/aarch64/platform_mp_stack.S]: ../plat/common/aarch64/platform_mp_stack.S
|
||||
[plat/common/aarch64/platform_up_stack.S]: ../plat/common/aarch64/platform_up_stack.S
|
|
@ -8,7 +8,8 @@ Contents
|
|||
2. [Common Modifications](#2--common-modifications)
|
||||
* [Common mandatory modifications](#21-common-mandatory-modifications)
|
||||
* [Handling reset](#22-handling-reset)
|
||||
* [Common optional modifications](#23-common-optional-modifications)
|
||||
* [Common mandatory modifications](#23-common-mandatory-modifications)
|
||||
* [Common optional modifications](#24-common-optional-modifications)
|
||||
3. [Boot Loader stage specific modifications](#3--modifications-specific-to-a-boot-loader-stage)
|
||||
* [Boot Loader stage 1 (BL1)](#31-boot-loader-stage-1-bl1)
|
||||
* [Boot Loader stage 2 (BL2)](#32-boot-loader-stage-2-bl2)
|
||||
|
@ -25,6 +26,10 @@ Contents
|
|||
1. 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 the ARM Trusted Firmware to a new platform involves making some
|
||||
mandatory and optional modifications for both the cold and warm boot paths.
|
||||
Modifications consist of:
|
||||
|
@ -139,21 +144,39 @@ platform port to define additional platform porting constants in
|
|||
Defines the total number of CPUs implemented by the platform across all
|
||||
clusters in the system.
|
||||
|
||||
* **#define : PLATFORM_NUM_AFFS**
|
||||
* **#define : PLAT_NUM_PWR_DOMAINS**
|
||||
|
||||
Defines the total number of nodes in the affinity heirarchy at all affinity
|
||||
levels used by the platform.
|
||||
Defines the total number of nodes in the power domain topology
|
||||
tree at all the power domain levels used by the platform.
|
||||
This macro is used by the PSCI implementation to allocate
|
||||
data structures to represent power domain topology.
|
||||
|
||||
* **#define : PLATFORM_MAX_AFFLVL**
|
||||
* **#define : PLAT_MAX_PWR_LVL**
|
||||
|
||||
Defines the maximum affinity level that the power management operations
|
||||
should apply to. ARMv8-A has support for 4 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 CPUs. It reports the maximum
|
||||
affinity level as 1, resulting in PSCI power control up to the cluster
|
||||
level.
|
||||
Defines the maximum power domain level that the power management operations
|
||||
should apply to. More often, but not always, the power domain level
|
||||
corresponds to affinity level. This macro allows the PSCI implementation
|
||||
to know the highest power domain level that it should consider for power
|
||||
management operations in the system that the platform implements. For
|
||||
example, the Base AEM FVP implements two clusters with a configurable
|
||||
number of CPUs and it reports the maximum power domain level as 1.
|
||||
|
||||
* **#define : PLAT_MAX_OFF_STATE**
|
||||
|
||||
Defines the local power state corresponding to the deepest power down
|
||||
possible at every power domain level in the platform. The local power
|
||||
states for each level may be sparsely allocated between 0 and this value
|
||||
with 0 being reserved for the RUN state. The PSCI implementation uses this
|
||||
value to initialize the local power states of the power domain nodes and
|
||||
to specify the requested power state for a PSCI_CPU_OFF call.
|
||||
|
||||
* **#define : PLAT_MAX_RET_STATE**
|
||||
|
||||
Defines the local power state corresponding to the deepest retention state
|
||||
possible at every power domain level in the platform. This macro should be
|
||||
a value less than PLAT_MAX_OFF_STATE and greater than 0. It is used by the
|
||||
PSCI implementation to distuiguish between retention and power down local
|
||||
power states within PSCI_CPU_SUSPEND call.
|
||||
|
||||
* **#define : BL1_RO_BASE**
|
||||
|
||||
|
@ -408,21 +431,17 @@ The following functions need to be implemented by the platform port to enable
|
|||
reset vector code to perform the above tasks.
|
||||
|
||||
|
||||
### Function : platform_get_entrypoint() [mandatory]
|
||||
### Function : plat_get_my_entrypoint() [mandatory when PROGRAMMABLE_RESET_ADDRESS == 0]
|
||||
|
||||
Argument : unsigned long
|
||||
Return : unsigned int
|
||||
Argument : void
|
||||
Return : unsigned long
|
||||
|
||||
This function is called with the `SCTLR.M` and `SCTLR.C` bits disabled. The CPU
|
||||
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's a warm reset then it returns the entrypoint into the
|
||||
BL3-1 image that the CPU must jump to. If it's a cold reset then this function
|
||||
must return zero.
|
||||
|
||||
This function is also responsible for implementing a platform-specific mechanism
|
||||
to handle the condition where the CPU has been warm reset but there is no
|
||||
entrypoint to jump to.
|
||||
This function is called with the called with the MMU and caches disabled
|
||||
(`SCTLR_EL3.M` = 0 and `SCTLR_EL3.C` = 0). The function is responsible for
|
||||
distinguishing between a warm and cold reset for the current CPU using
|
||||
platform-specific means. If it's a warm reset, then it returns the warm
|
||||
reset entrypoint point provided to `plat_setup_psci_ops()` during
|
||||
BL3-1 initialization. If it's a cold reset then this function must return zero.
|
||||
|
||||
This function does not follow the Procedure Call Standard used by the
|
||||
Application Binary Interface for the ARM 64-bit architecture. The caller should
|
||||
|
@ -431,11 +450,16 @@ function.
|
|||
|
||||
This function fulfills requirement 1 and 3 listed above.
|
||||
|
||||
Note that for platforms that support programming the reset address, it is
|
||||
expected that a CPU will start executing code directly at the right address,
|
||||
both on a cold and warm reset. In this case, there is no need to identify the
|
||||
type of reset nor to query the warm reset entrypoint. Therefore, implementing
|
||||
this function is not required on such platforms.
|
||||
|
||||
|
||||
### Function : plat_secondary_cold_boot_setup() [mandatory]
|
||||
|
||||
Argument : void
|
||||
Return : void
|
||||
|
||||
This function is called with the MMU and data caches disabled. It is responsible
|
||||
for placing the executing secondary CPU in a platform-specific state until the
|
||||
|
@ -449,15 +473,15 @@ requires them.
|
|||
This function fulfills requirement 2 above.
|
||||
|
||||
|
||||
### Function : platform_is_primary_cpu() [mandatory]
|
||||
### Function : plat_is_my_cpu_primary() [mandatory]
|
||||
|
||||
Argument : unsigned long
|
||||
Argument : void
|
||||
Return : unsigned int
|
||||
|
||||
This function identifies a CPU by its `MPIDR`, which is passed as the argument,
|
||||
to determine whether this CPU is the primary CPU or a secondary CPU. A return
|
||||
value of zero indicates that the CPU is not the primary CPU, while a non-zero
|
||||
return value indicates that the CPU is the primary CPU.
|
||||
This function identifies whether the current CPU is the primary CPU or a
|
||||
secondary CPU. A return value of zero indicates that the CPU is not the
|
||||
primary CPU, while a non-zero return value indicates that the CPU is the
|
||||
primary CPU.
|
||||
|
||||
|
||||
### Function : platform_mem_init() [mandatory]
|
||||
|
@ -501,58 +525,75 @@ retrieved from the platform. The function also reports extra information related
|
|||
to the ROTPK in the flags parameter.
|
||||
|
||||
|
||||
2.3 Common mandatory modifications
|
||||
---------------------------------
|
||||
|
||||
2.3 Common optional modifications
|
||||
The following functions are mandatory functions which need to be implemented
|
||||
by the platform port.
|
||||
|
||||
### Function : plat_my_core_pos()
|
||||
|
||||
Argument : void
|
||||
Return : unsigned int
|
||||
|
||||
This funtion returns the index of the calling CPU which is used as a
|
||||
CPU-specific linear index into blocks of memory (for example while allocating
|
||||
per-CPU stacks). This function will be invoked very early in the
|
||||
initialization sequence which mandates that this function should be
|
||||
implemented in assembly and should not rely on the avalability of a C
|
||||
runtime environment.
|
||||
|
||||
This function plays a crucial role in the power domain topology framework in
|
||||
PSCI and details of this can be found in [Power Domain Topology Design].
|
||||
|
||||
### Function : plat_core_pos_by_mpidr()
|
||||
|
||||
Argument : u_register_t
|
||||
Return : int
|
||||
|
||||
This function validates the `MPIDR` of a CPU and converts it to an index,
|
||||
which can be used as a CPU-specific linear index into blocks of memory. In
|
||||
case the `MPIDR` is invalid, this function returns -1. This function will only
|
||||
be invoked by BL3-1 after the power domain topology is initialized and can
|
||||
utilize the C runtime environment. For further details about how ARM Trusted
|
||||
Firmware represents the power domain topology and how this relates to the
|
||||
linear CPU index, please refer [Power Domain Topology Design].
|
||||
|
||||
|
||||
|
||||
2.4 Common optional modifications
|
||||
---------------------------------
|
||||
|
||||
The following are helper functions implemented by the firmware that perform
|
||||
common platform-specific tasks. A platform may choose to override these
|
||||
definitions.
|
||||
|
||||
### Function : plat_set_my_stack()
|
||||
|
||||
### Function : platform_get_core_pos()
|
||||
|
||||
Argument : unsigned long
|
||||
Return : int
|
||||
|
||||
A platform may need to convert the `MPIDR` of a CPU to an absolute number, which
|
||||
can be used as a CPU-specific linear index into blocks of memory (for example
|
||||
while allocating per-CPU stacks). This routine contains a simple mechanism
|
||||
to perform this conversion, using the assumption that each cluster contains a
|
||||
maximum of 4 CPUs:
|
||||
|
||||
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
|
||||
Argument : void
|
||||
Return : void
|
||||
|
||||
This function sets the current stack pointer to the normal memory stack that
|
||||
has been allocated for the CPU specificed by MPIDR. For BL images that only
|
||||
require a stack for the primary CPU the parameter is ignored. The size of
|
||||
the stack allocated to each CPU is specified by the platform defined constant
|
||||
`PLATFORM_STACK_SIZE`.
|
||||
has been allocated for the current CPU. For BL images that only require a
|
||||
stack for the primary CPU, the UP version of the function is used. The size
|
||||
of the stack allocated to each CPU 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()
|
||||
### Function : plat_get_my_stack()
|
||||
|
||||
Argument : unsigned long
|
||||
Argument : void
|
||||
Return : unsigned long
|
||||
|
||||
This function returns the base address of the normal memory stack that
|
||||
has been allocated for the CPU specificed by MPIDR. For BL images that only
|
||||
require a stack for the primary CPU the parameter is ignored. The size of
|
||||
the stack allocated to each CPU is specified by the platform defined constant
|
||||
`PLATFORM_STACK_SIZE`.
|
||||
has been allocated for the current CPU. For BL images that only require a
|
||||
stack for the primary CPU, the UP version of the function is used. The size
|
||||
of the stack allocated to each CPU 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
|
||||
|
@ -1113,147 +1154,159 @@ modes table.
|
|||
------------------------------------------------
|
||||
|
||||
The ARM Trusted Firmware's implementation of the PSCI API is based around the
|
||||
concept of an _affinity instance_. Each _affinity instance_ can be uniquely
|
||||
identified in a system by a CPU ID (the processor `MPIDR` is used in the PSCI
|
||||
interface) and an _affinity level_. A processing element (for example, a
|
||||
CPU) is at level 0. If the CPUs in the system are described in a tree where the
|
||||
node above a CPU is a logical grouping of CPUs that share some state, then
|
||||
affinity level 1 is that group of CPUs (for example, a cluster), and affinity
|
||||
level 2 is a group of clusters (for example, the system). The implementation
|
||||
assumes that the affinity level 1 ID can be computed from the affinity level 0
|
||||
ID (for example, a unique cluster ID can be computed from the CPU ID). The
|
||||
current implementation computes this on the basis of the recommended use of
|
||||
`MPIDR` affinity fields in the ARM Architecture Reference Manual.
|
||||
concept of a _power domain_. A _power domain_ is a CPU or a logical group of
|
||||
CPUs which share some state on which power management operations can be
|
||||
performed as specified by [PSCI]. Each CPU in the system is assigned a cpu
|
||||
index which is a unique number between `0` and `PLATFORM_CORE_COUNT - 1`.
|
||||
The _power domains_ are arranged in a hierarchial tree structure and
|
||||
each _power domain_ can be identified in a system by the cpu index of any CPU
|
||||
that is part of that domain and a _power domain level_. A processing element
|
||||
(for example, a CPU) is at level 0. If the _power domain_ node above a CPU is
|
||||
a logical grouping of CPUs that share some state, then level 1 is that group
|
||||
of CPUs (for example, a cluster), and level 2 is a group of clusters
|
||||
(for example, the system). More details on the power domain topology and its
|
||||
organization can be found in [Power Domain Topology Design].
|
||||
|
||||
BL3-1's platform initialization code exports a pointer to the platform-specific
|
||||
power management operations required for the PSCI implementation to function
|
||||
correctly. This information is populated in the `plat_pm_ops` structure. The
|
||||
PSCI implementation calls members of the `plat_pm_ops` structure for performing
|
||||
power management operations for each affinity instance. For example, the target
|
||||
CPU is specified by its `MPIDR` in a PSCI `CPU_ON` call. The `affinst_on()`
|
||||
handler (if present) is called for each affinity instance as the PSCI
|
||||
implementation powers up each affinity level implemented in the `MPIDR` (for
|
||||
example, CPU, cluster and system).
|
||||
correctly. This information is populated in the `plat_psci_ops` structure. The
|
||||
PSCI implementation calls members of the `plat_psci_ops` structure for performing
|
||||
power management operations on the power domains. For example, the target
|
||||
CPU is specified by its `MPIDR` in a PSCI `CPU_ON` call. The `pwr_domain_on()`
|
||||
handler (if present) is called for the CPU power domain.
|
||||
|
||||
The `power-state` parameter of a PSCI `CPU_SUSPEND` call can be used to
|
||||
describe composite power states specific to a platform. The PSCI implementation
|
||||
defines a generic representation of the power-state parameter viz which is an
|
||||
array of local power states where each index corresponds to a power domain
|
||||
level. Each entry contains the local power state the power domain at that power
|
||||
level could enter. It 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` call to this representation.
|
||||
|
||||
The following functions must be implemented to initialize PSCI functionality in
|
||||
the ARM Trusted Firmware.
|
||||
|
||||
|
||||
### Function : plat_get_aff_count() [mandatory]
|
||||
### Function : plat_get_target_pwr_state() [optional]
|
||||
|
||||
Argument : unsigned int, unsigned long
|
||||
Return : unsigned int
|
||||
Argument : unsigned int, const plat_local_state_t *, unsigned int
|
||||
Return : plat_local_state_t
|
||||
|
||||
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 CPU.
|
||||
The PSCI generic code uses this function to let the platform participate in
|
||||
state coordination during a power management operation. The function is passed
|
||||
a pointer to an array of platform specific local power state `states` (second
|
||||
argument) which contains the requested power state for each CPU at a particular
|
||||
power domain level `lvl` (first argument) within the power domain. The function
|
||||
is expected to traverse this array of upto `ncpus` (third argument) and return
|
||||
a coordinated target power state by the comparing all the requested power
|
||||
states. The target power state should not be deeper than any of the requested
|
||||
power states.
|
||||
|
||||
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 2 CPUs and the second cluster implements 4
|
||||
CPUs, 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.
|
||||
A weak definition of this API is provided by default wherein it assumes
|
||||
that the platform assigns a local state value in order of increasing depth
|
||||
of the power state i.e. for two power states X & Y, if X < Y
|
||||
then X represents a shallower power state than Y. As a result, the
|
||||
coordinated target local power state for a power domain will be the minimum
|
||||
of the requested local power state values.
|
||||
|
||||
|
||||
### Function : plat_get_aff_state() [mandatory]
|
||||
### Function : plat_get_power_domain_tree_desc() [mandatory]
|
||||
|
||||
Argument : unsigned int, unsigned long
|
||||
Return : unsigned int
|
||||
Argument : void
|
||||
Return : const unsigned char *
|
||||
|
||||
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 CPU.
|
||||
|
||||
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 4 CPUs and
|
||||
another CPU implemented directly on the interconnect with the cluster. The
|
||||
`MPIDR`s of the cluster would range from `0x0-0x3`. The `MPIDR` of the single
|
||||
CPU would be 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 CPU in the
|
||||
topology tree. Hence it is marked as `PSCI_AFF_ABSENT`.
|
||||
This function returns a pointer to the byte array containing the power domain
|
||||
topology tree description. The format and method to construct this array are
|
||||
described in [Power Domain Topology Design]. The BL3-1 PSCI initilization code
|
||||
requires this array to be described by the platform, either statically or
|
||||
dynamically, to initialize the power domain topology tree. In case the array
|
||||
is populated dynamically, then plat_core_pos_by_mpidr() and
|
||||
plat_my_core_pos() should also be implemented suitably so that the topology
|
||||
tree description matches the CPU indices returned by these APIs. These APIs
|
||||
together form the platform interface for the PSCI topology framework.
|
||||
|
||||
|
||||
### Function : platform_setup_pm() [mandatory]
|
||||
## Function : plat_setup_psci_ops() [mandatory]
|
||||
|
||||
Argument : const plat_pm_ops **
|
||||
Argument : uintptr_t, const plat_psci_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 CPU.
|
||||
|
||||
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 BL3-1's private `plat_pm_ops` structure.
|
||||
This function is called by PSCI initialization code. Its purpose is to let
|
||||
the platform layer know about the warm boot entrypoint through the
|
||||
`sec_entrypoint` (first argument) and to export handler routines for
|
||||
platform-specific psci power management actions by populating the passed
|
||||
pointer with a pointer to BL3-1's private `plat_psci_ops` structure.
|
||||
|
||||
A description of each member of this structure is given below. Please refer to
|
||||
the ARM FVP specific implementation of these handlers in
|
||||
[plat/arm/board/fvp/fvp_pm.c] as an example. 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/arm/board/fvp/fvp_pm.c] as an example. For each PSCI function that the
|
||||
platform wants to support, the associated operation or operations in this
|
||||
structure must be provided and implemented (Refer section 4 of
|
||||
[Firmware Design] for the PSCI API supported in Trusted Firmware). To disable
|
||||
a PSCI function in a platform port, the operation should be removed from this
|
||||
structure instead of providing an empty implementation.
|
||||
|
||||
#### plat_pm_ops.affinst_standby()
|
||||
#### plat_psci_ops.cpu_standby()
|
||||
|
||||
Perform the platform-specific setup to enter the standby state indicated by the
|
||||
passed argument. The generic code expects the handler to succeed.
|
||||
Perform the platform-specific actions to enter the standby state for a cpu
|
||||
indicated by the passed argument. This provides a fast path for CPU standby
|
||||
wherein overheads of PSCI state management and lock acquistion is avoided.
|
||||
For this handler to be invoked by the PSCI `CPU_SUSPEND` API implementation,
|
||||
the suspend state type specified in the `power-state` parameter should be
|
||||
STANDBY and the target power domain level specified should be the CPU. The
|
||||
handler should put the CPU into a low power retention state (usually by
|
||||
issuing a wfi instruction) and ensure that it can be woken up from that
|
||||
state by a normal interrupt. The generic code expects the handler to succeed.
|
||||
|
||||
#### plat_pm_ops.affinst_on()
|
||||
#### plat_psci_ops.pwr_domain_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 CPU, the cluster that contains this CPU 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.
|
||||
Perform the platform specific actions to power on a CPU, specified
|
||||
by the `MPIDR` (first argument). The generic code expects the platform to
|
||||
return PSCI_E_SUCCESS on success or PSCI_E_INTERN_FAIL for any failure.
|
||||
|
||||
#### plat_pm_ops.affinst_off()
|
||||
#### plat_psci_ops.pwr_domain_off()
|
||||
|
||||
Perform the platform specific setup to power off an affinity instance of the
|
||||
calling CPU. It is called by the PSCI `CPU_OFF` API implementation.
|
||||
Perform the platform specific actions to prepare to power off the calling CPU
|
||||
and its higher parent power domain levels as indicated by the `target_state`
|
||||
(first argument). 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 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 CPU is the last powered on CPU in the cluster, after powering down
|
||||
affinity level 0 (CPU), the platform port should power down affinity level 1
|
||||
(the cluster) as well. The generic code expects the handler to succeed.
|
||||
The `target_state` encodes the platform coordinated target local power states
|
||||
for the CPU power domain and its parent power domain levels. The handler
|
||||
needs to perform power management operation corresponding to the local state
|
||||
at each power level.
|
||||
|
||||
#### plat_pm_ops.affinst_suspend()
|
||||
For this handler, the local power state for the CPU power domain will be a
|
||||
power down state where as it could be either power down, retention or run state
|
||||
for the higher power domain levels depending on the result of state
|
||||
coordination. The generic code expects the handler to succeed.
|
||||
|
||||
Perform the platform specific setup to power off an affinity instance of the
|
||||
calling CPU. It is called by the PSCI `CPU_SUSPEND` API and `SYSTEM_SUSPEND`
|
||||
API implementation
|
||||
#### plat_psci_ops.pwr_domain_suspend()
|
||||
|
||||
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 CPU is the
|
||||
last powered on CPU in the cluster, after powering down affinity level 0 (CPU),
|
||||
the platform port should power down affinity level 1 (the cluster) as well.
|
||||
Perform the platform specific actions to prepare to suspend the calling
|
||||
CPU and its higher parent power domain levels as indicated by the
|
||||
`target_state` (first argument). It is called by the PSCI `CPU_SUSPEND`
|
||||
API implementation.
|
||||
|
||||
The difference between turning an affinity instance off versus suspending it
|
||||
is that in the former case, the affinity instance is expected to re-initialize
|
||||
its state when its next powered on (see `affinst_on_finish()`). In the latter
|
||||
case, the affinity instance is expected to save enough state so that it can
|
||||
The `target_state` has a similar meaning as described in
|
||||
the `pwr_domain_off()` operation. It encodes the platform coordinated
|
||||
target local power states for the CPU power domain and its parent
|
||||
power domain levels. The handler needs to perform power management operation
|
||||
corresponding to the local state at each power level. The generic code
|
||||
expects the handler to succeed.
|
||||
|
||||
The difference between turning a power domain off versus suspending it
|
||||
is that in the former case, the power domain is expected to re-initialize
|
||||
its state when it is next powered on (see `pwr_domain_on_finish()`). In the
|
||||
latter case, the power domain is expected to save enough state so that it can
|
||||
resume execution by restoring this state when its powered on (see
|
||||
`affinst_suspend_finish()`).The generic code expects the handler to succeed.
|
||||
`pwr_domain_suspend_finish()`).
|
||||
|
||||
#### plat_pm_ops.affinst_on_finish()
|
||||
#### plat_psci_ops.pwr_domain_on_finish()
|
||||
|
||||
This function is called by the PSCI implementation after the calling CPU is
|
||||
powered on and released from reset in response to an earlier PSCI `CPU_ON` call.
|
||||
|
@ -1261,11 +1314,12 @@ It performs the platform-specific setup required to initialize enough state for
|
|||
this CPU 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.
|
||||
The `target_state` (first argument) is the prior state of the power domains
|
||||
immediately before the CPU was turned on. It indicates which power domains
|
||||
above the CPU might require initialization due to having previously been in
|
||||
low power states. The generic code expects the handler to succeed.
|
||||
|
||||
#### plat_pm_ops.affinst_suspend_finish()
|
||||
#### plat_psci_ops.pwr_domain_suspend_finish()
|
||||
|
||||
This function is called by the PSCI implementation after the calling CPU is
|
||||
powered on and released from reset in response to an asynchronous wakeup
|
||||
|
@ -1274,40 +1328,36 @@ event, for example a timer interrupt that was programmed by the CPU during the
|
|||
setup required to restore the saved state for this CPU 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.
|
||||
The `target_state` (first argument) has a similar meaning as described in
|
||||
the `pwr_domain_on_finish()` operation. The generic code expects the platform
|
||||
to succeed.
|
||||
|
||||
#### plat_pm_ops.validate_power_state()
|
||||
#### plat_psci_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 error, which is propagated back to the normal
|
||||
world PSCI client.
|
||||
call to validate the `power_state` parameter of the PSCI API and if valid,
|
||||
populate it in `req_state` (second argument) array as power domain level
|
||||
specific local states. If the `power_state` is invalid, the platform must
|
||||
return PSCI_E_INVALID_PARAMS as error, which is propagated back to the
|
||||
normal world PSCI client.
|
||||
|
||||
#### plat_pm_ops.validate_ns_entrypoint()
|
||||
#### plat_psci_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 error, which is
|
||||
parameter passed by the normal world. If the `entry_point` is invalid,
|
||||
the platform must return PSCI_E_INVALID_ADDRESS as error, which is
|
||||
propagated back to the normal world PSCI client.
|
||||
|
||||
#### plat_pm_ops.get_sys_suspend_power_state()
|
||||
#### plat_psci_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.
|
||||
call to get the `req_state` parameter from platform which encodes the power
|
||||
domain level specific local states to suspend to system affinity level. The
|
||||
`req_state` will be utilized to do the PSCI state coordination and
|
||||
`pwr_domain_suspend()` will be invoked with the coordinated target state to
|
||||
enter system suspend.
|
||||
|
||||
BL3-1 platform initialization code must also detect the system topology and
|
||||
the state of each affinity instance in the topology. This information is
|
||||
critical for the PSCI runtime service to function correctly. More details are
|
||||
provided in the description of the `plat_get_aff_count()` and
|
||||
`plat_get_aff_state()` functions above.
|
||||
|
||||
3.4 Interrupt Management framework (in BL3-1)
|
||||
----------------------------------------------
|
||||
|
@ -1475,6 +1525,12 @@ register x0.
|
|||
4. 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
|
||||
|
@ -1589,6 +1645,9 @@ _Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved._
|
|||
[User Guide]: user-guide.md
|
||||
[FreeBSD]: http://www.freebsd.org
|
||||
[Firmware Design]: firmware-design.md
|
||||
[Power Domain Topology Design]: psci-pd-tree.md
|
||||
[PSCI]: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
|
||||
[Migration Guide]: platform-migration-guide.md
|
||||
|
||||
[plat/common/aarch64/platform_mp_stack.S]: ../plat/common/aarch64/platform_mp_stack.S
|
||||
[plat/common/aarch64/platform_up_stack.S]: ../plat/common/aarch64/platform_up_stack.S
|
||||
|
|
|
@ -351,7 +351,12 @@ performed.
|
|||
|
||||
* `PROGRAMMABLE_RESET_ADDRESS`: This option indicates whether the reset
|
||||
vector address can be programmed or is fixed on the platform. It can take
|
||||
either 0 (fixed) or 1 (programmable). Default is 0.
|
||||
either 0 (fixed) or 1 (programmable). Default is 0. If the platform has a
|
||||
programmable reset address, it is expected that a CPU will start executing
|
||||
code directly at the right address, both on a cold and warm reset. In this
|
||||
case, there is no need to identify the entrypoint on boot and this has
|
||||
implication for `plat_get_my_entrypoint()` platform porting interface.
|
||||
(see the [Porting Guide] for details)
|
||||
|
||||
* `PSCI_EXTENDED_STATE_ID`: As per PSCI1.0 Specification, there are 2 formats
|
||||
possible for the PSCI power-state parameter viz original and extended
|
||||
|
@ -1092,4 +1097,5 @@ _Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved._
|
|||
[Juno Software Guide]: http://community.arm.com/docs/DOC-8396
|
||||
[DS-5]: http://www.arm.com/products/tools/software-tools/ds-5/index.php
|
||||
[mbedTLS Repository]: https://github.com/ARMmbed/mbedtls.git
|
||||
[Porting Guide]: ./porting-guide.md
|
||||
[Trusted Board Boot]: trusted-board-boot.md
|
||||
|
|
|
@ -181,7 +181,7 @@
|
|||
* -------------------------------------------------------------
|
||||
*/
|
||||
bl plat_is_my_cpu_primary
|
||||
cbnz x0, do_primary_cold_boot
|
||||
cbnz w0, do_primary_cold_boot
|
||||
|
||||
/* This is a cold boot on a secondary CPU */
|
||||
bl plat_secondary_cold_boot_setup
|
||||
|
|
|
@ -154,11 +154,17 @@ _panic:
|
|||
b _panic
|
||||
endfunc plat_get_my_entrypoint
|
||||
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* unsigned int plat_is_my_cpu_primary (void);
|
||||
*
|
||||
* Find out whether the current cpu is the primary
|
||||
* cpu.
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
func plat_is_my_cpu_primary
|
||||
mrs x0, mpidr_el1
|
||||
and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
|
||||
cmp x0, #FVP_PRIMARY_CPU
|
||||
cset x0, eq
|
||||
cset w0, eq
|
||||
ret
|
||||
endfunc plat_is_my_cpu_primary
|
||||
|
|
|
@ -77,7 +77,7 @@ endfunc plat_get_my_entrypoint
|
|||
* Function to calculate the core position by
|
||||
* swapping the cluster order. This is necessary in order to
|
||||
* match the format of the boot information passed by the SCP
|
||||
* and read in platform_is_primary_cpu below.
|
||||
* and read in plat_is_my_cpu_primary below.
|
||||
* -----------------------------------------------------------
|
||||
*/
|
||||
func plat_arm_calc_core_pos
|
||||
|
@ -102,6 +102,6 @@ func plat_is_my_cpu_primary
|
|||
ldr x1, [x1]
|
||||
ubfx x1, x1, #PRIMARY_CPU_SHIFT, #PRIMARY_CPU_BIT_WIDTH
|
||||
cmp x0, x1
|
||||
cset x0, eq
|
||||
cset w0, eq
|
||||
ret x9
|
||||
endfunc plat_is_my_cpu_primary
|
||||
|
|
Loading…
Add table
Reference in a new issue