1# Copyright (c) 2018-2019 Linaro
2# Copyright (c) 2019 Nordic Semiconductor ASA
3#
4# SPDX-License-Identifier: Apache-2.0
5
6import functools
7import inspect
8import operator
9import os
10import pickle
11import re
12import sys
13from pathlib import Path
14
15ZEPHYR_BASE = str(Path(__file__).resolve().parents[2])
16sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts", "dts",
17                                "python-devicetree", "src"))
18
19# Types we support
20# 'string', 'int', 'hex', 'bool'
21
22doc_mode = os.environ.get('KCONFIG_DOC_MODE') == "1"
23
24if not doc_mode:
25    EDT_PICKLE = os.environ.get("EDT_PICKLE")
26
27    # The "if" handles a missing dts.
28    if EDT_PICKLE is not None and os.path.isfile(EDT_PICKLE):
29        with open(EDT_PICKLE, 'rb') as f:
30            edt = pickle.load(f)
31            edtlib = inspect.getmodule(edt)
32    else:
33        edt = None
34        edtlib = None
35
36
37def _warn(kconf, msg):
38    print("{}:{}: WARNING: {}".format(kconf.filename, kconf.linenr, msg))
39
40
41def _dt_units_to_scale(unit):
42    if not unit:
43        return 0
44    if unit in {'k', 'K'}:
45        return 10
46    if unit in {'m', 'M'}:
47        return 20
48    if unit in {'g', 'G'}:
49        return 30
50    if unit in {'kb', 'Kb'}:
51        return 13
52    if unit in {'mb', 'Mb'}:
53        return 23
54    if unit in {'gb', 'Gb'}:
55        return 33
56
57
58def dt_chosen_label(kconf, _, chosen):
59    """
60    This function takes a 'chosen' property and treats that property as a path
61    to an EDT node.  If it finds an EDT node, it will look to see if that node
62    has a "label" property and return the value of that "label". If not, we
63    return the node's name in the devicetree.
64    """
65    if doc_mode or edt is None:
66        return ""
67
68    node = edt.chosen_node(chosen)
69    if not node:
70        return ""
71
72    if "label" not in node.props:
73        return node.name
74
75    return node.props["label"].val
76
77
78def dt_chosen_enabled(kconf, _, chosen):
79    """
80    This function returns "y" if /chosen contains a property named 'chosen'
81    that points to an enabled node, and "n" otherwise
82    """
83    if doc_mode or edt is None:
84        return "n"
85
86    node = edt.chosen_node(chosen)
87    return "y" if node and node.status == "okay" else "n"
88
89
90def dt_chosen_path(kconf, _, chosen):
91    """
92    This function takes a /chosen node property and returns the path
93    to the node in the property value, or the empty string.
94    """
95    if doc_mode or edt is None:
96        return "n"
97
98    node = edt.chosen_node(chosen)
99
100    return node.path if node else ""
101
102def dt_chosen_has_compat(kconf, _, chosen, compat):
103    """
104    This function takes a /chosen node property and returns 'y' if the
105    chosen node has the provided compatible string 'compat'
106    """
107    if doc_mode or edt is None:
108        return "n"
109
110    node = edt.chosen_node(chosen)
111
112    if node is None:
113        return "n"
114
115    if compat in node.compats:
116        return "y"
117
118    return "n"
119
120def dt_node_enabled(kconf, name, node):
121    """
122    This function is used to test if a node is enabled (has status
123    'okay') or not.
124
125    The 'node' argument is a string which is either a path or an
126    alias, or both, depending on 'name'.
127
128    If 'name' is 'dt_path_enabled', 'node' is an alias or a path. If
129    'name' is 'dt_alias_enabled, 'node' is an alias.
130    """
131
132    if doc_mode or edt is None:
133        return "n"
134
135    if name == "dt_alias_enabled":
136        if node.startswith("/"):
137            # EDT.get_node() works with either aliases or paths. If we
138            # are specifically being asked about an alias, reject paths.
139            return "n"
140    else:
141        # Make sure this is being called appropriately.
142        assert name == "dt_path_enabled"
143
144    try:
145        node = edt.get_node(node)
146    except edtlib.EDTError:
147        return "n"
148
149    return "y" if node and node.status == "okay" else "n"
150
151
152def dt_nodelabel_enabled(kconf, _, label):
153    """
154    This function is like dt_node_enabled(), but the 'label' argument
155    should be a node label, like "foo" is here:
156
157       foo: some-node { ... };
158    """
159    if doc_mode or edt is None:
160        return "n"
161
162    node = edt.label2node.get(label)
163
164    return "y" if node and node.status == "okay" else "n"
165
166
167def _node_reg_addr(node, index, unit):
168    if not node:
169        return 0
170
171    if not node.regs:
172        return 0
173
174    if int(index) >= len(node.regs):
175        return 0
176
177    if node.regs[int(index)].addr is None:
178        return 0
179
180    return node.regs[int(index)].addr >> _dt_units_to_scale(unit)
181
182
183def _node_reg_size(node, index, unit):
184    if not node:
185        return 0
186
187    if not node.regs:
188        return 0
189
190    if int(index) >= len(node.regs):
191        return 0
192
193    if node.regs[int(index)].size is None:
194        return 0
195
196    return node.regs[int(index)].size >> _dt_units_to_scale(unit)
197
198
199def _node_int_prop(node, prop, unit=None):
200    """
201    This function takes a 'node' and  will look to see if that 'node' has a
202    property called 'prop' and if that 'prop' is an integer type will return
203    the value of the property 'prop' as either a string int or string hex
204    value, if not we return 0.
205
206    The function will divide the value based on 'unit':
207        None        No division
208        'k' or 'K'  divide by 1024 (1 << 10)
209        'm' or 'M'  divide by 1,048,576 (1 << 20)
210        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
211        'kb' or 'Kb'  divide by 8192 (1 << 13)
212        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
213        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
214    """
215    if not node:
216        return 0
217
218    if prop not in node.props:
219        return 0
220
221    if node.props[prop].type != "int":
222        return 0
223
224    return node.props[prop].val >> _dt_units_to_scale(unit)
225
226
227def _node_array_prop(node, prop, index=0, unit=None):
228    """
229    This function takes a 'node' and  will look to see if that 'node' has a
230    property called 'prop' and if that 'prop' is an array type will return
231    the value of the property 'prop' at the given 'index' as either a string int
232    or string hex value. If the property 'prop' is not found or the given 'index'
233    is out of range it will return 0.
234
235    The function will divide the value based on 'unit':
236        None        No division
237        'k' or 'K'  divide by 1024 (1 << 10)
238        'm' or 'M'  divide by 1,048,576 (1 << 20)
239        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
240    """
241    if not node:
242        return 0
243
244    if prop not in node.props:
245        return 0
246    if node.props[prop].type != "array":
247        return 0
248    if int(index) >= len(node.props[prop].val):
249        return 0
250    return node.props[prop].val[int(index)] >> _dt_units_to_scale(unit)
251
252def _node_ph_array_prop(node, prop, index, cell, unit=None):
253    """
254    This function takes a 'node', a property name ('prop'), index ('index') and
255    a cell ('cell') and it will look to see if that node has a property
256    called 'prop' and if that 'prop' is an phandle-array type.
257    Then it will check if that phandle array has a cell matching the given index
258    and then return the value of the cell named 'cell' in this array index.
259    If not found it will return 0.
260
261    The function will divide the value based on 'unit':
262        None        No division
263        'k' or 'K'  divide by 1024 (1 << 10)
264        'm' or 'M'  divide by 1,048,576 (1 << 20)
265        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
266    """
267    if not node:
268        return 0
269
270    if prop not in node.props:
271        return 0
272    if node.props[prop].type != "phandle-array":
273        return 0
274    if int(index) >= len(node.props[prop].val):
275        return 0
276    if cell not in node.props[prop].val[int(index)].data.keys():
277        return 0
278    return node.props[prop].val[int(index)].data[cell] >> _dt_units_to_scale(unit)
279
280def _dt_chosen_reg_addr(kconf, chosen, index=0, unit=None):
281    """
282    This function takes a 'chosen' property and treats that property as a path
283    to an EDT node.  If it finds an EDT node, it will look to see if that
284    node has a register at the given 'index' and return the address value of
285    that reg, if not we return 0.
286
287    The function will divide the value based on 'unit':
288        None        No division
289        'k' or 'K'  divide by 1024 (1 << 10)
290        'm' or 'M'  divide by 1,048,576 (1 << 20)
291        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
292        'kb' or 'Kb'  divide by 8192 (1 << 13)
293        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
294        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
295    """
296    if doc_mode or edt is None:
297        return 0
298
299    node = edt.chosen_node(chosen)
300
301    return _node_reg_addr(node, index, unit)
302
303
304def _dt_chosen_reg_size(kconf, chosen, index=0, unit=None):
305    """
306    This function takes a 'chosen' property and treats that property as a path
307    to an EDT node.  If it finds an EDT node, it will look to see if that node
308    has a register at the given 'index' and return the size value of that reg,
309    if not we return 0.
310
311    The function will divide the value based on 'unit':
312        None        No division
313        'k' or 'K'  divide by 1024 (1 << 10)
314        'm' or 'M'  divide by 1,048,576 (1 << 20)
315        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
316        'kb' or 'Kb'  divide by 8192 (1 << 13)
317        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
318        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
319    """
320    if doc_mode or edt is None:
321        return 0
322
323    node = edt.chosen_node(chosen)
324
325    return _node_reg_size(node, index, unit)
326
327
328def dt_chosen_reg(kconf, name, chosen, index=0, unit=None):
329    """
330    This function just routes to the proper function and converts
331    the result to either a string int or string hex value.
332    """
333    if name == "dt_chosen_reg_size_int":
334        return str(_dt_chosen_reg_size(kconf, chosen, index, unit))
335    if name == "dt_chosen_reg_size_hex":
336        return hex(_dt_chosen_reg_size(kconf, chosen, index, unit))
337    if name == "dt_chosen_reg_addr_int":
338        return str(_dt_chosen_reg_addr(kconf, chosen, index, unit))
339    if name == "dt_chosen_reg_addr_hex":
340        return hex(_dt_chosen_reg_addr(kconf, chosen, index, unit))
341
342
343def _dt_chosen_partition_addr(kconf, chosen, index=0, unit=None):
344    """
345    This function takes a 'chosen' property and treats that property as a path
346    to an EDT node.  If it finds an EDT node, it will look to see if that
347    node has a register, and if that node has a grandparent that has a register
348    at the given 'index'. The addition of both addresses will be returned, if
349    not, we return 0.
350
351    The function will divide the value based on 'unit':
352        None        No division
353        'k' or 'K'  divide by 1024 (1 << 10)
354        'm' or 'M'  divide by 1,048,576 (1 << 20)
355        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
356        'kb' or 'Kb'  divide by 8192 (1 << 13)
357        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
358        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
359    """
360    if doc_mode or edt is None:
361        return 0
362
363    node = edt.chosen_node(chosen)
364    if not node:
365        return 0
366
367    p_node = node.parent
368    if not p_node:
369        return 0
370
371    return _node_reg_addr(p_node.parent, index, unit) + _node_reg_addr(node, 0, unit)
372
373
374def dt_chosen_partition_addr(kconf, name, chosen, index=0, unit=None):
375    """
376    This function just routes to the proper function and converts
377    the result to either a string int or string hex value.
378    """
379    if name == "dt_chosen_partition_addr_int":
380        return str(_dt_chosen_partition_addr(kconf, chosen, index, unit))
381    if name == "dt_chosen_partition_addr_hex":
382        return hex(_dt_chosen_partition_addr(kconf, chosen, index, unit))
383
384
385def _dt_node_reg_addr(kconf, path, index=0, unit=None):
386    """
387    This function takes a 'path' and looks for an EDT node at that path. If it
388    finds an EDT node, it will look to see if that node has a register at the
389    given 'index' and return the address value of that reg, if not we return 0.
390
391    The function will divide the value based on 'unit':
392        None        No division
393        'k' or 'K'  divide by 1024 (1 << 10)
394        'm' or 'M'  divide by 1,048,576 (1 << 20)
395        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
396        'kb' or 'Kb'  divide by 8192 (1 << 13)
397        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
398        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
399    """
400    if doc_mode or edt is None:
401        return 0
402
403    try:
404        node = edt.get_node(path)
405    except edtlib.EDTError:
406        return 0
407
408    return _node_reg_addr(node, index, unit)
409
410
411def _dt_node_reg_size(kconf, path, index=0, unit=None):
412    """
413    This function takes a 'path' and looks for an EDT node at that path. If it
414    finds an EDT node, it will look to see if that node has a register at the
415    given 'index' and return the size value of that reg, if not we return 0.
416
417    The function will divide the value based on 'unit':
418        None        No division
419        'k' or 'K'  divide by 1024 (1 << 10)
420        'm' or 'M'  divide by 1,048,576 (1 << 20)
421        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
422        'kb' or 'Kb'  divide by 8192 (1 << 13)
423        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
424        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
425    """
426    if doc_mode or edt is None:
427        return 0
428
429    try:
430        node = edt.get_node(path)
431    except edtlib.EDTError:
432        return 0
433
434    return _node_reg_size(node, index, unit)
435
436
437def dt_node_reg(kconf, name, path, index=0, unit=None):
438    """
439    This function just routes to the proper function and converts
440    the result to either a string int or string hex value.
441    """
442    if name == "dt_node_reg_size_int":
443        return str(_dt_node_reg_size(kconf, path, index, unit))
444    if name == "dt_node_reg_size_hex":
445        return hex(_dt_node_reg_size(kconf, path, index, unit))
446    if name == "dt_node_reg_addr_int":
447        return str(_dt_node_reg_addr(kconf, path, index, unit))
448    if name == "dt_node_reg_addr_hex":
449        return hex(_dt_node_reg_addr(kconf, path, index, unit))
450
451def dt_nodelabel_reg(kconf, name, label, index=0, unit=None):
452    """
453    This function is like dt_node_reg(), but the 'label' argument
454    should be a node label, like "foo" is here:
455
456       foo: some-node { ... };
457    """
458    if doc_mode or edt is None:
459        node = None
460    else:
461        node = edt.label2node.get(label)
462
463    if name == "dt_nodelabel_reg_size_int":
464        return str(_dt_node_reg_size(kconf, node.path, index, unit)) if node else "0"
465    if name == "dt_nodelabel_reg_size_hex":
466        return hex(_dt_node_reg_size(kconf, node.path, index, unit)) if node else "0x0"
467    if name == "dt_nodelabel_reg_addr_int":
468        return str(_dt_node_reg_addr(kconf, node.path, index, unit)) if node else "0"
469    if name == "dt_nodelabel_reg_addr_hex":
470        return hex(_dt_node_reg_addr(kconf, node.path, index, unit)) if node else "0x0"
471
472
473def _dt_node_bool_prop_generic(node_search_function, search_arg, prop):
474    """
475    This function takes the 'node_search_function' and uses it to search for
476    a node with 'search_arg' and if node exists, checks if 'prop' exists
477    inside the node and is a boolean, if it is true, returns "y".
478    Otherwise, it returns "n".
479    """
480    try:
481        node = node_search_function(search_arg)
482    except edtlib.EDTError:
483        return "n"
484
485    if node is None:
486        return "n"
487
488    if prop not in node.props:
489        return "n"
490
491    if node.props[prop].type != "boolean":
492        return "n"
493
494    if node.props[prop].val:
495        return "y"
496
497    return "n"
498
499def dt_node_bool_prop(kconf, _, path, prop):
500    """
501    This function takes a 'path' and looks for an EDT node at that path. If it
502    finds an EDT node, it will look to see if that node has a boolean property
503    by the name of 'prop'.  If the 'prop' exists it will return "y" otherwise
504    we return "n".
505    """
506    if doc_mode or edt is None:
507        return "n"
508
509    return _dt_node_bool_prop_generic(edt.get_node, path, prop)
510
511def dt_nodelabel_bool_prop(kconf, _, label, prop):
512    """
513    This function takes a 'label' and looks for an EDT node with that label.
514    If it finds an EDT node, it will look to see if that node has a boolean
515    property by the name of 'prop'.  If the 'prop' exists it will return "y"
516    otherwise we return "n".
517    """
518    if doc_mode or edt is None:
519        return "n"
520
521    return _dt_node_bool_prop_generic(edt.label2node.get, label, prop)
522
523def dt_chosen_bool_prop(kconf, _, chosen, prop):
524    """
525    This function takes a /chosen node property named 'chosen', and
526    looks for the chosen node. If that node exists and has a boolean
527    property 'prop', it returns "y". Otherwise, it returns "n".
528    """
529    if doc_mode or edt is None:
530        return "n"
531
532    return _dt_node_bool_prop_generic(edt.chosen_node, chosen, prop)
533
534def _dt_node_has_prop_generic(node_search_function, search_arg, prop):
535    """
536    This function takes the 'node_search_function' and uses it to search for
537    a node with 'search_arg' and if node exists, then checks if 'prop'
538    exists inside the node and returns "y". Otherwise, it returns "n".
539    """
540    try:
541        node = node_search_function(search_arg)
542    except edtlib.EDTError:
543        return "n"
544
545    if node is None:
546        return "n"
547
548    if prop in node.props:
549        return "y"
550
551    return "n"
552
553def dt_node_has_prop(kconf, _, path, prop):
554    """
555    This function takes a 'path' and looks for an EDT node at that path. If it
556    finds an EDT node, it will look to see if that node has a property
557    by the name of 'prop'.  If the 'prop' exists it will return "y" otherwise
558    it returns "n".
559    """
560    if doc_mode or edt is None:
561        return "n"
562
563    return _dt_node_has_prop_generic(edt.get_node, path, prop)
564
565def dt_nodelabel_has_prop(kconf, _, label, prop):
566    """
567    This function takes a 'label' and looks for an EDT node with that label.
568    If it finds an EDT node, it will look to see if that node has a property
569    by the name of 'prop'.  If the 'prop' exists it will return "y" otherwise
570    it returns "n".
571    """
572    if doc_mode or edt is None:
573        return "n"
574
575    return _dt_node_has_prop_generic(edt.label2node.get, label, prop)
576
577def dt_node_int_prop(kconf, name, path, prop, unit=None):
578    """
579    This function takes a 'path' and property name ('prop') looks for an EDT
580    node at that path. If it finds an EDT node, it will look to see if that
581    node has a property called 'prop' and if that 'prop' is an integer type
582    will return the value of the property 'prop' as either a string int or
583    string hex value, if not we return 0.
584
585    The function will divide the value based on 'unit':
586        None        No division
587        'k' or 'K'  divide by 1024 (1 << 10)
588        'm' or 'M'  divide by 1,048,576 (1 << 20)
589        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
590        'kb' or 'Kb'  divide by 8192 (1 << 13)
591        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
592        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
593    """
594    if doc_mode or edt is None:
595        return "0"
596
597    try:
598        node = edt.get_node(path)
599    except edtlib.EDTError:
600        return "0"
601
602    if name == "dt_node_int_prop_int":
603        return str(_node_int_prop(node, prop, unit))
604    if name == "dt_node_int_prop_hex":
605        return hex(_node_int_prop(node, prop, unit))
606
607
608def dt_node_array_prop(kconf, name, path, prop, index, unit=None):
609    """
610    This function takes a 'path', property name ('prop') and index ('index')
611    and looks for an EDT node at that path. If it finds an EDT node, it will
612    look to see if that node has a property called 'prop' and if that 'prop'
613    is an array type will return the value of the property 'prop' at the given
614    'index' as either a string int or string hex value. If not found we return 0.
615
616    The function will divide the value based on 'unit':
617        None        No division
618        'k' or 'K'  divide by 1024 (1 << 10)
619        'm' or 'M'  divide by 1,048,576 (1 << 20)
620        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
621    """
622    if doc_mode or edt is None:
623        return "0"
624
625    try:
626        node = edt.get_node(path)
627    except edtlib.EDTError:
628        return "0"
629    if name == "dt_node_array_prop_int":
630        return str(_node_array_prop(node, prop, index, unit))
631    if name == "dt_node_array_prop_hex":
632        return hex(_node_array_prop(node, prop, index, unit))
633
634
635def dt_node_ph_array_prop(kconf, name, path, prop, index, cell, unit=None):
636    """
637    This function takes a 'path', property name ('prop'), index ('index') and
638    a cell ('cell') and looks for an EDT node at that path.
639    If it finds an EDT node, it will look to see if that node has a property
640    called 'prop' and if that 'prop' is an phandle-array type.
641    Then it will check if that phandle array has a cell matching the given index
642    and ten return the value of the cell named 'cell' in this array index as
643    either a string int or string hex value. If not found we return 0.
644
645    The function will divide the value based on 'unit':
646        None        No division
647        'k' or 'K'  divide by 1024 (1 << 10)
648        'm' or 'M'  divide by 1,048,576 (1 << 20)
649        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
650    """
651    if doc_mode or edt is None:
652        return "0"
653
654    try:
655        node = edt.get_node(path)
656    except edtlib.EDTError:
657        return "0"
658    if name == "dt_node_ph_array_prop_int":
659        return str(_node_ph_array_prop(node, prop, index, cell, unit))
660    if name == "dt_node_ph_array_prop_hex":
661        return hex(_node_ph_array_prop(node, prop, index, cell, unit))
662
663def dt_node_ph_prop_path(kconf, name, path, prop):
664    """
665    This function takes a 'path' and a property name ('prop') and
666    looks for an EDT node at that path. If it finds an EDT node,
667    it will look to see if that node has a property called 'prop'
668    and if that 'prop' is an phandle type. Then it will return the
669    path to the pointed-to node, or an empty string if there is
670    no such node.
671    """
672    if doc_mode or edt is None:
673        return ""
674
675    try:
676        node = edt.get_node(path)
677    except edtlib.EDTError:
678        return ""
679
680    if prop not in node.props:
681        return ""
682    if node.props[prop].type != "phandle":
683        return ""
684
685    phandle = node.props[prop].val
686
687    return phandle.path if phandle else ""
688
689def dt_node_str_prop_equals(kconf, _, path, prop, val):
690    """
691    This function takes a 'path' and property name ('prop') looks for an EDT
692    node at that path. If it finds an EDT node, it will look to see if that
693    node has a property 'prop' of type string. If that 'prop' is equal to 'val'
694    it will return "y" otherwise return "n".
695    """
696
697    if doc_mode or edt is None:
698        return "n"
699
700    try:
701        node = edt.get_node(path)
702    except edtlib.EDTError:
703        return "n"
704
705    if prop not in node.props:
706        return "n"
707
708    if node.props[prop].type != "string":
709        return "n"
710
711    if node.props[prop].val == val:
712        return "y"
713
714    return "n"
715
716
717def dt_has_compat(kconf, _, compat):
718    """
719    This function takes a 'compat' and returns "y" if any compatible node
720    can be found in the EDT, otherwise it returns "n".
721    """
722    if doc_mode or edt is None:
723        return "n"
724
725    return "y" if compat in edt.compat2nodes else "n"
726
727
728def dt_compat_enabled(kconf, _, compat):
729    """
730    This function takes a 'compat' and returns "y" if we find a status "okay"
731    compatible node in the EDT otherwise we return "n"
732    """
733    if doc_mode or edt is None:
734        return "n"
735
736    return "y" if compat in edt.compat2okay else "n"
737
738
739def dt_compat_on_bus(kconf, _, compat, bus):
740    """
741    This function takes a 'compat' and returns "y" if we find an enabled
742    compatible node in the EDT which is on bus 'bus'. It returns "n" otherwise.
743    """
744    if doc_mode or edt is None:
745        return "n"
746
747    if compat in edt.compat2okay:
748        for node in edt.compat2okay[compat]:
749            if node.on_buses is not None and bus in node.on_buses:
750                return "y"
751
752    return "n"
753
754def dt_compat_any_has_prop(kconf, _, compat, prop, value=None):
755    """
756    This function takes a 'compat', a 'prop', and a 'value'.
757    If value=None, the function returns "y" if any
758    enabled node with compatible 'compat' also has a valid property 'prop'.
759    If value is given, the function returns "y" if any enabled node with compatible 'compat'
760    also has a valid property 'prop' with value 'value'.
761    It returns "n" otherwise.
762    """
763    if doc_mode or edt is None:
764        return "n"
765
766    if compat in edt.compat2okay:
767        for node in edt.compat2okay[compat]:
768            if prop in node.props:
769                if value is None:
770                    return "y"
771                elif str(node.props[prop].val) == value:
772                    return "y"
773    return "n"
774
775def dt_compat_any_not_has_prop(kconf, _, compat, prop):
776    """
777    This function takes a 'compat', and a 'prop'.
778    The function returns "y" if any enabled node with compatible 'compat'
779    does NOT contain the property 'prop'.
780    It returns "n" otherwise.
781    """
782    if doc_mode or edt is None:
783        return "n"
784
785    if compat in edt.compat2okay:
786        for node in edt.compat2okay[compat]:
787            if prop not in node.props:
788                return "y"
789
790    return "n"
791
792def dt_nodelabel_has_compat(kconf, _, label, compat):
793    """
794    This function takes a 'label' and looks for an EDT node with that label.
795    If it finds such node, it returns "y" if this node is compatible with
796    the provided 'compat'. Otherwise, it return "n" .
797    """
798    if doc_mode or edt is None:
799        return "n"
800
801    node = edt.label2node.get(label)
802
803    if node and compat in node.compats:
804        return "y"
805
806    return "n"
807
808def dt_node_has_compat(kconf, _, path, compat):
809    """
810    This function takes a 'path' and looks for an EDT node at that path. If it
811    finds an EDT node, it returns "y" if this node is compatible with
812    the provided 'compat'. Otherwise, it return "n" .
813    """
814
815    if doc_mode or edt is None:
816        return "n"
817
818    try:
819        node = edt.get_node(path)
820    except edtlib.EDTError:
821        return "n"
822
823    if node and compat in node.compats:
824        return "y"
825
826    return "n"
827
828def dt_nodelabel_enabled_with_compat(kconf, _, label, compat):
829    """
830    This function takes a 'label' and returns "y" if an enabled node with
831    such label can be found in the EDT and that node is compatible with the
832    provided 'compat', otherwise it returns "n".
833    """
834    if doc_mode or edt is None:
835        return "n"
836
837    if compat in edt.compat2okay:
838        for node in edt.compat2okay[compat]:
839            if label in node.labels:
840                return "y"
841
842    return "n"
843
844
845def dt_nodelabel_array_prop_has_val(kconf, _, label, prop, val):
846    """
847    This function looks for a node with node label 'label'.
848    If the node exists, it checks if the node node has a property
849    'prop' with type "array". If so, and the property contains
850    an element equal to the integer 'val', it returns "y".
851    Otherwise, it returns "n".
852    """
853    if doc_mode or edt is None:
854        return "n"
855
856    node = edt.label2node.get(label)
857
858    if not node or (prop not in node.props) or (node.props[prop].type != "array"):
859        return "n"
860    else:
861        return "y" if int(val, base=0) in node.props[prop].val else "n"
862
863
864def dt_nodelabel_path(kconf, _, label):
865    """
866    This function takes a node label (not a label property) and
867    returns the path to the node which has that label, or an empty
868    string if there is no such node.
869    """
870    if doc_mode or edt is None:
871        return ""
872
873    node = edt.label2node.get(label)
874
875    return node.path if node else ""
876
877def dt_node_parent(kconf, _, path):
878    """
879    This function takes a 'path' and looks for an EDT node at that path. If it
880    finds an EDT node, it will look for the parent of that node. If the parent
881    exists, it will return the path to that parent. Otherwise, an empty string
882    will be returned.
883    """
884    if doc_mode or edt is None:
885        return ""
886
887    try:
888        node = edt.get_node(path)
889    except edtlib.EDTError:
890        return ""
891
892    if node is None:
893        return ""
894
895    return node.parent.path if node.parent else ""
896
897def dt_gpio_hogs_enabled(kconf, _):
898    """
899    Return "y" if any GPIO hog node is enabled. Otherwise, return "n".
900    """
901    if doc_mode or edt is None:
902        return "n"
903
904    for node in edt.nodes:
905        if node.gpio_hogs and node.status == "okay":
906            return "y"
907
908    return "n"
909
910
911def normalize_upper(kconf, _, string):
912    """
913    Normalize the string, so that the string only contains alpha-numeric
914    characters or underscores. All non-alpha-numeric characters are replaced
915    with an underscore, '_'.
916    When string has been normalized it will be converted into upper case.
917    """
918    return re.sub(r'[^a-zA-Z0-9_]', '_', string).upper()
919
920
921def shields_list_contains(kconf, _, shield):
922    """
923    Return "n" if cmake environment variable 'SHIELD_AS_LIST' doesn't exist.
924    Return "y" if 'shield' is present list obtained after 'SHIELD_AS_LIST'
925    has been split using ";" as a separator and "n" otherwise.
926    """
927    try:
928        list = os.environ['SHIELD_AS_LIST']
929    except KeyError:
930        return "n"
931
932    return "y" if shield in list.split(";") else "n"
933
934
935def substring(kconf, _, string, start, stop=None):
936    """
937    Extracts a portion of the string, removing characters from the front, back or both.
938    """
939    if stop is not None:
940        return string[int(start):int(stop)]
941    else:
942        return string[int(start):]
943
944def arith(kconf, name, *args):
945    """
946    The arithmetic operations on integers.
947    If three or more arguments are given, it returns the result of performing
948    the operation on the first two arguments and operates the same operation as
949    the result and the following argument.
950    For interoperability with inc and dec,
951    if there is only one argument, it will be split with a comma and processed
952    as a sequence of numbers.
953
954    Examples in Kconfig:
955
956    $(add, 10, 3)          # -> 13
957    $(add, 10, 3, 2)       # -> 15
958    $(sub, 10, 3)          # -> 7
959    $(sub, 10, 3, 2)       # -> 5
960    $(mul, 10, 3)          # -> 30
961    $(mul, 10, 3, 2)       # -> 60
962    $(div, 10, 3)          # -> 3
963    $(div, 10, 3, 2)       # -> 1
964    $(mod, 10, 3)          # -> 1
965    $(mod, 10, 3, 2)       # -> 1
966    $(inc, 1)              # -> 2
967    $(inc, 1, 1)           # -> "2,2"
968    $(inc, $(inc, 1, 1))   # -> "3,3"
969    $(dec, 1)              # -> 0
970    $(dec, 1, 1)           # -> "0,0"
971    $(dec, $(dec, 1, 1))   # -> "-1,-1"
972    $(add, $(inc, 1, 1))   # -> 4
973    $(div, $(dec, 1, 1))   # Error (0 div 0)
974    """
975
976    intarray = map(int, args if len(args) > 1 else args[0].split(","))
977
978    if name == "add":
979        return str(int(functools.reduce(operator.add, intarray)))
980    elif name == "sub":
981        return str(int(functools.reduce(operator.sub, intarray)))
982    elif name == "mul":
983        return str(int(functools.reduce(operator.mul, intarray)))
984    elif name == "div":
985        return str(int(functools.reduce(operator.truediv, intarray)))
986    elif name == "mod":
987        return str(int(functools.reduce(operator.mod, intarray)))
988    elif name == "max":
989        return str(int(functools.reduce(max, intarray)))
990    elif name == "min":
991        return str(int(functools.reduce(min, intarray)))
992    else:
993        assert False
994
995
996def inc_dec(kconf, name, *args):
997    """
998    Calculate the increment and the decrement of integer sequence.
999    Returns a string that concatenates numbers with a comma as a separator.
1000    """
1001
1002    intarray = map(int, args if len(args) > 1 else args[0].split(","))
1003
1004    if name == "inc":
1005        return ",".join(map(lambda a: str(a + 1), intarray))
1006    elif name == "dec":
1007        return ",".join(map(lambda a: str(a - 1), intarray))
1008    else:
1009        assert False
1010
1011
1012# Keys in this dict are the function names as they appear
1013# in Kconfig files. The values are tuples in this form:
1014#
1015#       (python_function, minimum_number_of_args, maximum_number_of_args)
1016#
1017# Each python function is given a kconf object and its name in the
1018# Kconfig file, followed by arguments from the Kconfig file.
1019#
1020# See the kconfiglib documentation for more details.
1021functions = {
1022        "dt_has_compat": (dt_has_compat, 1, 1),
1023        "dt_compat_enabled": (dt_compat_enabled, 1, 1),
1024        "dt_compat_on_bus": (dt_compat_on_bus, 2, 2),
1025        "dt_compat_any_has_prop": (dt_compat_any_has_prop, 2, 3),
1026        "dt_compat_any_not_has_prop": (dt_compat_any_not_has_prop, 2, 2),
1027        "dt_chosen_label": (dt_chosen_label, 1, 1),
1028        "dt_chosen_enabled": (dt_chosen_enabled, 1, 1),
1029        "dt_chosen_path": (dt_chosen_path, 1, 1),
1030        "dt_chosen_has_compat": (dt_chosen_has_compat, 2, 2),
1031        "dt_path_enabled": (dt_node_enabled, 1, 1),
1032        "dt_alias_enabled": (dt_node_enabled, 1, 1),
1033        "dt_nodelabel_enabled": (dt_nodelabel_enabled, 1, 1),
1034        "dt_nodelabel_enabled_with_compat": (dt_nodelabel_enabled_with_compat, 2, 2),
1035        "dt_chosen_reg_addr_int": (dt_chosen_reg, 1, 3),
1036        "dt_chosen_reg_addr_hex": (dt_chosen_reg, 1, 3),
1037        "dt_chosen_reg_size_int": (dt_chosen_reg, 1, 3),
1038        "dt_chosen_reg_size_hex": (dt_chosen_reg, 1, 3),
1039        "dt_node_reg_addr_int": (dt_node_reg, 1, 3),
1040        "dt_node_reg_addr_hex": (dt_node_reg, 1, 3),
1041        "dt_node_reg_size_int": (dt_node_reg, 1, 3),
1042        "dt_node_reg_size_hex": (dt_node_reg, 1, 3),
1043        "dt_nodelabel_reg_addr_int": (dt_nodelabel_reg, 1, 3),
1044        "dt_nodelabel_reg_addr_hex": (dt_nodelabel_reg, 1, 3),
1045        "dt_nodelabel_reg_size_int": (dt_nodelabel_reg, 1, 3),
1046        "dt_nodelabel_reg_size_hex": (dt_nodelabel_reg, 1, 3),
1047        "dt_node_bool_prop": (dt_node_bool_prop, 2, 2),
1048        "dt_nodelabel_bool_prop": (dt_nodelabel_bool_prop, 2, 2),
1049        "dt_chosen_bool_prop": (dt_chosen_bool_prop, 2, 2),
1050        "dt_node_has_prop": (dt_node_has_prop, 2, 2),
1051        "dt_nodelabel_has_prop": (dt_nodelabel_has_prop, 2, 2),
1052        "dt_node_int_prop_int": (dt_node_int_prop, 2, 3),
1053        "dt_node_int_prop_hex": (dt_node_int_prop, 2, 3),
1054        "dt_node_array_prop_int": (dt_node_array_prop, 3, 4),
1055        "dt_node_array_prop_hex": (dt_node_array_prop, 3, 4),
1056        "dt_node_ph_array_prop_int": (dt_node_ph_array_prop, 4, 5),
1057        "dt_node_ph_array_prop_hex": (dt_node_ph_array_prop, 4, 5),
1058        "dt_node_ph_prop_path": (dt_node_ph_prop_path, 2, 2),
1059        "dt_node_str_prop_equals": (dt_node_str_prop_equals, 3, 3),
1060        "dt_nodelabel_has_compat": (dt_nodelabel_has_compat, 2, 2),
1061        "dt_node_has_compat": (dt_node_has_compat, 2, 2),
1062        "dt_nodelabel_path": (dt_nodelabel_path, 1, 1),
1063        "dt_node_parent": (dt_node_parent, 1, 1),
1064        "dt_nodelabel_array_prop_has_val": (dt_nodelabel_array_prop_has_val, 3, 3),
1065        "dt_gpio_hogs_enabled": (dt_gpio_hogs_enabled, 0, 0),
1066        "dt_chosen_partition_addr_int": (dt_chosen_partition_addr, 1, 3),
1067        "dt_chosen_partition_addr_hex": (dt_chosen_partition_addr, 1, 3),
1068        "normalize_upper": (normalize_upper, 1, 1),
1069        "shields_list_contains": (shields_list_contains, 1, 1),
1070        "substring": (substring, 2, 3),
1071        "add": (arith, 1, 255),
1072        "sub": (arith, 1, 255),
1073        "mul": (arith, 1, 255),
1074        "div": (arith, 1, 255),
1075        "mod": (arith, 1, 255),
1076        "max": (arith, 1, 255),
1077        "min": (arith, 1, 255),
1078        "inc": (inc_dec, 1, 255),
1079        "dec": (inc_dec, 1, 255),
1080}
1081