summaryrefslogtreecommitdiff
path: root/docs/platform-migration-guide.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/platform-migration-guide.md')
-rw-r--r--docs/platform-migration-guide.md575
1 files changed, 0 insertions, 575 deletions
diff --git a/docs/platform-migration-guide.md b/docs/platform-migration-guide.md
deleted file mode 100644
index 27cd0671..00000000
--- a/docs/platform-migration-guide.md
+++ /dev/null
@@ -1,575 +0,0 @@
-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_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][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 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 :
-
- 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. This handler
-is now mandatory for PSCI `CPU_SUSPEND` support.
-
-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.
-
-![Image 1](diagrams/psci-suspend-sequence.png?raw=true)
-
-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.
-
-
-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_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.
-
-
-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
-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
-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
-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, 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