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