blob: 2b181d380ee652410947eba31e7c7858ce8993a2 [file] [log] [blame]
Madhurima Paruchurifa738b02022-10-26 13:34:09 +00001#!/usr/bin/env python3
2
3# Copyright (c) 2022 The Chromium OS Authors
4# SPDX-License-Identifier: Apache-2.0
5
6"""This file contains a Python script which parses through Zephyr device tree using
7EDT.pickle generated at build and generates a XML file containing USB VIF policies"""
8
9import argparse
Keith Short52e6b4e2023-03-24 15:17:31 -060010import inspect
Madhurima Paruchurifa738b02022-10-26 13:34:09 +000011import os
12import pickle
13import sys
14import xml.etree.ElementTree as ET
15
16import constants
17
18SCRIPTS_DIR = os.path.join(os.path.dirname(__file__), "..")
19sys.path.insert(0, os.path.join(SCRIPTS_DIR, 'dts', 'python-devicetree', 'src'))
20
Madhurima Paruchurifa738b02022-10-26 13:34:09 +000021def main():
Keith Short52e6b4e2023-03-24 15:17:31 -060022 global edtlib
23
Madhurima Paruchurifa738b02022-10-26 13:34:09 +000024 args = parse_args()
Keith Short52e6b4e2023-03-24 15:17:31 -060025 with open(args.edt_pickle, 'rb') as f:
26 edt = pickle.load(f)
27 edtlib = inspect.getmodule(edt)
28
Madhurima Paruchurifa738b02022-10-26 13:34:09 +000029 xml_root = get_root()
30 add_elements_to_xml(xml_root, constants.VIF_SPEC_ELEMENTS)
31 add_element_to_xml(xml_root, constants.MODEL_PART_NUMBER, args.board)
32 for node in edt.compat2nodes[args.compatible]:
33 xml_ele = add_element_to_xml(xml_root, constants.COMPONENT)
34 parse_and_add_node_to_xml(xml_ele, node)
35 tree = ET.ElementTree(xml_root)
36 tree.write(args.vif_out, xml_declaration=True,
37 encoding=constants.XML_ENCODING)
38
39
40def is_vif_element(name):
41 if name in constants.VIF_ELEMENTS:
42 return True
43 return False
44
45
46def get_vif_element_name(name):
47 return constants.XML_ELEMENT_NAME_PREFIX + ":" + constants.DT_VIF_ELEMENTS.get(
48 name, name)
49
50
51def get_root():
52 xml_root = ET.Element(get_vif_element_name(constants.XML_ROOT_ELEMENT_NAME))
53 add_attributes_to_xml_element(xml_root, constants.XML_NAMESPACE_ATTRIBUTES)
54 return xml_root
55
56
57def add_attributes_to_xml_element(xml_ele, attributes):
58 for key, value in attributes.items():
59 xml_ele.set(key, value)
60
61
62def add_element_to_xml(xml_ele, name, text=None, attributes=None):
63 if is_vif_element(name):
64 new_xml_ele = ET.SubElement(xml_ele, get_vif_element_name(name))
65 if text:
66 new_xml_ele.text = str(text)
67 if attributes:
68 add_attributes_to_xml_element(new_xml_ele, attributes)
69 return new_xml_ele
70 return xml_ele
71
72
73def add_elements_to_xml(xml_ele, elements):
74 for element_name in elements:
75 text = elements[element_name].get(constants.TEXT, None)
76 attributes = elements[element_name].get(constants.ATTRIBUTES, None)
77 new_xml_ele = add_element_to_xml(xml_ele, element_name, text, attributes)
78 if constants.CHILD in elements[element_name]:
79 add_elements_to_xml(new_xml_ele, elements[element_name][constants.CHILD])
80
81
82def is_simple_datatype(value):
83 if isinstance(value, (str, int, bool)):
84 return True
85 return False
86
87
88def get_pdo_type(pdo_value):
89 return pdo_value >> 30
90
91
92def get_xml_bool_value(value):
93 if value:
94 return constants.TRUE
95 return constants.FALSE
96
97
98def parse_and_add_sink_pdos_to_xml(xml_ele, sink_pdos):
99 new_xml_ele = add_element_to_xml(xml_ele, constants.SINK_PDOS)
100 pdos_info = dict()
101 snk_max_power = 0
102 for pdo_value in sink_pdos:
103 power_mv = parse_and_add_sink_pdo_to_xml(new_xml_ele, pdo_value, pdos_info)
104 if power_mv > snk_max_power:
105 snk_max_power = power_mv
106 add_element_to_xml(xml_ele, constants.NUM_SINK_PDOS, None,
107 {constants.VALUE: str(len(sink_pdos))})
108 add_element_to_xml(xml_ele, constants.EPR_SUPPORTED_AS_SINK,
109 attributes={constants.VALUE: constants.FALSE})
110 add_element_to_xml(xml_ele, constants.NO_USB_SUSPEND_MAY_BE_SET,
111 attributes={constants.VALUE: constants.TRUE})
112 add_element_to_xml(xml_ele, constants.HIGHER_CAPABILITY_SET, attributes={
113 constants.VALUE: get_xml_bool_value(pdos_info.get(constants.HIGHER_CAPABILITY_SET, 0))})
114 add_element_to_xml(xml_ele, constants.FR_SWAP_REQD_TYPE_C_CURRENT_AS_INITIAL_SOURCE,
115 "FR_Swap not supported", attributes={constants.VALUE: str(
116 pdos_info.get(constants.FR_SWAP_REQD_TYPE_C_CURRENT_AS_INITIAL_SOURCE, 0))})
117 add_element_to_xml(xml_ele, constants.PD_POWER_AS_SINK, f'{snk_max_power} mW',
118 {constants.VALUE: str(snk_max_power)})
119
120
121def parse_and_add_sink_pdo_to_xml(xml_ele, pdo_value, pdos_info):
122 power_mw = 0
123 xml_ele = add_element_to_xml(xml_ele, constants.SINK_PDO)
124 pdo_type = get_pdo_type(pdo_value)
125 if pdo_type == constants.PDO_TYPE_FIXED:
126 current = pdo_value & 0x3ff
127 current_ma = current * 10
128 voltage = (pdo_value >> 10) & 0x3ff
129 voltage_mv = voltage * 50
130 power_mw = (current_ma * voltage_mv) // 1000
131 pdos_info[constants.HIGHER_CAPABILITY_SET] = pdo_value & (1 << 28)
132 pdos_info[constants.FR_SWAP_REQD_TYPE_C_CURRENT_AS_INITIAL_SOURCE] = pdo_value & (3 << 23)
133 add_element_to_xml(xml_ele, constants.SINK_PDO_VOLTAGE, f'{voltage_mv} mV',
134 {constants.VALUE: str(voltage)})
135 add_element_to_xml(xml_ele, constants.SINK_PDO_OP_CURRENT,
136 f'{current_ma} mA',
137 {constants.VALUE: str(current)})
138 elif pdo_type == constants.PDO_TYPE_BATTERY:
139 max_voltage = (pdo_value >> 20) & 0x3ff
140 max_voltage_mv = max_voltage * 50
141 min_voltage = (pdo_value >> 10) & 0x3ff
142 min_voltage_mv = min_voltage * 50
143 power = pdo_value & 0x3ff
144 power_mw = power * 250
145 add_element_to_xml(xml_ele, constants.SINK_PDO_MIN_VOLTAGE,
146 f'{min_voltage_mv} mV',
147 {constants.VALUE: str(min_voltage)})
148 add_element_to_xml(xml_ele, constants.SINK_PDO_MAX_VOLTAGE,
149 f'{max_voltage_mv} mV',
150 {constants.VALUE: str(max_voltage)})
151 add_element_to_xml(xml_ele, constants.SINK_PDO_OP_POWER, f'{power_mw} mW',
152 {constants.VALUE: str(power)})
153 elif pdo_type == constants.PDO_TYPE_VARIABLE:
154 max_voltage = (pdo_value >> 20) & 0x3ff
155 max_voltage_mv = max_voltage * 50
156 min_voltage = (pdo_value >> 10) & 0x3ff
157 min_voltage_mv = min_voltage * 50
158 current = pdo_value & 0x3ff
159 current_ma = current * 10
160 power_mw = (current_ma * max_voltage_mv) // 1000
161 add_element_to_xml(xml_ele, constants.SINK_PDO_MIN_VOLTAGE,
162 f'{min_voltage_mv} mV',
163 {constants.VALUE: str(min_voltage)})
164 add_element_to_xml(xml_ele, constants.SINK_PDO_MAX_VOLTAGE,
165 f'{max_voltage_mv} mV',
166 {constants.VALUE: str(max_voltage)})
167 add_element_to_xml(xml_ele, constants.SINK_PDO_OP_CURRENT,
168 f'{current_ma} mA',
169 {constants.VALUE: str(current)})
170 elif pdo_type == constants.PDO_TYPE_AUGUMENTED:
171 pps = (pdo_value >> 28) & 0x03
172 if pps:
173 raise ValueError(f'ERROR: Invalid PDO_TYPE {pdo_value}')
174 pps_max_voltage = (pdo_value >> 17) & 0xff
175 pps_max_voltage_mv = pps_max_voltage * 100
176 pps_min_voltage = (pdo_value >> 8) & 0xff
177 pps_min_voltage_mv = pps_min_voltage * 100
178 pps_current = pdo_value & 0x7f
179 pps_current_ma = pps_current * 50
180 power_mw = (pps_current_ma * pps_max_voltage_mv) // 1000
181 add_element_to_xml(xml_ele, constants.SINK_PDO_MIN_VOLTAGE,
182 f'{pps_min_voltage_mv} mV',
183 {constants.VALUE: str(pps_min_voltage)})
184 add_element_to_xml(xml_ele, constants.SINK_PDO_MAX_VOLTAGE,
185 f'{pps_max_voltage_mv} mV',
186 {constants.VALUE: str(pps_max_voltage)})
187 add_element_to_xml(xml_ele, constants.SINK_PDO_OP_CURRENT,
188 f'{pps_current_ma} mA',
189 {constants.VALUE: str(pps_current)})
190 else:
191 raise ValueError(f'ERROR: Invalid PDO_TYPE {pdo_value}')
192 add_element_to_xml(xml_ele, constants.SINK_PDO_SUPPLY_TYPE,
193 constants.PDO_TYPES[pdo_type], {constants.VALUE: str(pdo_type)})
194 return power_mw
195
196
197def parse_and_add_controller_and_data_to_xml(xml_ele, cad):
198 xml_ele = add_element_to_xml(xml_ele, cad.basename)
199 for name in cad.data:
200 add_element_to_xml(xml_ele, name, str(cad.data[name]))
201 parse_and_add_node_to_xml(xml_ele, cad.controller)
202
203
204def parse_and_add_array_to_xml(xml_ele, prop):
205 for member in prop.val:
206 if is_simple_datatype(member):
207 add_element_to_xml(xml_ele, prop.name, str(member))
208 elif isinstance(member, list):
209 new_xml_ele = add_element_to_xml(xml_ele, prop.name)
210 parse_and_add_array_to_xml(new_xml_ele, member)
211 elif isinstance(member, edtlib.Node):
212 new_xml_ele = add_element_to_xml(xml_ele, prop.name)
213 parse_and_add_node_to_xml(new_xml_ele, member)
214 elif isinstance(member, edtlib.ControllerAndData):
215 new_xml_ele = add_element_to_xml(xml_ele, prop.name)
216 parse_and_add_controller_and_data_to_xml(new_xml_ele, member)
217 else:
218 ValueError(
219 f'Noticed undefined type : {str(type(member))}, with value {str(member)}')
220
221
222def parse_and_add_node_to_xml(xml_ele, node):
223 if not isinstance(node, edtlib.Node):
224 return
225 xml_ele = add_element_to_xml(xml_ele, node.name)
226 for prop in node.props:
227 if is_simple_datatype(node.props[prop].val):
228 add_element_to_xml(xml_ele, node.props[prop].name,
229 str(node.props[prop].val))
230 elif node.props[prop].name == constants.SINK_PDOS:
231 parse_and_add_sink_pdos_to_xml(xml_ele, node.props[prop].val)
232 elif isinstance(node.props[prop].val, list):
233 parse_and_add_array_to_xml(xml_ele, node.props[prop])
234 elif isinstance(node.props[prop].val, edtlib.Node):
235 new_xml_ele = add_element_to_xml(xml_ele, node.props[prop].name)
236 parse_and_add_node_to_xml(new_xml_ele, node.props[prop].val)
237 elif isinstance(node.props[prop].val, edtlib.ControllerAndData):
238 new_xml_ele = add_element_to_xml(xml_ele, node.props[prop].name)
239 parse_and_add_controller_and_data_to_xml(new_xml_ele, node.props[prop].val)
240 else:
241 ValueError(
242 f'Noticed undefined type : {str(type(node.props[prop].val))}, '
243 f'with value {str(node.props[prop].val)}')
244 for child in node.children:
245 new_xml_ele = add_element_to_xml(xml_ele, child)
246 parse_and_add_node_to_xml(new_xml_ele, node.children[child])
247
248
249def parse_args():
Jamie McCraeec704442023-01-04 16:08:36 +0000250 parser = argparse.ArgumentParser(allow_abbrev=False)
Madhurima Paruchurifa738b02022-10-26 13:34:09 +0000251 parser.add_argument("--edt-pickle", required=True,
252 help="path to read the pickled edtlib.EDT object from")
253 parser.add_argument("--compatible", required=True,
254 help="device tree compatible to be parsed")
255 parser.add_argument("--vif-out", required=True,
256 help="path to write VIF policies to")
257 parser.add_argument("--board", required=True, help="board name")
258 return parser.parse_args()
259
260
261if __name__ == "__main__":
262 main()