xref: /rk3399_ARM-atf/tools/sptool/spactions.py (revision 78c82cd09913554c25557970802c8514f513ca81)
1*b1e6a415SJ-Alves#!/usr/bin/python3
2*b1e6a415SJ-Alves# Copyright (c) 2022, Arm Limited. All rights reserved.
3*b1e6a415SJ-Alves#
4*b1e6a415SJ-Alves# SPDX-License-Identifier: BSD-3-Clause
5*b1e6a415SJ-Alves'''
6*b1e6a415SJ-AlvesThis is a python module for defining and executing SP setup actions, targeting
7*b1e6a415SJ-Alvesa system deploying an SPM implementation.
8*b1e6a415SJ-AlvesEach action consists of a function, that processes the SP layout json file and
9*b1e6a415SJ-Alvesother provided arguments.
10*b1e6a415SJ-AlvesAt the core of this is the SpSetupActions which provides a means to register
11*b1e6a415SJ-Alvesthe functions into a table of actions, and execute them all when invoking
12*b1e6a415SJ-AlvesSpSetupActions.run_actions.
13*b1e6a415SJ-AlvesRegistering the function is done by using the decorator '@SpSetupActions.sp_action'
14*b1e6a415SJ-Alvesat function definition.
15*b1e6a415SJ-Alves
16*b1e6a415SJ-AlvesFunctions can be called:
17*b1e6a415SJ-Alves- once only, or per SP defined in the SP layout file;
18*b1e6a415SJ-Alves- following an order, from lowest to highest of their execution order.
19*b1e6a415SJ-AlvesMore information in the doc comments below.
20*b1e6a415SJ-Alves'''
21*b1e6a415SJ-Alvesimport bisect
22*b1e6a415SJ-Alves
23*b1e6a415SJ-AlvesDEFAULT_ACTION_ORDER = 100
24*b1e6a415SJ-Alves
25*b1e6a415SJ-Alvesclass _ConfiguredAction:
26*b1e6a415SJ-Alves    """
27*b1e6a415SJ-Alves    Wraps action function with its configuration.
28*b1e6a415SJ-Alves    """
29*b1e6a415SJ-Alves    def __init__(self, action, exec_order=DEFAULT_ACTION_ORDER, global_action=True, log_calls = False):
30*b1e6a415SJ-Alves        self.exec_order = exec_order
31*b1e6a415SJ-Alves        self.__name__ = action.__name__
32*b1e6a415SJ-Alves        def logged_action(action):
33*b1e6a415SJ-Alves            def inner_logged_action(sp_layout, sp, args :dict):
34*b1e6a415SJ-Alves                print(f"Calling {action.__name__} -> {sp}")
35*b1e6a415SJ-Alves                return action(sp_layout, sp, args)
36*b1e6a415SJ-Alves            return inner_logged_action
37*b1e6a415SJ-Alves        self.action = logged_action(action) if log_calls is True else action
38*b1e6a415SJ-Alves        self.global_action = global_action
39*b1e6a415SJ-Alves
40*b1e6a415SJ-Alves    def __lt__(self, other):
41*b1e6a415SJ-Alves        """
42*b1e6a415SJ-Alves        To allow for ordered inserts in a list of actions.
43*b1e6a415SJ-Alves        """
44*b1e6a415SJ-Alves        return self.exec_order < other.exec_order
45*b1e6a415SJ-Alves
46*b1e6a415SJ-Alves    def __call__(self, sp_layout, sp, args :dict):
47*b1e6a415SJ-Alves        """
48*b1e6a415SJ-Alves        Calls action function.
49*b1e6a415SJ-Alves        """
50*b1e6a415SJ-Alves        return self.action(sp_layout, sp, args)
51*b1e6a415SJ-Alves
52*b1e6a415SJ-Alves    def __repr__(self) -> str:
53*b1e6a415SJ-Alves        """
54*b1e6a415SJ-Alves        Pretty format to show debug information about the action.
55*b1e6a415SJ-Alves        """
56*b1e6a415SJ-Alves        return f"func: {self.__name__}; global:{self.global_action}; exec_order: {self.exec_order}"
57*b1e6a415SJ-Alves
58*b1e6a415SJ-Alvesclass SpSetupActions:
59*b1e6a415SJ-Alves    actions = []
60*b1e6a415SJ-Alves
61*b1e6a415SJ-Alves    def sp_action(in_action = None, global_action = False, log_calls=False, exec_order=DEFAULT_ACTION_ORDER):
62*b1e6a415SJ-Alves        """
63*b1e6a415SJ-Alves        Function decorator that registers and configures action.
64*b1e6a415SJ-Alves
65*b1e6a415SJ-Alves        :param in_action - function to register
66*b1e6a415SJ-Alves        :param global_action - make the function global, i.e. make it be
67*b1e6a415SJ-Alves        only called once.
68*b1e6a415SJ-Alves        :param log_calls - at every call to action, a useful log will be printed.
69*b1e6a415SJ-Alves        :param exec_order - action's calling order.
70*b1e6a415SJ-Alves        """
71*b1e6a415SJ-Alves        def append_action(action):
72*b1e6a415SJ-Alves            action = _ConfiguredAction(action, exec_order, global_action, log_calls)
73*b1e6a415SJ-Alves            bisect.insort(SpSetupActions.actions, action)
74*b1e6a415SJ-Alves            return action
75*b1e6a415SJ-Alves        if in_action is not None:
76*b1e6a415SJ-Alves            return append_action(in_action)
77*b1e6a415SJ-Alves        return append_action
78*b1e6a415SJ-Alves
79*b1e6a415SJ-Alves    def run_actions(sp_layout: dict, args: dict, verbose=False):
80*b1e6a415SJ-Alves        """
81*b1e6a415SJ-Alves        Executes all actions in accordance to their registering configuration:
82*b1e6a415SJ-Alves        - If set as "global" it will be called once.
83*b1e6a415SJ-Alves        - Actions are called respecting the order established by their "exec_order" field.
84*b1e6a415SJ-Alves
85*b1e6a415SJ-Alves        :param sp_layout - dictionary containing the SP layout information.
86*b1e6a415SJ-Alves        :param args - arguments to be propagated through the call of actions.
87*b1e6a415SJ-Alves        :param verbose - prints actions information in order of execution.
88*b1e6a415SJ-Alves        """
89*b1e6a415SJ-Alves        args["called"] = [] # for debug purposes
90*b1e6a415SJ-Alves        def append_called(action, sp, args :dict):
91*b1e6a415SJ-Alves            args["called"].append(f"{action.__name__} -> {sp}")
92*b1e6a415SJ-Alves            return args
93*b1e6a415SJ-Alves
94*b1e6a415SJ-Alves        for action in SpSetupActions.actions:
95*b1e6a415SJ-Alves            if verbose:
96*b1e6a415SJ-Alves                print(f"Calling {action}")
97*b1e6a415SJ-Alves            if action.global_action:
98*b1e6a415SJ-Alves                scope = "global"
99*b1e6a415SJ-Alves                args = action(sp_layout, scope, args)
100*b1e6a415SJ-Alves                args = append_called(action, scope, args)
101*b1e6a415SJ-Alves            else:
102*b1e6a415SJ-Alves                # Functions that are not global called for each SP defined in
103*b1e6a415SJ-Alves                # the SP layout.
104*b1e6a415SJ-Alves                for sp in sp_layout.keys():
105*b1e6a415SJ-Alves                    args = action(sp_layout, sp, args)
106*b1e6a415SJ-Alves                    args = append_called(action, sp, args)
107*b1e6a415SJ-Alves
108*b1e6a415SJ-Alvesif __name__ == "__main__":
109*b1e6a415SJ-Alves    # Executing this module will have the following test code/playground executed
110*b1e6a415SJ-Alves    sp_layout = {
111*b1e6a415SJ-Alves        "partition1" : {
112*b1e6a415SJ-Alves            "boot-info": True,
113*b1e6a415SJ-Alves            "image": {
114*b1e6a415SJ-Alves                "file": "partition.bin",
115*b1e6a415SJ-Alves                "offset":"0x2000"
116*b1e6a415SJ-Alves            },
117*b1e6a415SJ-Alves            "pm": {
118*b1e6a415SJ-Alves                "file": "cactus.dts",
119*b1e6a415SJ-Alves                "offset":"0x1000"
120*b1e6a415SJ-Alves            },
121*b1e6a415SJ-Alves            "owner": "SiP"
122*b1e6a415SJ-Alves        },
123*b1e6a415SJ-Alves        "partition2" : {
124*b1e6a415SJ-Alves            "image": "partition.bin",
125*b1e6a415SJ-Alves            "pm": "cactus-secondary.dts",
126*b1e6a415SJ-Alves            "owner": "Plat"
127*b1e6a415SJ-Alves        },
128*b1e6a415SJ-Alves        "partition3" : {
129*b1e6a415SJ-Alves            "image": "partition.bin",
130*b1e6a415SJ-Alves            "pm": "cactus-tertiary.dts",
131*b1e6a415SJ-Alves            "owner": "Plat"
132*b1e6a415SJ-Alves        },
133*b1e6a415SJ-Alves        "partition4" : {
134*b1e6a415SJ-Alves            "image": "ivy.bin",
135*b1e6a415SJ-Alves            "pm": "ivy.dts",
136*b1e6a415SJ-Alves            "owner": "Plat"
137*b1e6a415SJ-Alves        }
138*b1e6a415SJ-Alves    }
139*b1e6a415SJ-Alves
140*b1e6a415SJ-Alves    #Example of how to use this module
141*b1e6a415SJ-Alves    @SpSetupActions.sp_action(global_action=True)
142*b1e6a415SJ-Alves    def my_action1(sp_layout, _, args :dict):
143*b1e6a415SJ-Alves        print(f"inside function my_action1{sp_layout}\n\n args:{args})")
144*b1e6a415SJ-Alves        return args # Always return args in action function.
145*b1e6a415SJ-Alves    @SpSetupActions.sp_action(exec_order=1)
146*b1e6a415SJ-Alves    def my_action2(sp_layout, sp_name, args :dict):
147*b1e6a415SJ-Alves        print(f"inside function my_action2; SP: {sp_name} {sp_layout} args:{args}")
148*b1e6a415SJ-Alves        return args
149*b1e6a415SJ-Alves
150*b1e6a415SJ-Alves    # Example arguments to be propagated through the functions.
151*b1e6a415SJ-Alves    # 'args' can be extended in the action functions.
152*b1e6a415SJ-Alves    args = dict()
153*b1e6a415SJ-Alves    args["arg1"] = 0xEEE
154*b1e6a415SJ-Alves    args["arg2"] = 0xFF
155*b1e6a415SJ-Alves    SpSetupActions.run_actions(sp_layout, args)
156