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