blob: f16c55414fa1616ef684a2ed7b103b5cdf53cd76 [file] [log] [blame]
kelvin.zhangac22e652021-10-18 15:09:21 +08001# Copyright (c) 2018-2019 Linaro
2# Copyright (c) 2019 Nordic Semiconductor ASA
3#
4# SPDX-License-Identifier: Apache-2.0
5
6import os
7import pickle
8import sys
9
10SDK_BASE = os.environ["SDK_BASE"]
11sys.path.insert(0, os.path.join(SDK_BASE, "scripts", "dts",
12 "python-devicetree", "src"))
13
14from devicetree import edtlib
15
16# Types we support
17# 'string', 'int', 'hex', 'bool'
18
19doc_mode = os.environ.get('KCONFIG_DOC_MODE') == "1"
20
21if not doc_mode:
22 EDT_PICKLE = os.environ.get("EDT_PICKLE")
23
24 # The "if" handles a missing dts.
25 if EDT_PICKLE is not None and os.path.isfile(EDT_PICKLE):
26 with open(EDT_PICKLE, 'rb') as f:
27 edt = pickle.load(f)
28 else:
29 edt = None
30
31
32def _warn(kconf, msg):
33 print("{}:{}: WARNING: {}".format(kconf.filename, kconf.linenr, msg))
34
35
36def _dt_units_to_scale(unit):
37 if not unit:
38 return 0
39 if unit in {'k', 'K'}:
40 return 10
41 if unit in {'m', 'M'}:
42 return 20
43 if unit in {'g', 'G'}:
44 return 30
45
46
47def dt_chosen_label(kconf, _, chosen):
48 """
49 This function takes a 'chosen' property and treats that property as a path
50 to an EDT node. If it finds an EDT node, it will look to see if that node
51 has a "label" property and return the value of that "label", if not we
52 return an empty string.
53 """
54 if doc_mode or edt is None:
55 return ""
56
57 node = edt.chosen_node(chosen)
58 if not node:
59 return ""
60
61 if "label" not in node.props:
62 return ""
63
64 return node.props["label"].val
65
66
67def dt_chosen_enabled(kconf, _, chosen):
68 """
69 This function returns "y" if /chosen contains a property named 'chosen'
70 that points to an enabled node, and "n" otherwise
71 """
72 if doc_mode or edt is None:
73 return "n"
74
75 node = edt.chosen_node(chosen)
76 return "y" if node and node.status == "okay" else "n"
77
78
79def dt_chosen_path(kconf, _, chosen):
80 """
81 This function takes a /chosen node property and returns the path
82 to the node in the property value, or the empty string.
83 """
84 if doc_mode or edt is None:
85 return "n"
86
87 node = edt.chosen_node(chosen)
88
89 return node.path if node else ""
90
91
92def dt_node_enabled(kconf, name, node):
93 """
94 This function is used to test if a node is enabled (has status
95 'okay') or not.
96
97 The 'node' argument is a string which is either a path or an
98 alias, or both, depending on 'name'.
99
100 If 'name' is 'dt_path_enabled', 'node' is an alias or a path. If
101 'name' is 'dt_alias_enabled, 'node' is an alias.
102 """
103
104 if doc_mode or edt is None:
105 return "n"
106
107 if name == "dt_alias_enabled":
108 if node.startswith("/"):
109 # EDT.get_node() works with either aliases or paths. If we
110 # are specifically being asked about an alias, reject paths.
111 return "n"
112 else:
113 # Make sure this is being called appropriately.
114 assert name == "dt_path_enabled"
115
116 try:
117 node = edt.get_node(node)
118 except edtlib.EDTError:
119 return "n"
120
121 return "y" if node and node.status == "okay" else "n"
122
123
124def dt_nodelabel_enabled(kconf, _, label):
125 """
126 This function is like dt_node_enabled(), but the 'label' argument
127 should be a node label, like "foo" is here:
128
129 foo: some-node { ... };
130 """
131 if doc_mode or edt is None:
132 return "n"
133
134 node = edt.label2node.get(label)
135
136 return "y" if node and node.status == "okay" else "n"
137
138
139def _node_reg_addr(node, index, unit):
140 if not node:
141 return 0
142
143 if not node.regs:
144 return 0
145
146 if int(index) >= len(node.regs):
147 return 0
148
149 if node.regs[int(index)].addr is None:
150 return 0
151
152 return node.regs[int(index)].addr >> _dt_units_to_scale(unit)
153
154
155def _node_reg_size(node, index, unit):
156 if not node:
157 return 0
158
159 if not node.regs:
160 return 0
161
162 if int(index) >= len(node.regs):
163 return 0
164
165 if node.regs[int(index)].size is None:
166 return 0
167
168 return node.regs[int(index)].size >> _dt_units_to_scale(unit)
169
170
171def _node_int_prop(node, prop):
172 if not node:
173 return 0
174
175 if prop not in node.props:
176 return 0
177
178 if node.props[prop].type != "int":
179 return 0
180
181 return node.props[prop].val
182
183
184def _dt_chosen_reg_addr(kconf, chosen, index=0, unit=None):
185 """
186 This function takes a 'chosen' property and treats that property as a path
187 to an EDT node. If it finds an EDT node, it will look to see if that
188 nodnode has a register at the given 'index' and return the address value of
189 that reg, if not we return 0.
190
191 The function will divide the value based on 'unit':
192 None No division
193 'k' or 'K' divide by 1024 (1 << 10)
194 'm' or 'M' divide by 1,048,576 (1 << 20)
195 'g' or 'G' divide by 1,073,741,824 (1 << 30)
196 """
197 if doc_mode or edt is None:
198 return 0
199
200 node = edt.chosen_node(chosen)
201
202 return _node_reg_addr(node, index, unit)
203
204
205def _dt_chosen_reg_size(kconf, chosen, index=0, unit=None):
206 """
207 This function takes a 'chosen' property and treats that property as a path
208 to an EDT node. If it finds an EDT node, it will look to see if that node
209 has a register at the given 'index' and return the size value of that reg,
210 if not we return 0.
211
212 The function will divide the value based on 'unit':
213 None No division
214 'k' or 'K' divide by 1024 (1 << 10)
215 'm' or 'M' divide by 1,048,576 (1 << 20)
216 'g' or 'G' divide by 1,073,741,824 (1 << 30)
217 """
218 if doc_mode or edt is None:
219 return 0
220
221 node = edt.chosen_node(chosen)
222
223 return _node_reg_size(node, index, unit)
224
225
226def dt_chosen_reg(kconf, name, chosen, index=0, unit=None):
227 """
228 This function just routes to the proper function and converts
229 the result to either a string int or string hex value.
230 """
231 if name == "dt_chosen_reg_size_int":
232 return str(_dt_chosen_reg_size(kconf, chosen, index, unit))
233 if name == "dt_chosen_reg_size_hex":
234 return hex(_dt_chosen_reg_size(kconf, chosen, index, unit))
235 if name == "dt_chosen_reg_addr_int":
236 return str(_dt_chosen_reg_addr(kconf, chosen, index, unit))
237 if name == "dt_chosen_reg_addr_hex":
238 return hex(_dt_chosen_reg_addr(kconf, chosen, index, unit))
239
240
241def _dt_node_reg_addr(kconf, path, index=0, unit=None):
242 """
243 This function takes a 'path' and looks for an EDT node at that path. If it
244 finds an EDT node, it will look to see if that node has a register at the
245 given 'index' and return the address value of that reg, if not we return 0.
246
247 The function will divide the value based on 'unit':
248 None No division
249 'k' or 'K' divide by 1024 (1 << 10)
250 'm' or 'M' divide by 1,048,576 (1 << 20)
251 'g' or 'G' divide by 1,073,741,824 (1 << 30)
252 """
253 if doc_mode or edt is None:
254 return 0
255
256 try:
257 node = edt.get_node(path)
258 except edtlib.EDTError:
259 return 0
260
261 return _node_reg_addr(node, index, unit)
262
263
264def _dt_node_reg_size(kconf, path, index=0, unit=None):
265 """
266 This function takes a 'path' and looks for an EDT node at that path. If it
267 finds an EDT node, it will look to see if that node has a register at the
268 given 'index' and return the size value of that reg, if not we return 0.
269
270 The function will divide the value based on 'unit':
271 None No division
272 'k' or 'K' divide by 1024 (1 << 10)
273 'm' or 'M' divide by 1,048,576 (1 << 20)
274 'g' or 'G' divide by 1,073,741,824 (1 << 30)
275 """
276 if doc_mode or edt is None:
277 return 0
278
279 try:
280 node = edt.get_node(path)
281 except edtlib.EDTError:
282 return 0
283
284 return _node_reg_size(node, index, unit)
285
286
287def dt_node_reg(kconf, name, path, index=0, unit=None):
288 """
289 This function just routes to the proper function and converts
290 the result to either a string int or string hex value.
291 """
292 if name == "dt_node_reg_size_int":
293 return str(_dt_node_reg_size(kconf, path, index, unit))
294 if name == "dt_node_reg_size_hex":
295 return hex(_dt_node_reg_size(kconf, path, index, unit))
296 if name == "dt_node_reg_addr_int":
297 return str(_dt_node_reg_addr(kconf, path, index, unit))
298 if name == "dt_node_reg_addr_hex":
299 return hex(_dt_node_reg_addr(kconf, path, index, unit))
300
301
302def dt_node_has_bool_prop(kconf, _, path, prop):
303 """
304 This function takes a 'path' and looks for an EDT node at that path. If it
305 finds an EDT node, it will look to see if that node has a boolean property
306 by the name of 'prop'. If the 'prop' exists it will return "y" otherwise
307 we return "n".
308 """
309 if doc_mode or edt is None:
310 return "n"
311
312 try:
313 node = edt.get_node(path)
314 except edtlib.EDTError:
315 return "n"
316
317 if prop not in node.props:
318 return "n"
319
320 if node.props[prop].type != "boolean":
321 return "n"
322
323 if node.props[prop].val:
324 return "y"
325
326 return "n"
327
328def dt_node_has_prop(kconf, _, label, prop):
329 """
330 This function takes a 'label' and looks for an EDT node for that label. If
331 it finds an EDT node, it will look to see if that node has a property
332 by the name of 'prop'. If the 'prop' exists it will return "y" otherwise
333 we return "n".
334 """
335
336 if doc_mode or edt is None:
337 return "n"
338
339 try:
340 node = edt.label2node.get(label)
341 except edtlib.EDTError:
342 return "n"
343
344 if node is None:
345 return "n"
346
347 if prop in node.props:
348 return "y"
349
350 return "n"
351
352def dt_node_int_prop(kconf, name, path, prop):
353 """
354 This function takes a 'path' and property name ('prop') looks for an EDT
355 node at that path. If it finds an EDT node, it will look to see if that
356 node has a property called 'prop' and if that 'prop' is an integer type
357 will return the value of the property 'prop' as either a string int or
358 string hex value, if not we return 0.
359 """
360
361 if doc_mode or edt is None:
362 return "0"
363
364 try:
365 node = edt.get_node(path)
366 except edtlib.EDTError:
367 return "0"
368
369 if name == "dt_node_int_prop_int":
370 return str(_node_int_prop(node, prop))
371 if name == "dt_node_int_prop_hex":
372 return hex(_node_int_prop(node, prop))
373
374
375def dt_compat_enabled(kconf, _, compat):
376 """
377 This function takes a 'compat' and returns "y" if we find a status "okay"
378 compatible node in the EDT otherwise we return "n"
379 """
380 if doc_mode or edt is None:
381 return "n"
382
383 return "y" if compat in edt.compat2okay else "n"
384
385
386def dt_compat_on_bus(kconf, _, compat, bus):
387 """
388 This function takes a 'compat' and returns "y" if we find an "enabled"
389 compatible node in the EDT which is on bus 'bus'. It returns "n" otherwise.
390 """
391 if doc_mode or edt is None:
392 return "n"
393
394 if compat in edt.compat2okay:
395 for node in edt.compat2okay[compat]:
396 if node.on_bus is not None and node.on_bus == bus:
397 return "y"
398
399 return "n"
400
401
402def dt_nodelabel_has_compat(kconf, _, label, compat):
403 """
404 This function takes a 'label' and returns "y" if an "enabled" node with
405 such label can be found in the EDT and that node is compatible with the
406 provided 'compat', otherwise it returns "n".
407 """
408 if doc_mode or edt is None:
409 return "n"
410
411 if compat in edt.compat2okay:
412 for node in edt.compat2okay[compat]:
413 if label in node.labels:
414 return "y"
415
416 return "n"
417
418
419def dt_nodelabel_path(kconf, _, label):
420 """
421 This function takes a node label (not a label property) and
422 returns the path to the node which has that label, or an empty
423 string if there is no such node.
424 """
425 if doc_mode or edt is None:
426 return ""
427
428 node = edt.label2node.get(label)
429
430 return node.path if node else ""
431
432
433def shields_list_contains(kconf, _, shield):
434 """
435 Return "n" if cmake environment variable 'SHIELD_AS_LIST' doesn't exist.
436 Return "y" if 'shield' is present list obtained after 'SHIELD_AS_LIST'
437 has been split using ";" as a separator and "n" otherwise.
438 """
439 try:
440 list = os.environ['SHIELD_AS_LIST']
441 except KeyError:
442 return "n"
443
444 return "y" if shield in list.split(";") else "n"
445
446
447# Keys in this dict are the function names as they appear
448# in Kconfig files. The values are tuples in this form:
449#
450# (python_function, minimum_number_of_args, maximum_number_of_args)
451#
452# Each python function is given a kconf object and its name in the
453# Kconfig file, followed by arguments from the Kconfig file.
454#
455# See the kconfiglib documentation for more details.
456functions = {
457 "dt_compat_enabled": (dt_compat_enabled, 1, 1),
458 "dt_compat_on_bus": (dt_compat_on_bus, 2, 2),
459 "dt_chosen_label": (dt_chosen_label, 1, 1),
460 "dt_chosen_enabled": (dt_chosen_enabled, 1, 1),
461 "dt_chosen_path": (dt_chosen_path, 1, 1),
462 "dt_path_enabled": (dt_node_enabled, 1, 1),
463 "dt_alias_enabled": (dt_node_enabled, 1, 1),
464 "dt_nodelabel_enabled": (dt_nodelabel_enabled, 1, 1),
465 "dt_chosen_reg_addr_int": (dt_chosen_reg, 1, 3),
466 "dt_chosen_reg_addr_hex": (dt_chosen_reg, 1, 3),
467 "dt_chosen_reg_size_int": (dt_chosen_reg, 1, 3),
468 "dt_chosen_reg_size_hex": (dt_chosen_reg, 1, 3),
469 "dt_node_reg_addr_int": (dt_node_reg, 1, 3),
470 "dt_node_reg_addr_hex": (dt_node_reg, 1, 3),
471 "dt_node_reg_size_int": (dt_node_reg, 1, 3),
472 "dt_node_reg_size_hex": (dt_node_reg, 1, 3),
473 "dt_node_has_bool_prop": (dt_node_has_bool_prop, 2, 2),
474 "dt_node_has_prop": (dt_node_has_prop, 2, 2),
475 "dt_node_int_prop_int": (dt_node_int_prop, 2, 2),
476 "dt_node_int_prop_hex": (dt_node_int_prop, 2, 2),
477 "dt_nodelabel_has_compat": (dt_nodelabel_has_compat, 2, 2),
478 "dt_nodelabel_path": (dt_nodelabel_path, 1, 1),
479 "shields_list_contains": (shields_list_contains, 1, 1),
480}