Douglas Raillard | d7c21b7 | 2017-06-28 15:23:03 +0100 | [diff] [blame] | 1 | Guide to migrate to new Platform porting interface |
| 2 | ================================================== |
| 3 | |
| 4 | |
| 5 | .. section-numbering:: |
| 6 | :suffix: . |
| 7 | |
| 8 | .. contents:: |
| 9 | |
| 10 | -------------- |
| 11 | |
| 12 | Introduction |
| 13 | ------------ |
| 14 | |
| 15 | The PSCI implementation in Trusted Firmware has undergone a redesign because of |
| 16 | three requirements that the PSCI 1.0 specification introduced : |
| 17 | |
| 18 | - Removing the framework assumption about the structure of the MPIDR, and |
| 19 | its relation to the power topology enables support for deeper and more |
| 20 | complex hierarchies. |
| 21 | |
| 22 | - Reworking the power state coordination implementation in the framework |
| 23 | to support the more detailed PSCI 1.0 requirements and reduce platform |
| 24 | port complexity |
| 25 | |
| 26 | - Enable the use of the extended power\_state parameter and the larger StateID |
| 27 | field |
| 28 | |
| 29 | The PSCI 1.0 implementation introduces new frameworks to fulfill the above |
| 30 | requirements. These framework changes mean that the platform porting API must |
| 31 | also be modified. This document is a guide to assist migration of the existing |
| 32 | platform ports to the new platform API. |
| 33 | |
| 34 | This document describes the new platform API and compares it with the |
| 35 | deprecated API. It also describes the compatibility layer that enables the |
| 36 | existing platform ports to work with the PSCI 1.0 implementation. The |
| 37 | deprecated platform API is documented for reference. |
| 38 | |
| 39 | Platform API modification due to PSCI framework changes |
| 40 | ------------------------------------------------------- |
| 41 | |
| 42 | This section describes changes to the platform APIs. |
| 43 | |
| 44 | Power domain topology framework platform API modifications |
| 45 | ---------------------------------------------------------- |
| 46 | |
| 47 | This removes the assumption in the PSCI implementation that MPIDR |
| 48 | based affinity instances map directly to power domains. A power domain, as |
| 49 | described in section 4.2 of `PSCI`_, could contain a core or a logical group |
| 50 | of cores (a cluster) which share some state on which power management |
| 51 | operations can be performed. The existing affinity instance based APIs |
| 52 | ``plat_get_aff_count()`` and ``plat_get_aff_state()`` are deprecated. The new |
| 53 | platform interfaces that are introduced for this framework are: |
| 54 | |
| 55 | - ``plat_core_pos_by_mpidr()`` |
| 56 | - ``plat_my_core_pos()`` |
| 57 | - ``plat_get_power_domain_tree_desc()`` |
| 58 | |
| 59 | ``plat_my_core_pos()`` and ``plat_core_pos_by_mpidr()`` are mandatory |
| 60 | and are meant to replace the existing ``platform_get_core_pos()`` API. |
| 61 | The description of these APIs can be found in the `Porting Guide`_. |
| 62 | These are used by the power domain topology framework such that: |
| 63 | |
| 64 | #. The generic PSCI code does not generate MPIDRs or use them to query the |
| 65 | platform about the number of power domains at a particular power level. The |
| 66 | ``plat_get_power_domain_tree_desc()`` provides a description of the power |
| 67 | domain tree on the SoC through a pointer to the byte array containing the |
| 68 | power domain topology tree description data structure. |
| 69 | |
| 70 | #. The linear indices returned by ``plat_core_pos_by_mpidr()`` and |
| 71 | ``plat_my_core_pos()`` are used to retrieve core power domain nodes from |
| 72 | the power domain tree. These core indices are unique for a core and it is a |
| 73 | number between ``0`` and ``PLATFORM_CORE_COUNT - 1``. The platform can choose |
| 74 | to implement a static mapping between ``MPIDR`` and core index or implement |
| 75 | a dynamic mapping, choosing to skip the unavailable/unused cores to compact |
| 76 | the core indices. |
| 77 | |
| 78 | In addition, the platforms must define the macros ``PLAT_NUM_PWR_DOMAINS`` and |
| 79 | ``PLAT_MAX_PWR_LVL`` which replace the macros ``PLAT_NUM_AFFS`` and |
| 80 | ``PLATFORM_MAX_AFFLVL`` respectively. On platforms where the affinity instances |
| 81 | correspond to power domains, the values of new macros remain the same as the |
| 82 | old ones. |
| 83 | |
| 84 | More details on the power domain topology description and its platform |
| 85 | interface can be found in `psci pd tree`_. |
| 86 | |
| 87 | Composite power state framework platform API modifications |
| 88 | ---------------------------------------------------------- |
| 89 | |
| 90 | The state-ID field in the power-state parameter of a CPU\_SUSPEND call can be |
| 91 | used to describe the composite power states specific to a platform. The existing |
| 92 | PSCI state coordination had the limitation that it operates on a run/off |
| 93 | granularity of power states and it did not interpret the state-ID field. This |
| 94 | was acceptable as the specification requirement in PSCI 0.2 and the framework's |
| 95 | approach to coordination only required maintaining a reference |
| 96 | count of the number of cores that have requested the cluster to remain powered. |
| 97 | |
| 98 | In the PSCI 1.0 specification, this approach is non optimal. If composite |
| 99 | power states are used, the PSCI implementation cannot make global |
| 100 | decisions about state coordination required because it does not understand the |
| 101 | platform specific states. |
| 102 | |
| 103 | The PSCI 1.0 implementation now defines a generic representation of the |
| 104 | power-state parameter : |
| 105 | |
| 106 | .. code:: c |
| 107 | |
| 108 | typedef struct psci_power_state { |
| 109 | plat_local_state_t pwr_domain_state[PLAT_MAX_PWR_LVL + 1]; |
| 110 | } psci_power_state_t; |
| 111 | |
| 112 | ``pwr_domain_state`` is an array where each index corresponds to a power level. |
| 113 | Each entry in the array contains the local power state the power domain at |
| 114 | that power level could enter. The meaning of the local power state value is |
| 115 | platform defined, and can vary between levels in a single platform. The PSCI |
| 116 | implementation constraints the values only so that it can classify the state |
| 117 | as RUN, RETENTION or OFF as required by the specification: |
| 118 | |
| 119 | #. Zero means RUN |
| 120 | |
| 121 | #. All OFF state values at all levels must be higher than all |
| 122 | RETENTION state values at all levels |
| 123 | |
| 124 | The platform is required to define the macros ``PLAT_MAX_RET_STATE`` and |
| 125 | ``PLAT_MAX_OFF_STATE`` to the framework. The requirement for these macros can |
| 126 | be found in the `Porting Guide <porting-guide.rst>`__. |
| 127 | |
| 128 | The PSCI 1.0 implementation adds support to involve the platform in state |
| 129 | coordination. This enables the platform to decide the final target state. |
| 130 | During a request to place a power domain in a low power state, the platform |
| 131 | is passed an array of requested ``plat_local_state_t`` for that power domain by |
| 132 | each core within it through the ``plat_get_target_pwr_state()`` API. This API |
| 133 | coordinates amongst these requested states to determine a target |
| 134 | ``plat_local_state_t`` for that power domain. A default weak implementation of |
| 135 | this API is provided in the platform layer which returns the minimum of the |
| 136 | requested local states back to the PSCI state coordination. More details |
| 137 | of ``plat_get_target_pwr_state()`` API can be found in the |
| 138 | `Porting Guide <porting-guide.rst#user-content-function--plat_get_target_pwr_state-optional>`__. |
| 139 | |
| 140 | The PSCI Generic implementation expects platform ports to populate the handlers |
| 141 | for the ``plat_psci_ops`` structure which is declared as : |
| 142 | |
| 143 | .. code:: c |
| 144 | |
| 145 | typedef struct plat_psci_ops { |
| 146 | void (*cpu_standby)(plat_local_state_t cpu_state); |
| 147 | int (*pwr_domain_on)(u_register_t mpidr); |
| 148 | void (*pwr_domain_off)(const psci_power_state_t *target_state); |
Varun Wadekar | ae87f4b | 2017-07-10 16:02:05 -0700 | [diff] [blame] | 149 | void (*pwr_domain_suspend_early)(const psci_power_state_t *target_state); |
Douglas Raillard | d7c21b7 | 2017-06-28 15:23:03 +0100 | [diff] [blame] | 150 | void (*pwr_domain_suspend)(const psci_power_state_t *target_state); |
| 151 | void (*pwr_domain_on_finish)(const psci_power_state_t *target_state); |
| 152 | void (*pwr_domain_suspend_finish)( |
| 153 | const psci_power_state_t *target_state); |
| 154 | void (*system_off)(void) __dead2; |
| 155 | void (*system_reset)(void) __dead2; |
| 156 | int (*validate_power_state)(unsigned int power_state, |
| 157 | psci_power_state_t *req_state); |
| 158 | int (*validate_ns_entrypoint)(unsigned long ns_entrypoint); |
| 159 | void (*get_sys_suspend_power_state)( |
| 160 | psci_power_state_t *req_state); |
Roberto Vargas | ff0509c | 2017-10-13 12:24:09 +0100 | [diff] [blame] | 161 | int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state, |
| 162 | int pwrlvl); |
| 163 | int (*translate_power_state_by_mpidr)(u_register_t mpidr, |
| 164 | unsigned int power_state, |
| 165 | psci_power_state_t *output_state); |
| 166 | int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level); |
Roberto Vargas | d963e3e | 2017-09-12 10:28:35 +0100 | [diff] [blame] | 167 | int (*mem_protect_chk)(uintptr_t base, u_register_t length); |
| 168 | int (*read_mem_protect)(int *val); |
| 169 | int (*write_mem_protect)(int val); |
| 170 | int (*system_reset2)(int is_vendor, |
| 171 | int reset_type, u_register_t cookie); |
Douglas Raillard | d7c21b7 | 2017-06-28 15:23:03 +0100 | [diff] [blame] | 172 | } plat_psci_ops_t; |
| 173 | |
| 174 | The description of these handlers can be found in the `Porting Guide <porting-guide.rst#user-content-function--plat_setup_psci_ops-mandatory>`__. |
| 175 | The previous ``plat_pm_ops`` structure is deprecated. Compared with the previous |
| 176 | handlers, the major differences are: |
| 177 | |
| 178 | - Difference in parameters |
| 179 | |
| 180 | The PSCI 1.0 implementation depends on the ``validate_power_state`` handler to |
| 181 | convert the power-state parameter (possibly encoding a composite power state) |
| 182 | passed in a PSCI ``CPU_SUSPEND`` to the ``psci_power_state`` format. This handler |
| 183 | is now mandatory for PSCI ``CPU_SUSPEND`` support. |
| 184 | |
Varun Wadekar | ae87f4b | 2017-07-10 16:02:05 -0700 | [diff] [blame] | 185 | The ``plat_psci_ops`` handlers, ``pwr_domain_off``, ``pwr_domain_suspend_early`` |
| 186 | and ``pwr_domain_suspend``, are passed the target local state for each affected |
| 187 | power domain. The platform must execute operations specific to these target |
| 188 | states. Similarly, ``pwr_domain_on_finish`` and ``pwr_domain_suspend_finish`` |
| 189 | are passed the local states of the affected power domains before wakeup. The |
| 190 | platform must execute actions to restore these power domains from these specific |
Douglas Raillard | d7c21b7 | 2017-06-28 15:23:03 +0100 | [diff] [blame] | 191 | local states. |
| 192 | |
| 193 | - Difference in invocation |
| 194 | |
| 195 | Whereas the power management handlers in ``plat_pm_ops`` used to be invoked |
| 196 | for each affinity level till the target affinity level, the new handlers |
| 197 | are only invoked once. The ``target_state`` encodes the target low power |
| 198 | state or the low power state woken up from for each affected power domain. |
| 199 | |
| 200 | - Difference in semantics |
| 201 | |
| 202 | Although the previous ``suspend`` handlers could be used for power down as well |
| 203 | as retention at different affinity levels, the new handlers make this support |
| 204 | explicit. The ``pwr_domain_suspend`` can be used to specify powerdown and |
| 205 | retention at various power domain levels subject to the conditions mentioned |
| 206 | in section 4.2.1 of `PSCI`_ |
| 207 | |
| 208 | Unlike the previous ``standby`` handler, the ``cpu_standby()`` handler is only used |
| 209 | as a fast path for placing a core power domain into a standby or retention |
| 210 | state. |
| 211 | |
| 212 | The below diagram shows the sequence of a PSCI SUSPEND call and the interaction |
| 213 | with the platform layer depicting the exchange of data between PSCI Generic |
| 214 | layer and the platform layer. |
| 215 | |
| 216 | |Image 1| |
| 217 | |
| 218 | Refer `plat/arm/board/fvp/fvp\_pm.c`_ for the implementation details of |
| 219 | these handlers for the FVP. The commit `38dce70f51fb83b27958ba3e2ad15f5635cb1061`_ |
| 220 | demonstrates the migration of ARM reference platforms to the new platform API. |
| 221 | |
| 222 | Miscellaneous modifications |
| 223 | --------------------------- |
| 224 | |
| 225 | In addition to the framework changes, unification of warm reset entry points on |
| 226 | wakeup from low power modes has led to a change in the platform API. In the |
| 227 | earlier implementation, the warm reset entry used to be programmed into the |
| 228 | mailboxes by the 'ON' and 'SUSPEND' power management hooks. In the PSCI 1.0 |
| 229 | implementation, this information is not required, because it can figure that |
| 230 | out by querying affinity info state whether to execute the 'suspend\_finisher\` |
| 231 | or 'on\_finisher'. |
| 232 | |
| 233 | As a result, the warm reset entry point must be programmed only once. The |
| 234 | ``plat_setup_psci_ops()`` API takes the secure entry point as an |
| 235 | additional parameter to enable the platforms to configure their mailbox. The |
| 236 | plat\_psci\_ops handlers ``pwr_domain_on`` and ``pwr_domain_suspend`` no longer take |
| 237 | the warm reset entry point as a parameter. |
| 238 | |
| 239 | Also, some platform APIs which took ``MPIDR`` as an argument were only ever |
| 240 | invoked to perform actions specific to the caller core which makes the argument |
| 241 | redundant. Therefore the platform APIs ``plat_get_my_entrypoint()``, |
| 242 | ``plat_is_my_cpu_primary()``, ``plat_set_my_stack()`` and |
| 243 | ``plat_get_my_stack()`` are defined which are meant to be invoked only for |
| 244 | operations on the current caller core instead of ``platform_get_entrypoint()``, |
| 245 | ``platform_is_primary_cpu()``, ``platform_set_stack()`` and ``platform_get_stack()``. |
| 246 | |
| 247 | Compatibility layer |
| 248 | ------------------- |
| 249 | |
| 250 | To ease the migration of the platform ports to the new porting interface, |
| 251 | a compatibility layer is introduced that essentially implements a glue layer |
| 252 | between the old platform API and the new API. The build flag |
| 253 | ``ENABLE_PLAT_COMPAT`` (enabled by default), specifies whether to enable this |
| 254 | layer or not. A platform port which has migrated to the new API can disable |
| 255 | this flag within the platform specific makefile. |
| 256 | |
| 257 | The compatibility layer works on the assumption that the onus of |
| 258 | state coordination, in case multiple low power states are supported, |
| 259 | is with the platform. The generic PSCI implementation only takes into |
| 260 | account whether the suspend request is power down or not. This corresponds |
| 261 | with the behavior of the PSCI implementation before the introduction of |
| 262 | new frameworks. Also, it assumes that the affinity levels of the platform |
| 263 | correspond directly to the power domain levels. |
| 264 | |
| 265 | The compatibility layer dynamically constructs the new topology |
| 266 | description array by querying the platform using ``plat_get_aff_count()`` |
| 267 | and ``plat_get_aff_state()`` APIs. The linear index returned by |
| 268 | ``platform_get_core_pos()`` is used as the core index for the cores. The |
| 269 | higher level (non-core) power domain nodes must know the cores contained |
| 270 | within its domain. It does so by storing the core index of first core |
| 271 | within it and number of core indexes following it. This means that core |
| 272 | indices returned by ``platform_get_core_pos()`` for cores within a particular |
| 273 | power domain must be consecutive. We expect that this is the case for most |
| 274 | platform ports including ARM reference platforms. |
| 275 | |
| 276 | The old PSCI helpers like ``psci_get_suspend_powerstate()``, |
| 277 | ``psci_get_suspend_stateid()``, ``psci_get_suspend_stateid_by_mpidr()``, |
| 278 | ``psci_get_max_phys_off_afflvl()`` and ``psci_get_suspend_afflvl()`` are also |
| 279 | implemented for the compatibility layer. This allows the existing |
| 280 | platform ports to work with the new PSCI frameworks without significant |
| 281 | rework. |
| 282 | |
| 283 | Deprecated Platform API |
| 284 | ----------------------- |
| 285 | |
| 286 | This section documents the deprecated platform porting API. |
| 287 | |
| 288 | Common mandatory modifications |
| 289 | ------------------------------ |
| 290 | |
| 291 | The mandatory macros to be defined by the platform port in ``platform_def.h`` |
| 292 | |
| 293 | - **#define : PLATFORM\_NUM\_AFFS** |
| 294 | |
| 295 | Defines the total number of nodes in the affinity hierarchy at all affinity |
| 296 | levels used by the platform. |
| 297 | |
| 298 | - **#define : PLATFORM\_MAX\_AFFLVL** |
| 299 | |
| 300 | Defines the maximum affinity level that the power management operations |
| 301 | should apply to. ARMv8-A has support for four affinity levels. It is likely |
| 302 | that hardware will implement fewer affinity levels. This macro allows the |
| 303 | PSCI implementation to consider only those affinity levels in the system |
| 304 | that the platform implements. For example, the Base AEM FVP implements two |
| 305 | clusters with a configurable number of cores. It reports the maximum |
| 306 | affinity level as 1, resulting in PSCI power control up to the cluster |
| 307 | level. |
| 308 | |
| 309 | The following functions must be implemented by the platform port to enable |
| 310 | the reset vector code to perform the required tasks. |
| 311 | |
| 312 | Function : platform\_get\_entrypoint() [mandatory] |
| 313 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 314 | |
| 315 | :: |
| 316 | |
| 317 | Argument : unsigned long |
| 318 | Return : unsigned long |
| 319 | |
| 320 | This function is called with the ``SCTLR.M`` and ``SCTLR.C`` bits disabled. The core |
| 321 | is identified by its ``MPIDR``, which is passed as the argument. The function is |
| 322 | responsible for distinguishing between a warm and cold reset using platform- |
| 323 | specific means. If it is a warm reset, it returns the entrypoint into the |
| 324 | BL31 image that the core must jump to. If it is a cold reset, this function |
| 325 | must return zero. |
| 326 | |
| 327 | This function is also responsible for implementing a platform-specific mechanism |
| 328 | to handle the condition where the core has been warm reset but there is no |
| 329 | entrypoint to jump to. |
| 330 | |
| 331 | This function does not follow the Procedure Call Standard used by the |
| 332 | Application Binary Interface for the ARM 64-bit architecture. The caller should |
| 333 | not assume that callee saved registers are preserved across a call to this |
| 334 | function. |
| 335 | |
| 336 | Function : platform\_is\_primary\_cpu() [mandatory] |
| 337 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 338 | |
| 339 | :: |
| 340 | |
| 341 | Argument : unsigned long |
| 342 | Return : unsigned int |
| 343 | |
| 344 | This function identifies a core by its ``MPIDR``, which is passed as the argument, |
| 345 | to determine whether this core is the primary core or a secondary core. A return |
| 346 | value of zero indicates that the core is not the primary core, while a non-zero |
| 347 | return value indicates that the core is the primary core. |
| 348 | |
| 349 | Common optional modifications |
| 350 | ----------------------------- |
| 351 | |
| 352 | Function : platform\_get\_core\_pos() |
| 353 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 354 | |
| 355 | :: |
| 356 | |
| 357 | Argument : unsigned long |
| 358 | Return : int |
| 359 | |
| 360 | A platform may need to convert the ``MPIDR`` of a core to an absolute number, which |
| 361 | can be used as a core-specific linear index into blocks of memory (for example |
| 362 | while allocating per-core stacks). This routine contains a simple mechanism |
| 363 | to perform this conversion, using the assumption that each cluster contains a |
| 364 | maximum of four cores: |
| 365 | |
| 366 | :: |
| 367 | |
| 368 | linear index = cpu_id + (cluster_id * 4) |
| 369 | |
| 370 | cpu_id = 8-bit value in MPIDR at affinity level 0 |
| 371 | cluster_id = 8-bit value in MPIDR at affinity level 1 |
| 372 | |
| 373 | Function : platform\_set\_stack() |
| 374 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 375 | |
| 376 | :: |
| 377 | |
| 378 | Argument : unsigned long |
| 379 | Return : void |
| 380 | |
| 381 | This function sets the current stack pointer to the normal memory stack that |
| 382 | has been allocated for the core specified by MPIDR. For BL images that only |
| 383 | require a stack for the primary core the parameter is ignored. The size of |
| 384 | the stack allocated to each core is specified by the platform defined constant |
| 385 | ``PLATFORM_STACK_SIZE``. |
| 386 | |
| 387 | Common implementations of this function for the UP and MP BL images are |
| 388 | provided in `plat/common/aarch64/platform\_up\_stack.S`_ and |
| 389 | `plat/common/aarch64/platform\_mp\_stack.S`_ |
| 390 | |
| 391 | Function : platform\_get\_stack() |
| 392 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 393 | |
| 394 | :: |
| 395 | |
| 396 | Argument : unsigned long |
| 397 | Return : unsigned long |
| 398 | |
| 399 | This function returns the base address of the normal memory stack that |
| 400 | has been allocated for the core specificed by MPIDR. For BL images that only |
| 401 | require a stack for the primary core the parameter is ignored. The size of |
| 402 | the stack allocated to each core is specified by the platform defined constant |
| 403 | ``PLATFORM_STACK_SIZE``. |
| 404 | |
| 405 | Common implementations of this function for the UP and MP BL images are |
| 406 | provided in `plat/common/aarch64/platform\_up\_stack.S`_ and |
| 407 | `plat/common/aarch64/platform\_mp\_stack.S`_ |
| 408 | |
| 409 | Modifications for Power State Coordination Interface (in BL31) |
| 410 | -------------------------------------------------------------- |
| 411 | |
| 412 | The following functions must be implemented to initialize PSCI functionality in |
| 413 | the ARM Trusted Firmware. |
| 414 | |
| 415 | Function : plat\_get\_aff\_count() [mandatory] |
| 416 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 417 | |
| 418 | :: |
| 419 | |
| 420 | Argument : unsigned int, unsigned long |
| 421 | Return : unsigned int |
| 422 | |
| 423 | This function may execute with the MMU and data caches enabled if the platform |
| 424 | port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only |
| 425 | called by the primary core. |
| 426 | |
| 427 | This function is called by the PSCI initialization code to detect the system |
| 428 | topology. Its purpose is to return the number of affinity instances implemented |
| 429 | at a given ``affinity level`` (specified by the first argument) and a given |
| 430 | ``MPIDR`` (specified by the second argument). For example, on a dual-cluster |
| 431 | system where first cluster implements two cores and the second cluster |
| 432 | implements four cores, a call to this function with an ``MPIDR`` corresponding |
| 433 | to the first cluster (``0x0``) and affinity level 0, would return 2. A call |
| 434 | to this function with an ``MPIDR`` corresponding to the second cluster (``0x100``) |
| 435 | and affinity level 0, would return 4. |
| 436 | |
| 437 | Function : plat\_get\_aff\_state() [mandatory] |
| 438 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 439 | |
| 440 | :: |
| 441 | |
| 442 | Argument : unsigned int, unsigned long |
| 443 | Return : unsigned int |
| 444 | |
| 445 | This function may execute with the MMU and data caches enabled if the platform |
| 446 | port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only |
| 447 | called by the primary core. |
| 448 | |
| 449 | This function is called by the PSCI initialization code. Its purpose is to |
| 450 | return the state of an affinity instance. The affinity instance is determined by |
| 451 | the affinity ID at a given ``affinity level`` (specified by the first argument) |
| 452 | and an ``MPIDR`` (specified by the second argument). The state can be one of |
| 453 | ``PSCI_AFF_PRESENT`` or ``PSCI_AFF_ABSENT``. The latter state is used to cater for |
| 454 | system topologies where certain affinity instances are unimplemented. For |
| 455 | example, consider a platform that implements a single cluster with four cores and |
| 456 | another core implemented directly on the interconnect with the cluster. The |
| 457 | ``MPIDR``\ s of the cluster would range from ``0x0-0x3``. The ``MPIDR`` of the single |
| 458 | core is 0x100 to indicate that it does not belong to cluster 0. Cluster 1 |
| 459 | is missing but needs to be accounted for to reach this single core in the |
| 460 | topology tree. Therefore it is marked as ``PSCI_AFF_ABSENT``. |
| 461 | |
| 462 | Function : platform\_setup\_pm() [mandatory] |
| 463 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 464 | |
| 465 | :: |
| 466 | |
| 467 | Argument : const plat_pm_ops ** |
| 468 | Return : int |
| 469 | |
| 470 | This function may execute with the MMU and data caches enabled if the platform |
| 471 | port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only |
| 472 | called by the primary core. |
| 473 | |
| 474 | This function is called by PSCI initialization code. Its purpose is to export |
| 475 | handler routines for platform-specific power management actions by populating |
| 476 | the passed pointer with a pointer to the private ``plat_pm_ops`` structure of |
| 477 | BL31. |
| 478 | |
| 479 | A description of each member of this structure is given below. A platform port |
| 480 | is expected to implement these handlers if the corresponding PSCI operation |
| 481 | is to be supported and these handlers are expected to succeed if the return |
| 482 | type is ``void``. |
| 483 | |
| 484 | plat\_pm\_ops.affinst\_standby() |
| 485 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 486 | |
| 487 | Perform the platform-specific setup to enter the standby state indicated by the |
| 488 | passed argument. The generic code expects the handler to succeed. |
| 489 | |
| 490 | plat\_pm\_ops.affinst\_on() |
| 491 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 492 | |
| 493 | Perform the platform specific setup to power on an affinity instance, specified |
| 494 | by the ``MPIDR`` (first argument) and ``affinity level`` (third argument). The |
| 495 | ``state`` (fourth argument) contains the current state of that affinity instance |
| 496 | (ON or OFF). This is useful to determine whether any action must be taken. For |
| 497 | example, while powering on a core, the cluster that contains this core might |
| 498 | already be in the ON state. The platform decides what actions must be taken to |
| 499 | transition from the current state to the target state (indicated by the power |
| 500 | management operation). The generic code expects the platform to return |
| 501 | E\_SUCCESS on success or E\_INTERN\_FAIL for any failure. |
| 502 | |
| 503 | plat\_pm\_ops.affinst\_off() |
| 504 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 505 | |
| 506 | Perform the platform specific setup to power off an affinity instance of the |
| 507 | calling core. It is called by the PSCI ``CPU_OFF`` API implementation. |
| 508 | |
| 509 | The ``affinity level`` (first argument) and ``state`` (second argument) have |
| 510 | a similar meaning as described in the ``affinst_on()`` operation. They |
| 511 | identify the affinity instance on which the call is made and its |
| 512 | current state. This gives the platform port an indication of the |
| 513 | state transition it must make to perform the requested action. For example, if |
| 514 | the calling core is the last powered on core in the cluster, after powering down |
| 515 | affinity level 0 (the core), the platform port should power down affinity |
| 516 | level 1 (the cluster) as well. The generic code expects the handler to succeed. |
| 517 | |
| 518 | plat\_pm\_ops.affinst\_suspend() |
| 519 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 520 | |
| 521 | Perform the platform specific setup to power off an affinity instance of the |
| 522 | calling core. It is called by the PSCI ``CPU_SUSPEND`` API and ``SYSTEM_SUSPEND`` |
| 523 | API implementation |
| 524 | |
| 525 | The ``affinity level`` (second argument) and ``state`` (third argument) have a |
| 526 | similar meaning as described in the ``affinst_on()`` operation. They are used to |
| 527 | identify the affinity instance on which the call is made and its current state. |
| 528 | This gives the platform port an indication of the state transition it must |
| 529 | make to perform the requested action. For example, if the calling core is the |
| 530 | last powered on core in the cluster, after powering down affinity level 0 |
| 531 | (the core), the platform port should power down affinity level 1 (the cluster) |
| 532 | as well. |
| 533 | |
| 534 | The difference between turning an affinity instance off and suspending it |
| 535 | is that in the former case, the affinity instance is expected to re-initialize |
| 536 | its state when it is next powered on (see ``affinst_on_finish()``). In the latter |
| 537 | case, the affinity instance is expected to save enough state so that it can |
| 538 | resume execution by restoring this state when it is powered on (see |
| 539 | ``affinst_suspend_finish()``).The generic code expects the handler to succeed. |
| 540 | |
| 541 | plat\_pm\_ops.affinst\_on\_finish() |
| 542 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 543 | |
| 544 | This function is called by the PSCI implementation after the calling core is |
| 545 | powered on and released from reset in response to an earlier PSCI ``CPU_ON`` call. |
| 546 | It performs the platform-specific setup required to initialize enough state for |
| 547 | this core to enter the Normal world and also provide secure runtime firmware |
| 548 | services. |
| 549 | |
| 550 | The ``affinity level`` (first argument) and ``state`` (second argument) have a |
| 551 | similar meaning as described in the previous operations. The generic code |
| 552 | expects the handler to succeed. |
| 553 | |
| 554 | plat\_pm\_ops.affinst\_suspend\_finish() |
| 555 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 556 | |
| 557 | This function is called by the PSCI implementation after the calling core is |
| 558 | powered on and released from reset in response to an asynchronous wakeup |
| 559 | event, for example a timer interrupt that was programmed by the core during the |
| 560 | ``CPU_SUSPEND`` call or ``SYSTEM_SUSPEND`` call. It performs the platform-specific |
| 561 | setup required to restore the saved state for this core to resume execution |
| 562 | in the Normal world and also provide secure runtime firmware services. |
| 563 | |
| 564 | The ``affinity level`` (first argument) and ``state`` (second argument) have a |
| 565 | similar meaning as described in the previous operations. The generic code |
| 566 | expects the platform to succeed. |
| 567 | |
| 568 | plat\_pm\_ops.validate\_power\_state() |
| 569 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 570 | |
| 571 | This function is called by the PSCI implementation during the ``CPU_SUSPEND`` |
| 572 | call to validate the ``power_state`` parameter of the PSCI API. If the |
| 573 | ``power_state`` is known to be invalid, the platform must return |
| 574 | PSCI\_E\_INVALID\_PARAMS as an error, which is propagated back to the Normal |
| 575 | world PSCI client. |
| 576 | |
| 577 | plat\_pm\_ops.validate\_ns\_entrypoint() |
| 578 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 579 | |
| 580 | This function is called by the PSCI implementation during the ``CPU_SUSPEND``, |
| 581 | ``SYSTEM_SUSPEND`` and ``CPU_ON`` calls to validate the Non-secure ``entry_point`` |
| 582 | parameter passed by the Normal world. If the ``entry_point`` is known to be |
| 583 | invalid, the platform must return PSCI\_E\_INVALID\_PARAMS as an error, which is |
| 584 | propagated back to the Normal world PSCI client. |
| 585 | |
| 586 | plat\_pm\_ops.get\_sys\_suspend\_power\_state() |
| 587 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 588 | |
| 589 | This function is called by the PSCI implementation during the ``SYSTEM_SUSPEND`` |
| 590 | call to return the ``power_state`` parameter. This allows the platform to encode |
| 591 | the appropriate State-ID field within the ``power_state`` parameter which can be |
| 592 | utilized in ``affinst_suspend()`` to suspend to system affinity level. The |
| 593 | ``power_state`` parameter should be in the same format as specified by the |
| 594 | PSCI specification for the CPU\_SUSPEND API. |
| 595 | |
| 596 | -------------- |
| 597 | |
| 598 | *Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.* |
| 599 | |
| 600 | .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf |
| 601 | .. _Porting Guide: porting-guide.rst#user-content-function--plat_my_core_pos |
| 602 | .. _psci pd tree: psci-pd-tree.rst |
| 603 | .. _plat/arm/board/fvp/fvp\_pm.c: ../plat/arm/board/fvp/fvp_pm.c |
| 604 | .. _38dce70f51fb83b27958ba3e2ad15f5635cb1061: https://github.com/ARM-software/arm-trusted-firmware/commit/38dce70f51fb83b27958ba3e2ad15f5635cb1061 |
| 605 | .. _plat/common/aarch64/platform\_up\_stack.S: ../plat/common/aarch64/platform_up_stack.S |
| 606 | .. _plat/common/aarch64/platform\_mp\_stack.S: ../plat/common/aarch64/platform_mp_stack.S |
| 607 | |
| 608 | .. |Image 1| image:: diagrams/psci-suspend-sequence.png?raw=true |