xref: /rk3399_ARM-atf/docs/design/psci-pd-tree.rst (revision 8aa050554b996406231a66a048b56fa03ba220c8)
1*8aa05055SPaul BeesleyPSCI Power Domain Tree Structure
2*8aa05055SPaul Beesley================================
340d553cfSPaul Beesley
440d553cfSPaul Beesley.. contents::
540d553cfSPaul Beesley
640d553cfSPaul Beesley--------------
740d553cfSPaul Beesley
840d553cfSPaul BeesleyRequirements
940d553cfSPaul Beesley------------
1040d553cfSPaul Beesley
1140d553cfSPaul Beesley#. A platform must export the ``plat_get_aff_count()`` and
1240d553cfSPaul Beesley   ``plat_get_aff_state()`` APIs to enable the generic PSCI code to
1340d553cfSPaul Beesley   populate a tree that describes the hierarchy of power domains in the
1440d553cfSPaul Beesley   system. This approach is inflexible because a change to the topology
1540d553cfSPaul Beesley   requires a change in the code.
1640d553cfSPaul Beesley
1740d553cfSPaul Beesley   It would be much simpler for the platform to describe its power domain tree
1840d553cfSPaul Beesley   in a data structure.
1940d553cfSPaul Beesley
2040d553cfSPaul Beesley#. The generic PSCI code generates MPIDRs in order to populate the power domain
2140d553cfSPaul Beesley   tree. It also uses an MPIDR to find a node in the tree. The assumption that
2240d553cfSPaul Beesley   a platform will use exactly the same MPIDRs as generated by the generic PSCI
2340d553cfSPaul Beesley   code is not scalable. The use of an MPIDR also restricts the number of
2440d553cfSPaul Beesley   levels in the power domain tree to four.
2540d553cfSPaul Beesley
2640d553cfSPaul Beesley   Therefore, there is a need to decouple allocation of MPIDRs from the
2740d553cfSPaul Beesley   mechanism used to populate the power domain topology tree.
2840d553cfSPaul Beesley
2940d553cfSPaul Beesley#. The current arrangement of the power domain tree requires a binary search
3040d553cfSPaul Beesley   over the sibling nodes at a particular level to find a specified power
3140d553cfSPaul Beesley   domain node. During a power management operation, the tree is traversed from
3240d553cfSPaul Beesley   a 'start' to an 'end' power level. The binary search is required to find the
3340d553cfSPaul Beesley   node at each level. The natural way to perform this traversal is to
3440d553cfSPaul Beesley   start from a leaf node and follow the parent node pointer to reach the end
3540d553cfSPaul Beesley   level.
3640d553cfSPaul Beesley
3740d553cfSPaul Beesley   Therefore, there is a need to define data structures that implement the tree in
3840d553cfSPaul Beesley   a way which facilitates such a traversal.
3940d553cfSPaul Beesley
4040d553cfSPaul Beesley#. The attributes of a core power domain differ from the attributes of power
4140d553cfSPaul Beesley   domains at higher levels. For example, only a core power domain can be identified
4240d553cfSPaul Beesley   using an MPIDR. There is no requirement to perform state coordination while
4340d553cfSPaul Beesley   performing a power management operation on the core power domain.
4440d553cfSPaul Beesley
4540d553cfSPaul Beesley   Therefore, there is a need to implement the tree in a way which facilitates this
4640d553cfSPaul Beesley   distinction between a leaf and non-leaf node and any associated
4740d553cfSPaul Beesley   optimizations.
4840d553cfSPaul Beesley
4940d553cfSPaul Beesley--------------
5040d553cfSPaul Beesley
5140d553cfSPaul BeesleyDesign
5240d553cfSPaul Beesley------
5340d553cfSPaul Beesley
5440d553cfSPaul BeesleyDescribing a power domain tree
5540d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5640d553cfSPaul Beesley
5740d553cfSPaul BeesleyTo fulfill requirement 1., the existing platform APIs
5840d553cfSPaul Beesley``plat_get_aff_count()`` and ``plat_get_aff_state()`` have been
5940d553cfSPaul Beesleyremoved. A platform must define an array of unsigned chars such that:
6040d553cfSPaul Beesley
6140d553cfSPaul Beesley#. The first entry in the array specifies the number of power domains at the
6240d553cfSPaul Beesley   highest power level implemented in the platform. This caters for platforms
6340d553cfSPaul Beesley   where the power domain tree does not have a single root node, for example,
6440d553cfSPaul Beesley   the FVP has two cluster power domains at the highest level (1).
6540d553cfSPaul Beesley
6640d553cfSPaul Beesley#. Each subsequent entry corresponds to a power domain and contains the number
6740d553cfSPaul Beesley   of power domains that are its direct children.
6840d553cfSPaul Beesley
6940d553cfSPaul Beesley#. The size of the array minus the first entry will be equal to the number of
7040d553cfSPaul Beesley   non-leaf power domains.
7140d553cfSPaul Beesley
7240d553cfSPaul Beesley#. The value in each entry in the array is used to find the number of entries
7340d553cfSPaul Beesley   to consider at the next level. The sum of the values (number of children) of
7440d553cfSPaul Beesley   all the entries at a level specifies the number of entries in the array for
7540d553cfSPaul Beesley   the next level.
7640d553cfSPaul Beesley
7740d553cfSPaul BeesleyThe following example power domain topology tree will be used to describe the
7840d553cfSPaul Beesleyabove text further. The leaf and non-leaf nodes in this tree have been numbered
7940d553cfSPaul Beesleyseparately.
8040d553cfSPaul Beesley
8140d553cfSPaul Beesley::
8240d553cfSPaul Beesley
8340d553cfSPaul Beesley                                         +-+
8440d553cfSPaul Beesley                                         |0|
8540d553cfSPaul Beesley                                         +-+
8640d553cfSPaul Beesley                                        /   \
8740d553cfSPaul Beesley                                       /     \
8840d553cfSPaul Beesley                                      /       \
8940d553cfSPaul Beesley                                     /         \
9040d553cfSPaul Beesley                                    /           \
9140d553cfSPaul Beesley                                   /             \
9240d553cfSPaul Beesley                                  /               \
9340d553cfSPaul Beesley                                 /                 \
9440d553cfSPaul Beesley                                /                   \
9540d553cfSPaul Beesley                               /                     \
9640d553cfSPaul Beesley                            +-+                       +-+
9740d553cfSPaul Beesley                            |1|                       |2|
9840d553cfSPaul Beesley                            +-+                       +-+
9940d553cfSPaul Beesley                           /   \                     /   \
10040d553cfSPaul Beesley                          /     \                   /     \
10140d553cfSPaul Beesley                         /       \                 /       \
10240d553cfSPaul Beesley                        /         \               /         \
10340d553cfSPaul Beesley                     +-+           +-+         +-+           +-+
10440d553cfSPaul Beesley                     |3|           |4|         |5|           |6|
10540d553cfSPaul Beesley                     +-+           +-+         +-+           +-+
10640d553cfSPaul Beesley            +---+-----+    +----+----|     +----+----+     +----+-----+-----+
10740d553cfSPaul Beesley            |   |     |    |    |    |     |    |    |     |    |     |     |
10840d553cfSPaul Beesley            |   |     |    |    |    |     |    |    |     |    |     |     |
10940d553cfSPaul Beesley            v   v     v    v    v    v     v    v    v     v    v     v     v
11040d553cfSPaul Beesley          +-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+
11140d553cfSPaul Beesley          |0|  |1|   |2|  |3|  |4|  |5|   |6|  |7|  |8|   |9|  |10|  |11|  |12|
11240d553cfSPaul Beesley          +-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+
11340d553cfSPaul Beesley
11440d553cfSPaul BeesleyThis tree is defined by the platform as the array described above as follows:
11540d553cfSPaul Beesley
11640d553cfSPaul Beesley::
11740d553cfSPaul Beesley
11840d553cfSPaul Beesley        #define PLAT_NUM_POWER_DOMAINS       20
11940d553cfSPaul Beesley        #define PLATFORM_CORE_COUNT          13
12040d553cfSPaul Beesley        #define PSCI_NUM_NON_CPU_PWR_DOMAINS \
12140d553cfSPaul Beesley                           (PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT)
12240d553cfSPaul Beesley
12340d553cfSPaul Beesley        unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4};
12440d553cfSPaul Beesley
12540d553cfSPaul BeesleyRemoving assumptions about MPIDRs used in a platform
12640d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12740d553cfSPaul Beesley
12840d553cfSPaul BeesleyTo fulfill requirement 2., it is assumed that the platform assigns a
12940d553cfSPaul Beesleyunique number (core index) between ``0`` and ``PLAT_CORE_COUNT - 1`` to each core
13040d553cfSPaul Beesleypower domain. MPIDRs could be allocated in any manner and will not be used to
13140d553cfSPaul Beesleypopulate the tree.
13240d553cfSPaul Beesley
13340d553cfSPaul Beesley``plat_core_pos_by_mpidr(mpidr)`` will return the core index for the core
13440d553cfSPaul Beesleycorresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed
13540d553cfSPaul Beesleywhich is not allocated or corresponds to an absent core. The semantics of this
13640d553cfSPaul Beesleyplatform API have changed since it is required to validate the passed MPIDR. It
13740d553cfSPaul Beesleyhas been made a mandatory API as a result.
13840d553cfSPaul Beesley
13940d553cfSPaul BeesleyAnother mandatory API, ``plat_my_core_pos()`` has been added to return the core
14040d553cfSPaul Beesleyindex for the calling core. This API provides a more lightweight mechanism to get
14140d553cfSPaul Beesleythe index since there is no need to validate the MPIDR of the calling core.
14240d553cfSPaul Beesley
14340d553cfSPaul BeesleyThe platform should assign the core indices (as illustrated in the diagram above)
14440d553cfSPaul Beesleysuch that, if the core nodes are numbered from left to right, then the index
14540d553cfSPaul Beesleyfor a core domain will be the same as the index returned by
14640d553cfSPaul Beesley``plat_core_pos_by_mpidr()`` or ``plat_my_core_pos()`` for that core. This
14740d553cfSPaul Beesleyrelationship allows the core nodes to be allocated in a separate array
14840d553cfSPaul Beesley(requirement 4.) during ``psci_setup()`` in such an order that the index of the
14940d553cfSPaul Beesleycore in the array is the same as the return value from these APIs.
15040d553cfSPaul Beesley
15140d553cfSPaul BeesleyDealing with holes in MPIDR allocation
15240d553cfSPaul Beesley^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15340d553cfSPaul Beesley
15440d553cfSPaul BeesleyFor platforms where the number of allocated MPIDRs is equal to the number of
15540d553cfSPaul Beesleycore power domains, for example, Juno and FVPs, the logic to convert an MPIDR to
15640d553cfSPaul Beesleya core index should remain unchanged. Both Juno and FVP use a simple collision
15740d553cfSPaul Beesleyproof hash function to do this.
15840d553cfSPaul Beesley
15940d553cfSPaul BeesleyIt is possible that on some platforms, the allocation of MPIDRs is not
16040d553cfSPaul Beesleycontiguous or certain cores have been disabled. This essentially means that the
16140d553cfSPaul BeesleyMPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs
16240d553cfSPaul Beesleyused by the platform is not equal to the number of core power domains.
16340d553cfSPaul Beesley
16440d553cfSPaul BeesleyThe platform could adopt one of the following approaches to deal with this
16540d553cfSPaul Beesleyscenario:
16640d553cfSPaul Beesley
16740d553cfSPaul Beesley#. Implement more complex logic to convert a valid MPIDR to a core index while
16840d553cfSPaul Beesley   maintaining the relationship described earlier. This means that the power
16940d553cfSPaul Beesley   domain tree descriptor will not describe any core power domains which are
17040d553cfSPaul Beesley   disabled or absent. Entries will not be allocated in the tree for these
17140d553cfSPaul Beesley   domains.
17240d553cfSPaul Beesley
17340d553cfSPaul Beesley#. Treat unallocated MPIDRs and disabled cores as absent but still describe them
17440d553cfSPaul Beesley   in the power domain descriptor, that is, the number of core nodes described
17540d553cfSPaul Beesley   is equal to the size of the range of MPIDRs allocated. This approach will
17640d553cfSPaul Beesley   lead to memory wastage since entries will be allocated in the tree but will
17740d553cfSPaul Beesley   allow use of a simpler logic to convert an MPIDR to a core index.
17840d553cfSPaul Beesley
17940d553cfSPaul BeesleyTraversing through and distinguishing between core and non-core power domains
18040d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18140d553cfSPaul Beesley
18240d553cfSPaul BeesleyTo fulfill requirement 3 and 4, separate data structures have been defined
18340d553cfSPaul Beesleyto represent leaf and non-leaf power domain nodes in the tree.
18440d553cfSPaul Beesley
18540d553cfSPaul Beesley.. code:: c
18640d553cfSPaul Beesley
18740d553cfSPaul Beesley    /*******************************************************************************
18840d553cfSPaul Beesley     * The following two data structures implement the power domain tree. The tree
18940d553cfSPaul Beesley     * is used to track the state of all the nodes i.e. power domain instances
19040d553cfSPaul Beesley     * described by the platform. The tree consists of nodes that describe CPU power
19140d553cfSPaul Beesley     * domains i.e. leaf nodes and all other power domains which are parents of a
19240d553cfSPaul Beesley     * CPU power domain i.e. non-leaf nodes.
19340d553cfSPaul Beesley     ******************************************************************************/
19440d553cfSPaul Beesley    typedef struct non_cpu_pwr_domain_node {
19540d553cfSPaul Beesley        /*
19640d553cfSPaul Beesley         * Index of the first CPU power domain node level 0 which has this node
19740d553cfSPaul Beesley         * as its parent.
19840d553cfSPaul Beesley         */
19940d553cfSPaul Beesley        unsigned int cpu_start_idx;
20040d553cfSPaul Beesley
20140d553cfSPaul Beesley        /*
20240d553cfSPaul Beesley         * Number of CPU power domains which are siblings of the domain indexed
20340d553cfSPaul Beesley         * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
20440d553cfSPaul Beesley         * -> cpu_start_idx + ncpus' have this node as their parent.
20540d553cfSPaul Beesley         */
20640d553cfSPaul Beesley        unsigned int ncpus;
20740d553cfSPaul Beesley
20840d553cfSPaul Beesley        /* Index of the parent power domain node */
20940d553cfSPaul Beesley        unsigned int parent_node;
21040d553cfSPaul Beesley
21140d553cfSPaul Beesley        -----
21240d553cfSPaul Beesley    } non_cpu_pd_node_t;
21340d553cfSPaul Beesley
21440d553cfSPaul Beesley    typedef struct cpu_pwr_domain_node {
21540d553cfSPaul Beesley        u_register_t mpidr;
21640d553cfSPaul Beesley
21740d553cfSPaul Beesley        /* Index of the parent power domain node */
21840d553cfSPaul Beesley        unsigned int parent_node;
21940d553cfSPaul Beesley
22040d553cfSPaul Beesley        -----
22140d553cfSPaul Beesley    } cpu_pd_node_t;
22240d553cfSPaul Beesley
22340d553cfSPaul BeesleyThe power domain tree is implemented as a combination of the following data
22440d553cfSPaul Beesleystructures.
22540d553cfSPaul Beesley
22640d553cfSPaul Beesley::
22740d553cfSPaul Beesley
22840d553cfSPaul Beesley    non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
22940d553cfSPaul Beesley    cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
23040d553cfSPaul Beesley
23140d553cfSPaul BeesleyPopulating the power domain tree
23240d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23340d553cfSPaul Beesley
23440d553cfSPaul BeesleyThe ``populate_power_domain_tree()`` function in ``psci_setup.c`` implements the
23540d553cfSPaul Beesleyalgorithm to parse the power domain descriptor exported by the platform to
23640d553cfSPaul Beesleypopulate the two arrays. It is essentially a breadth-first-search. The nodes for
23740d553cfSPaul Beesleyeach level starting from the root are laid out one after another in the
23840d553cfSPaul Beesley``psci_non_cpu_pd_nodes`` and ``psci_cpu_pd_nodes`` arrays as follows:
23940d553cfSPaul Beesley
24040d553cfSPaul Beesley::
24140d553cfSPaul Beesley
24240d553cfSPaul Beesley    psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]]
24340d553cfSPaul Beesley    psci_cpu_pd_nodes -> [Level 0 nodes]
24440d553cfSPaul Beesley
24540d553cfSPaul BeesleyFor the example power domain tree illustrated above, the ``psci_cpu_pd_nodes``
24640d553cfSPaul Beesleywill be populated as follows. The value in each entry is the index of the parent
24740d553cfSPaul Beesleynode. Other fields have been ignored for simplicity.
24840d553cfSPaul Beesley
24940d553cfSPaul Beesley::
25040d553cfSPaul Beesley
25140d553cfSPaul Beesley                          +-------------+     ^
25240d553cfSPaul Beesley                    CPU0  |      3      |     |
25340d553cfSPaul Beesley                          +-------------+     |
25440d553cfSPaul Beesley                    CPU1  |      3      |     |
25540d553cfSPaul Beesley                          +-------------+     |
25640d553cfSPaul Beesley                    CPU2  |      3      |     |
25740d553cfSPaul Beesley                          +-------------+     |
25840d553cfSPaul Beesley                    CPU3  |      4      |     |
25940d553cfSPaul Beesley                          +-------------+     |
26040d553cfSPaul Beesley                    CPU4  |      4      |     |
26140d553cfSPaul Beesley                          +-------------+     |
26240d553cfSPaul Beesley                    CPU5  |      4      |     | PLATFORM_CORE_COUNT
26340d553cfSPaul Beesley                          +-------------+     |
26440d553cfSPaul Beesley                    CPU6  |      5      |     |
26540d553cfSPaul Beesley                          +-------------+     |
26640d553cfSPaul Beesley                    CPU7  |      5      |     |
26740d553cfSPaul Beesley                          +-------------+     |
26840d553cfSPaul Beesley                    CPU8  |      5      |     |
26940d553cfSPaul Beesley                          +-------------+     |
27040d553cfSPaul Beesley                    CPU9  |      6      |     |
27140d553cfSPaul Beesley                          +-------------+     |
27240d553cfSPaul Beesley                    CPU10 |      6      |     |
27340d553cfSPaul Beesley                          +-------------+     |
27440d553cfSPaul Beesley                    CPU11 |      6      |     |
27540d553cfSPaul Beesley                          +-------------+     |
27640d553cfSPaul Beesley                    CPU12 |      6      |     v
27740d553cfSPaul Beesley                          +-------------+
27840d553cfSPaul Beesley
27940d553cfSPaul BeesleyThe ``psci_non_cpu_pd_nodes`` array will be populated as follows. The value in
28040d553cfSPaul Beesleyeach entry is the index of the parent node.
28140d553cfSPaul Beesley
28240d553cfSPaul Beesley::
28340d553cfSPaul Beesley
28440d553cfSPaul Beesley                          +-------------+     ^
28540d553cfSPaul Beesley                    PD0   |      -1     |     |
28640d553cfSPaul Beesley                          +-------------+     |
28740d553cfSPaul Beesley                    PD1   |      0      |     |
28840d553cfSPaul Beesley                          +-------------+     |
28940d553cfSPaul Beesley                    PD2   |      0      |     |
29040d553cfSPaul Beesley                          +-------------+     |
29140d553cfSPaul Beesley                    PD3   |      1      |     | PLAT_NUM_POWER_DOMAINS -
29240d553cfSPaul Beesley                          +-------------+     | PLATFORM_CORE_COUNT
29340d553cfSPaul Beesley                    PD4   |      1      |     |
29440d553cfSPaul Beesley                          +-------------+     |
29540d553cfSPaul Beesley                    PD5   |      2      |     |
29640d553cfSPaul Beesley                          +-------------+     |
29740d553cfSPaul Beesley                    PD6   |      2      |     |
29840d553cfSPaul Beesley                          +-------------+     v
29940d553cfSPaul Beesley
30040d553cfSPaul BeesleyEach core can find its node in the ``psci_cpu_pd_nodes`` array using the
30140d553cfSPaul Beesley``plat_my_core_pos()`` function. When a core is turned on, the normal world
30240d553cfSPaul Beesleyprovides an MPIDR. The ``plat_core_pos_by_mpidr()`` function is used to validate
30340d553cfSPaul Beesleythe MPIDR before using it to find the corresponding core node. The non-core power
30440d553cfSPaul Beesleydomain nodes do not need to be identified.
30540d553cfSPaul Beesley
30640d553cfSPaul Beesley--------------
30740d553cfSPaul Beesley
30840d553cfSPaul Beesley*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.*
309