xref: /aosp_15_r20/external/arm-trusted-firmware/docs/design/psci-pd-tree.rst (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong ParkPSCI Power Domain Tree Structure
2*54fd6939SJiyong Park================================
3*54fd6939SJiyong Park
4*54fd6939SJiyong ParkRequirements
5*54fd6939SJiyong Park------------
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park#. A platform must export the ``plat_get_aff_count()`` and
8*54fd6939SJiyong Park   ``plat_get_aff_state()`` APIs to enable the generic PSCI code to
9*54fd6939SJiyong Park   populate a tree that describes the hierarchy of power domains in the
10*54fd6939SJiyong Park   system. This approach is inflexible because a change to the topology
11*54fd6939SJiyong Park   requires a change in the code.
12*54fd6939SJiyong Park
13*54fd6939SJiyong Park   It would be much simpler for the platform to describe its power domain tree
14*54fd6939SJiyong Park   in a data structure.
15*54fd6939SJiyong Park
16*54fd6939SJiyong Park#. The generic PSCI code generates MPIDRs in order to populate the power domain
17*54fd6939SJiyong Park   tree. It also uses an MPIDR to find a node in the tree. The assumption that
18*54fd6939SJiyong Park   a platform will use exactly the same MPIDRs as generated by the generic PSCI
19*54fd6939SJiyong Park   code is not scalable. The use of an MPIDR also restricts the number of
20*54fd6939SJiyong Park   levels in the power domain tree to four.
21*54fd6939SJiyong Park
22*54fd6939SJiyong Park   Therefore, there is a need to decouple allocation of MPIDRs from the
23*54fd6939SJiyong Park   mechanism used to populate the power domain topology tree.
24*54fd6939SJiyong Park
25*54fd6939SJiyong Park#. The current arrangement of the power domain tree requires a binary search
26*54fd6939SJiyong Park   over the sibling nodes at a particular level to find a specified power
27*54fd6939SJiyong Park   domain node. During a power management operation, the tree is traversed from
28*54fd6939SJiyong Park   a 'start' to an 'end' power level. The binary search is required to find the
29*54fd6939SJiyong Park   node at each level. The natural way to perform this traversal is to
30*54fd6939SJiyong Park   start from a leaf node and follow the parent node pointer to reach the end
31*54fd6939SJiyong Park   level.
32*54fd6939SJiyong Park
33*54fd6939SJiyong Park   Therefore, there is a need to define data structures that implement the tree in
34*54fd6939SJiyong Park   a way which facilitates such a traversal.
35*54fd6939SJiyong Park
36*54fd6939SJiyong Park#. The attributes of a core power domain differ from the attributes of power
37*54fd6939SJiyong Park   domains at higher levels. For example, only a core power domain can be identified
38*54fd6939SJiyong Park   using an MPIDR. There is no requirement to perform state coordination while
39*54fd6939SJiyong Park   performing a power management operation on the core power domain.
40*54fd6939SJiyong Park
41*54fd6939SJiyong Park   Therefore, there is a need to implement the tree in a way which facilitates this
42*54fd6939SJiyong Park   distinction between a leaf and non-leaf node and any associated
43*54fd6939SJiyong Park   optimizations.
44*54fd6939SJiyong Park
45*54fd6939SJiyong Park--------------
46*54fd6939SJiyong Park
47*54fd6939SJiyong ParkDesign
48*54fd6939SJiyong Park------
49*54fd6939SJiyong Park
50*54fd6939SJiyong ParkDescribing a power domain tree
51*54fd6939SJiyong Park~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52*54fd6939SJiyong Park
53*54fd6939SJiyong ParkTo fulfill requirement 1., the existing platform APIs
54*54fd6939SJiyong Park``plat_get_aff_count()`` and ``plat_get_aff_state()`` have been
55*54fd6939SJiyong Parkremoved. A platform must define an array of unsigned chars such that:
56*54fd6939SJiyong Park
57*54fd6939SJiyong Park#. The first entry in the array specifies the number of power domains at the
58*54fd6939SJiyong Park   highest power level implemented in the platform. This caters for platforms
59*54fd6939SJiyong Park   where the power domain tree does not have a single root node, for example,
60*54fd6939SJiyong Park   the FVP has two cluster power domains at the highest level (1).
61*54fd6939SJiyong Park
62*54fd6939SJiyong Park#. Each subsequent entry corresponds to a power domain and contains the number
63*54fd6939SJiyong Park   of power domains that are its direct children.
64*54fd6939SJiyong Park
65*54fd6939SJiyong Park#. The size of the array minus the first entry will be equal to the number of
66*54fd6939SJiyong Park   non-leaf power domains.
67*54fd6939SJiyong Park
68*54fd6939SJiyong Park#. The value in each entry in the array is used to find the number of entries
69*54fd6939SJiyong Park   to consider at the next level. The sum of the values (number of children) of
70*54fd6939SJiyong Park   all the entries at a level specifies the number of entries in the array for
71*54fd6939SJiyong Park   the next level.
72*54fd6939SJiyong Park
73*54fd6939SJiyong ParkThe following example power domain topology tree will be used to describe the
74*54fd6939SJiyong Parkabove text further. The leaf and non-leaf nodes in this tree have been numbered
75*54fd6939SJiyong Parkseparately.
76*54fd6939SJiyong Park
77*54fd6939SJiyong Park::
78*54fd6939SJiyong Park
79*54fd6939SJiyong Park                                         +-+
80*54fd6939SJiyong Park                                         |0|
81*54fd6939SJiyong Park                                         +-+
82*54fd6939SJiyong Park                                        /   \
83*54fd6939SJiyong Park                                       /     \
84*54fd6939SJiyong Park                                      /       \
85*54fd6939SJiyong Park                                     /         \
86*54fd6939SJiyong Park                                    /           \
87*54fd6939SJiyong Park                                   /             \
88*54fd6939SJiyong Park                                  /               \
89*54fd6939SJiyong Park                                 /                 \
90*54fd6939SJiyong Park                                /                   \
91*54fd6939SJiyong Park                               /                     \
92*54fd6939SJiyong Park                            +-+                       +-+
93*54fd6939SJiyong Park                            |1|                       |2|
94*54fd6939SJiyong Park                            +-+                       +-+
95*54fd6939SJiyong Park                           /   \                     /   \
96*54fd6939SJiyong Park                          /     \                   /     \
97*54fd6939SJiyong Park                         /       \                 /       \
98*54fd6939SJiyong Park                        /         \               /         \
99*54fd6939SJiyong Park                     +-+           +-+         +-+           +-+
100*54fd6939SJiyong Park                     |3|           |4|         |5|           |6|
101*54fd6939SJiyong Park                     +-+           +-+         +-+           +-+
102*54fd6939SJiyong Park            +---+-----+    +----+----|     +----+----+     +----+-----+-----+
103*54fd6939SJiyong Park            |   |     |    |    |    |     |    |    |     |    |     |     |
104*54fd6939SJiyong Park            |   |     |    |    |    |     |    |    |     |    |     |     |
105*54fd6939SJiyong Park            v   v     v    v    v    v     v    v    v     v    v     v     v
106*54fd6939SJiyong Park          +-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+
107*54fd6939SJiyong Park          |0|  |1|   |2|  |3|  |4|  |5|   |6|  |7|  |8|   |9|  |10|  |11|  |12|
108*54fd6939SJiyong Park          +-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+
109*54fd6939SJiyong Park
110*54fd6939SJiyong ParkThis tree is defined by the platform as the array described above as follows:
111*54fd6939SJiyong Park
112*54fd6939SJiyong Park.. code:: c
113*54fd6939SJiyong Park
114*54fd6939SJiyong Park        #define PLAT_NUM_POWER_DOMAINS       20
115*54fd6939SJiyong Park        #define PLATFORM_CORE_COUNT          13
116*54fd6939SJiyong Park        #define PSCI_NUM_NON_CPU_PWR_DOMAINS \
117*54fd6939SJiyong Park                           (PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT)
118*54fd6939SJiyong Park
119*54fd6939SJiyong Park        unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4};
120*54fd6939SJiyong Park
121*54fd6939SJiyong ParkRemoving assumptions about MPIDRs used in a platform
122*54fd6939SJiyong Park~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123*54fd6939SJiyong Park
124*54fd6939SJiyong ParkTo fulfill requirement 2., it is assumed that the platform assigns a
125*54fd6939SJiyong Parkunique number (core index) between ``0`` and ``PLAT_CORE_COUNT - 1`` to each core
126*54fd6939SJiyong Parkpower domain. MPIDRs could be allocated in any manner and will not be used to
127*54fd6939SJiyong Parkpopulate the tree.
128*54fd6939SJiyong Park
129*54fd6939SJiyong Park``plat_core_pos_by_mpidr(mpidr)`` will return the core index for the core
130*54fd6939SJiyong Parkcorresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed
131*54fd6939SJiyong Parkwhich is not allocated or corresponds to an absent core. The semantics of this
132*54fd6939SJiyong Parkplatform API have changed since it is required to validate the passed MPIDR. It
133*54fd6939SJiyong Parkhas been made a mandatory API as a result.
134*54fd6939SJiyong Park
135*54fd6939SJiyong ParkAnother mandatory API, ``plat_my_core_pos()`` has been added to return the core
136*54fd6939SJiyong Parkindex for the calling core. This API provides a more lightweight mechanism to get
137*54fd6939SJiyong Parkthe index since there is no need to validate the MPIDR of the calling core.
138*54fd6939SJiyong Park
139*54fd6939SJiyong ParkThe platform should assign the core indices (as illustrated in the diagram above)
140*54fd6939SJiyong Parksuch that, if the core nodes are numbered from left to right, then the index
141*54fd6939SJiyong Parkfor a core domain will be the same as the index returned by
142*54fd6939SJiyong Park``plat_core_pos_by_mpidr()`` or ``plat_my_core_pos()`` for that core. This
143*54fd6939SJiyong Parkrelationship allows the core nodes to be allocated in a separate array
144*54fd6939SJiyong Park(requirement 4.) during ``psci_setup()`` in such an order that the index of the
145*54fd6939SJiyong Parkcore in the array is the same as the return value from these APIs.
146*54fd6939SJiyong Park
147*54fd6939SJiyong ParkDealing with holes in MPIDR allocation
148*54fd6939SJiyong Park^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
149*54fd6939SJiyong Park
150*54fd6939SJiyong ParkFor platforms where the number of allocated MPIDRs is equal to the number of
151*54fd6939SJiyong Parkcore power domains, for example, Juno and FVPs, the logic to convert an MPIDR to
152*54fd6939SJiyong Parka core index should remain unchanged. Both Juno and FVP use a simple collision
153*54fd6939SJiyong Parkproof hash function to do this.
154*54fd6939SJiyong Park
155*54fd6939SJiyong ParkIt is possible that on some platforms, the allocation of MPIDRs is not
156*54fd6939SJiyong Parkcontiguous or certain cores have been disabled. This essentially means that the
157*54fd6939SJiyong ParkMPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs
158*54fd6939SJiyong Parkused by the platform is not equal to the number of core power domains.
159*54fd6939SJiyong Park
160*54fd6939SJiyong ParkThe platform could adopt one of the following approaches to deal with this
161*54fd6939SJiyong Parkscenario:
162*54fd6939SJiyong Park
163*54fd6939SJiyong Park#. Implement more complex logic to convert a valid MPIDR to a core index while
164*54fd6939SJiyong Park   maintaining the relationship described earlier. This means that the power
165*54fd6939SJiyong Park   domain tree descriptor will not describe any core power domains which are
166*54fd6939SJiyong Park   disabled or absent. Entries will not be allocated in the tree for these
167*54fd6939SJiyong Park   domains.
168*54fd6939SJiyong Park
169*54fd6939SJiyong Park#. Treat unallocated MPIDRs and disabled cores as absent but still describe them
170*54fd6939SJiyong Park   in the power domain descriptor, that is, the number of core nodes described
171*54fd6939SJiyong Park   is equal to the size of the range of MPIDRs allocated. This approach will
172*54fd6939SJiyong Park   lead to memory wastage since entries will be allocated in the tree but will
173*54fd6939SJiyong Park   allow use of a simpler logic to convert an MPIDR to a core index.
174*54fd6939SJiyong Park
175*54fd6939SJiyong ParkTraversing through and distinguishing between core and non-core power domains
176*54fd6939SJiyong Park~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
177*54fd6939SJiyong Park
178*54fd6939SJiyong ParkTo fulfill requirement 3 and 4, separate data structures have been defined
179*54fd6939SJiyong Parkto represent leaf and non-leaf power domain nodes in the tree.
180*54fd6939SJiyong Park
181*54fd6939SJiyong Park.. code:: c
182*54fd6939SJiyong Park
183*54fd6939SJiyong Park    /*******************************************************************************
184*54fd6939SJiyong Park     * The following two data structures implement the power domain tree. The tree
185*54fd6939SJiyong Park     * is used to track the state of all the nodes i.e. power domain instances
186*54fd6939SJiyong Park     * described by the platform. The tree consists of nodes that describe CPU power
187*54fd6939SJiyong Park     * domains i.e. leaf nodes and all other power domains which are parents of a
188*54fd6939SJiyong Park     * CPU power domain i.e. non-leaf nodes.
189*54fd6939SJiyong Park     ******************************************************************************/
190*54fd6939SJiyong Park    typedef struct non_cpu_pwr_domain_node {
191*54fd6939SJiyong Park        /*
192*54fd6939SJiyong Park         * Index of the first CPU power domain node level 0 which has this node
193*54fd6939SJiyong Park         * as its parent.
194*54fd6939SJiyong Park         */
195*54fd6939SJiyong Park        unsigned int cpu_start_idx;
196*54fd6939SJiyong Park
197*54fd6939SJiyong Park        /*
198*54fd6939SJiyong Park         * Number of CPU power domains which are siblings of the domain indexed
199*54fd6939SJiyong Park         * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
200*54fd6939SJiyong Park         * -> cpu_start_idx + ncpus' have this node as their parent.
201*54fd6939SJiyong Park         */
202*54fd6939SJiyong Park        unsigned int ncpus;
203*54fd6939SJiyong Park
204*54fd6939SJiyong Park        /* Index of the parent power domain node */
205*54fd6939SJiyong Park        unsigned int parent_node;
206*54fd6939SJiyong Park
207*54fd6939SJiyong Park        -----
208*54fd6939SJiyong Park    } non_cpu_pd_node_t;
209*54fd6939SJiyong Park
210*54fd6939SJiyong Park    typedef struct cpu_pwr_domain_node {
211*54fd6939SJiyong Park        u_register_t mpidr;
212*54fd6939SJiyong Park
213*54fd6939SJiyong Park        /* Index of the parent power domain node */
214*54fd6939SJiyong Park        unsigned int parent_node;
215*54fd6939SJiyong Park
216*54fd6939SJiyong Park        -----
217*54fd6939SJiyong Park    } cpu_pd_node_t;
218*54fd6939SJiyong Park
219*54fd6939SJiyong ParkThe power domain tree is implemented as a combination of the following data
220*54fd6939SJiyong Parkstructures.
221*54fd6939SJiyong Park
222*54fd6939SJiyong Park.. code:: c
223*54fd6939SJiyong Park
224*54fd6939SJiyong Park    non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
225*54fd6939SJiyong Park    cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
226*54fd6939SJiyong Park
227*54fd6939SJiyong ParkPopulating the power domain tree
228*54fd6939SJiyong Park~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
229*54fd6939SJiyong Park
230*54fd6939SJiyong ParkThe ``populate_power_domain_tree()`` function in ``psci_setup.c`` implements the
231*54fd6939SJiyong Parkalgorithm to parse the power domain descriptor exported by the platform to
232*54fd6939SJiyong Parkpopulate the two arrays. It is essentially a breadth-first-search. The nodes for
233*54fd6939SJiyong Parkeach level starting from the root are laid out one after another in the
234*54fd6939SJiyong Park``psci_non_cpu_pd_nodes`` and ``psci_cpu_pd_nodes`` arrays as follows:
235*54fd6939SJiyong Park
236*54fd6939SJiyong Park::
237*54fd6939SJiyong Park
238*54fd6939SJiyong Park    psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]]
239*54fd6939SJiyong Park    psci_cpu_pd_nodes -> [Level 0 nodes]
240*54fd6939SJiyong Park
241*54fd6939SJiyong ParkFor the example power domain tree illustrated above, the ``psci_cpu_pd_nodes``
242*54fd6939SJiyong Parkwill be populated as follows. The value in each entry is the index of the parent
243*54fd6939SJiyong Parknode. Other fields have been ignored for simplicity.
244*54fd6939SJiyong Park
245*54fd6939SJiyong Park::
246*54fd6939SJiyong Park
247*54fd6939SJiyong Park                          +-------------+     ^
248*54fd6939SJiyong Park                    CPU0  |      3      |     |
249*54fd6939SJiyong Park                          +-------------+     |
250*54fd6939SJiyong Park                    CPU1  |      3      |     |
251*54fd6939SJiyong Park                          +-------------+     |
252*54fd6939SJiyong Park                    CPU2  |      3      |     |
253*54fd6939SJiyong Park                          +-------------+     |
254*54fd6939SJiyong Park                    CPU3  |      4      |     |
255*54fd6939SJiyong Park                          +-------------+     |
256*54fd6939SJiyong Park                    CPU4  |      4      |     |
257*54fd6939SJiyong Park                          +-------------+     |
258*54fd6939SJiyong Park                    CPU5  |      4      |     | PLATFORM_CORE_COUNT
259*54fd6939SJiyong Park                          +-------------+     |
260*54fd6939SJiyong Park                    CPU6  |      5      |     |
261*54fd6939SJiyong Park                          +-------------+     |
262*54fd6939SJiyong Park                    CPU7  |      5      |     |
263*54fd6939SJiyong Park                          +-------------+     |
264*54fd6939SJiyong Park                    CPU8  |      5      |     |
265*54fd6939SJiyong Park                          +-------------+     |
266*54fd6939SJiyong Park                    CPU9  |      6      |     |
267*54fd6939SJiyong Park                          +-------------+     |
268*54fd6939SJiyong Park                    CPU10 |      6      |     |
269*54fd6939SJiyong Park                          +-------------+     |
270*54fd6939SJiyong Park                    CPU11 |      6      |     |
271*54fd6939SJiyong Park                          +-------------+     |
272*54fd6939SJiyong Park                    CPU12 |      6      |     v
273*54fd6939SJiyong Park                          +-------------+
274*54fd6939SJiyong Park
275*54fd6939SJiyong ParkThe ``psci_non_cpu_pd_nodes`` array will be populated as follows. The value in
276*54fd6939SJiyong Parkeach entry is the index of the parent node.
277*54fd6939SJiyong Park
278*54fd6939SJiyong Park::
279*54fd6939SJiyong Park
280*54fd6939SJiyong Park                          +-------------+     ^
281*54fd6939SJiyong Park                    PD0   |      -1     |     |
282*54fd6939SJiyong Park                          +-------------+     |
283*54fd6939SJiyong Park                    PD1   |      0      |     |
284*54fd6939SJiyong Park                          +-------------+     |
285*54fd6939SJiyong Park                    PD2   |      0      |     |
286*54fd6939SJiyong Park                          +-------------+     |
287*54fd6939SJiyong Park                    PD3   |      1      |     | PLAT_NUM_POWER_DOMAINS -
288*54fd6939SJiyong Park                          +-------------+     | PLATFORM_CORE_COUNT
289*54fd6939SJiyong Park                    PD4   |      1      |     |
290*54fd6939SJiyong Park                          +-------------+     |
291*54fd6939SJiyong Park                    PD5   |      2      |     |
292*54fd6939SJiyong Park                          +-------------+     |
293*54fd6939SJiyong Park                    PD6   |      2      |     |
294*54fd6939SJiyong Park                          +-------------+     v
295*54fd6939SJiyong Park
296*54fd6939SJiyong ParkEach core can find its node in the ``psci_cpu_pd_nodes`` array using the
297*54fd6939SJiyong Park``plat_my_core_pos()`` function. When a core is turned on, the normal world
298*54fd6939SJiyong Parkprovides an MPIDR. The ``plat_core_pos_by_mpidr()`` function is used to validate
299*54fd6939SJiyong Parkthe MPIDR before using it to find the corresponding core node. The non-core power
300*54fd6939SJiyong Parkdomain nodes do not need to be identified.
301*54fd6939SJiyong Park
302*54fd6939SJiyong Park--------------
303*54fd6939SJiyong Park
304*54fd6939SJiyong Park*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.*
305