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_nodelabel_int_prop(kconf, _, label, prop):
536    """
537    This function takes a 'label' and looks for an EDT node with that label.
538    If it finds an EDT node, it will look to see if that node has a int
539    property by the name of 'prop'.  If the 'prop' exists it will return the
540    value of the property, otherwise it returns "0".
541    """
542    if doc_mode or edt is None:
543        return "0"
544
545    try:
546        node = edt.label2node.get(label)
547    except edtlib.EDTError:
548        return "0"
549
550    if not node or node.props[prop].type != "int":
551        return "0"
552
553    if not node.props[prop].val:
554        return "0"
555
556    return str(node.props[prop].val)
557
558def dt_chosen_bool_prop(kconf, _, chosen, prop):
559    """
560    This function takes a /chosen node property named 'chosen', and
561    looks for the chosen node. If that node exists and has a boolean
562    property 'prop', it returns "y". Otherwise, it returns "n".
563    """
564    if doc_mode or edt is None:
565        return "n"
566
567    return _dt_node_bool_prop_generic(edt.chosen_node, chosen, prop)
568
569def _dt_node_has_prop_generic(node_search_function, search_arg, prop):
570    """
571    This function takes the 'node_search_function' and uses it to search for
572    a node with 'search_arg' and if node exists, then checks if 'prop'
573    exists inside the node and returns "y". Otherwise, it returns "n".
574    """
575    try:
576        node = node_search_function(search_arg)
577    except edtlib.EDTError:
578        return "n"
579
580    if node is None:
581        return "n"
582
583    if prop in node.props:
584        return "y"
585
586    return "n"
587
588def dt_node_has_prop(kconf, _, path, prop):
589    """
590    This function takes a 'path' and looks for an EDT node at that path. If it
591    finds an EDT node, it will look to see if that node has a property
592    by the name of 'prop'.  If the 'prop' exists it will return "y" otherwise
593    it returns "n".
594    """
595    if doc_mode or edt is None:
596        return "n"
597
598    return _dt_node_has_prop_generic(edt.get_node, path, prop)
599
600def dt_nodelabel_has_prop(kconf, _, label, prop):
601    """
602    This function takes a 'label' and looks for an EDT node with that label.
603    If it finds an EDT node, it will look to see if that node has a property
604    by the name of 'prop'.  If the 'prop' exists it will return "y" otherwise
605    it returns "n".
606    """
607    if doc_mode or edt is None:
608        return "n"
609
610    return _dt_node_has_prop_generic(edt.label2node.get, label, prop)
611
612def dt_node_int_prop(kconf, name, path, prop, unit=None):
613    """
614    This function takes a 'path' and property name ('prop') looks for an EDT
615    node at that path. If it finds an EDT node, it will look to see if that
616    node has a property called 'prop' and if that 'prop' is an integer type
617    will return the value of the property 'prop' as either a string int or
618    string hex value, if not we return 0.
619
620    The function will divide the value based on 'unit':
621        None        No division
622        'k' or 'K'  divide by 1024 (1 << 10)
623        'm' or 'M'  divide by 1,048,576 (1 << 20)
624        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
625        'kb' or 'Kb'  divide by 8192 (1 << 13)
626        'mb' or 'Mb'  divide by 8,388,608 (1 << 23)
627        'gb' or 'Gb'  divide by 8,589,934,592 (1 << 33)
628    """
629    if doc_mode or edt is None:
630        return "0"
631
632    try:
633        node = edt.get_node(path)
634    except edtlib.EDTError:
635        return "0"
636
637    if name == "dt_node_int_prop_int":
638        return str(_node_int_prop(node, prop, unit))
639    if name == "dt_node_int_prop_hex":
640        return hex(_node_int_prop(node, prop, unit))
641
642
643def dt_node_array_prop(kconf, name, path, prop, index, unit=None):
644    """
645    This function takes a 'path', property name ('prop') and index ('index')
646    and looks for an EDT node at that path. If it finds an EDT node, it will
647    look to see if that node has a property called 'prop' and if that 'prop'
648    is an array type will return the value of the property 'prop' at the given
649    'index' as either a string int or string hex value. If not found we return 0.
650
651    The function will divide the value based on 'unit':
652        None        No division
653        'k' or 'K'  divide by 1024 (1 << 10)
654        'm' or 'M'  divide by 1,048,576 (1 << 20)
655        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
656    """
657    if doc_mode or edt is None:
658        return "0"
659
660    try:
661        node = edt.get_node(path)
662    except edtlib.EDTError:
663        return "0"
664    if name == "dt_node_array_prop_int":
665        return str(_node_array_prop(node, prop, index, unit))
666    if name == "dt_node_array_prop_hex":
667        return hex(_node_array_prop(node, prop, index, unit))
668
669
670def dt_node_ph_array_prop(kconf, name, path, prop, index, cell, unit=None):
671    """
672    This function takes a 'path', property name ('prop'), index ('index') and
673    a cell ('cell') and looks for an EDT node at that path.
674    If it finds an EDT node, it will look to see if that node has a property
675    called 'prop' and if that 'prop' is an phandle-array type.
676    Then it will check if that phandle array has a cell matching the given index
677    and ten return the value of the cell named 'cell' in this array index as
678    either a string int or string hex value. If not found we return 0.
679
680    The function will divide the value based on 'unit':
681        None        No division
682        'k' or 'K'  divide by 1024 (1 << 10)
683        'm' or 'M'  divide by 1,048,576 (1 << 20)
684        'g' or 'G'  divide by 1,073,741,824 (1 << 30)
685    """
686    if doc_mode or edt is None:
687        return "0"
688
689    try:
690        node = edt.get_node(path)
691    except edtlib.EDTError:
692        return "0"
693    if name == "dt_node_ph_array_prop_int":
694        return str(_node_ph_array_prop(node, prop, index, cell, unit))
695    if name == "dt_node_ph_array_prop_hex":
696        return hex(_node_ph_array_prop(node, prop, index, cell, unit))
697
698def dt_node_ph_prop_path(kconf, name, path, prop):
699    """
700    This function takes a 'path' and a property name ('prop') and
701    looks for an EDT node at that path. If it finds an EDT node,
702    it will look to see if that node has a property called 'prop'
703    and if that 'prop' is an phandle type. Then it will return the
704    path to the pointed-to node, or an empty string if there is
705    no such node.
706    """
707    if doc_mode or edt is None:
708        return ""
709
710    try:
711        node = edt.get_node(path)
712    except edtlib.EDTError:
713        return ""
714
715    if prop not in node.props:
716        return ""
717    if node.props[prop].type != "phandle":
718        return ""
719
720    phandle = node.props[prop].val
721
722    return phandle.path if phandle else ""
723
724def dt_node_str_prop_equals(kconf, _, path, prop, val):
725    """
726    This function takes a 'path' and property name ('prop') looks for an EDT
727    node at that path. If it finds an EDT node, it will look to see if that
728    node has a property 'prop' of type string. If that 'prop' is equal to 'val'
729    it will return "y" otherwise return "n".
730    """
731
732    if doc_mode or edt is None:
733        return "n"
734
735    try:
736        node = edt.get_node(path)
737    except edtlib.EDTError:
738        return "n"
739
740    if prop not in node.props:
741        return "n"
742
743    if node.props[prop].type != "string":
744        return "n"
745
746    if node.props[prop].val == val:
747        return "y"
748
749    return "n"
750
751
752def dt_has_compat(kconf, _, compat):
753    """
754    This function takes a 'compat' and returns "y" if any compatible node
755    can be found in the EDT, otherwise it returns "n".
756    """
757    if doc_mode or edt is None:
758        return "n"
759
760    return "y" if compat in edt.compat2nodes else "n"
761
762
763def dt_compat_enabled(kconf, _, compat):
764    """
765    This function takes a 'compat' and returns "y" if we find a status "okay"
766    compatible node in the EDT otherwise we return "n"
767    """
768    if doc_mode or edt is None:
769        return "n"
770
771    return "y" if compat in edt.compat2okay else "n"
772
773
774def dt_compat_enabled_num(kconf, _, compat):
775    """
776    This function takes a 'compat' and the returns number of status "okay"
777    compatible nodes in the EDT.
778    """
779    if doc_mode or edt is None:
780        return "0"
781
782    return str(len(edt.compat2okay[compat]))
783
784
785def dt_compat_on_bus(kconf, _, compat, bus):
786    """
787    This function takes a 'compat' and returns "y" if we find an enabled
788    compatible node in the EDT which is on bus 'bus'. It returns "n" otherwise.
789    """
790    if doc_mode or edt is None:
791        return "n"
792
793    if compat in edt.compat2okay:
794        for node in edt.compat2okay[compat]:
795            if node.on_buses is not None and bus in node.on_buses:
796                return "y"
797
798    return "n"
799
800def dt_compat_any_has_prop(kconf, _, compat, prop, value=None):
801    """
802    This function takes a 'compat', a 'prop', and a 'value'.
803    If value=None, the function returns "y" if any
804    enabled node with compatible 'compat' also has a valid property 'prop'.
805    If value is given, the function returns "y" if any enabled node with compatible 'compat'
806    also has a valid property 'prop' with value 'value'.
807    It returns "n" otherwise.
808    """
809    if doc_mode or edt is None:
810        return "n"
811
812    if compat in edt.compat2okay:
813        for node in edt.compat2okay[compat]:
814            if prop in node.props:
815                if value is None:
816                    return "y"
817                elif str(node.props[prop].val) == value:
818                    return "y"
819    return "n"
820
821def dt_compat_any_not_has_prop(kconf, _, compat, prop):
822    """
823    This function takes a 'compat', and a 'prop'.
824    The function returns "y" if any enabled node with compatible 'compat'
825    does NOT contain the property 'prop'.
826    It returns "n" otherwise.
827    """
828    if doc_mode or edt is None:
829        return "n"
830
831    if compat in edt.compat2okay:
832        for node in edt.compat2okay[compat]:
833            if prop not in node.props:
834                return "y"
835
836    return "n"
837
838def dt_nodelabel_has_compat(kconf, _, label, compat):
839    """
840    This function takes a 'label' and looks for an EDT node with that label.
841    If it finds such node, it returns "y" if this node is compatible with
842    the provided 'compat'. Otherwise, it return "n" .
843    """
844    if doc_mode or edt is None:
845        return "n"
846
847    node = edt.label2node.get(label)
848
849    if node and compat in node.compats:
850        return "y"
851
852    return "n"
853
854def dt_node_has_compat(kconf, _, path, compat):
855    """
856    This function takes a 'path' and looks for an EDT node at that path. If it
857    finds an EDT node, it returns "y" if this node is compatible with
858    the provided 'compat'. Otherwise, it return "n" .
859    """
860
861    if doc_mode or edt is None:
862        return "n"
863
864    try:
865        node = edt.get_node(path)
866    except edtlib.EDTError:
867        return "n"
868
869    if node and compat in node.compats:
870        return "y"
871
872    return "n"
873
874def dt_nodelabel_enabled_with_compat(kconf, _, label, compat):
875    """
876    This function takes a 'label' and returns "y" if an enabled node with
877    such label can be found in the EDT and that node is compatible with the
878    provided 'compat', otherwise it returns "n".
879    """
880    if doc_mode or edt is None:
881        return "n"
882
883    if compat in edt.compat2okay:
884        for node in edt.compat2okay[compat]:
885            if label in node.labels:
886                return "y"
887
888    return "n"
889
890
891def dt_nodelabel_array_prop_has_val(kconf, _, label, prop, val):
892    """
893    This function looks for a node with node label 'label'.
894    If the node exists, it checks if the node node has a property
895    'prop' with type "array". If so, and the property contains
896    an element equal to the integer 'val', it returns "y".
897    Otherwise, it returns "n".
898    """
899    if doc_mode or edt is None:
900        return "n"
901
902    node = edt.label2node.get(label)
903
904    if not node or (prop not in node.props) or (node.props[prop].type != "array"):
905        return "n"
906    else:
907        return "y" if int(val, base=0) in node.props[prop].val else "n"
908
909
910def dt_nodelabel_path(kconf, _, label):
911    """
912    This function takes a node label (not a label property) and
913    returns the path to the node which has that label, or an empty
914    string if there is no such node.
915    """
916    if doc_mode or edt is None:
917        return ""
918
919    node = edt.label2node.get(label)
920
921    return node.path if node else ""
922
923def dt_node_parent(kconf, _, path):
924    """
925    This function takes a 'path' and looks for an EDT node at that path. If it
926    finds an EDT node, it will look for the parent of that node. If the parent
927    exists, it will return the path to that parent. Otherwise, an empty string
928    will be returned.
929    """
930    if doc_mode or edt is None:
931        return ""
932
933    try:
934        node = edt.get_node(path)
935    except edtlib.EDTError:
936        return ""
937
938    if node is None:
939        return ""
940
941    return node.parent.path if node.parent else ""
942
943def dt_gpio_hogs_enabled(kconf, _):
944    """
945    Return "y" if any GPIO hog node is enabled. Otherwise, return "n".
946    """
947    if doc_mode or edt is None:
948        return "n"
949
950    for node in edt.nodes:
951        if node.gpio_hogs and node.status == "okay":
952            return "y"
953
954    return "n"
955
956
957def normalize_upper(kconf, _, string):
958    """
959    Normalize the string, so that the string only contains alpha-numeric
960    characters or underscores. All non-alpha-numeric characters are replaced
961    with an underscore, '_'.
962    When string has been normalized it will be converted into upper case.
963    """
964    return re.sub(r'[^a-zA-Z0-9_]', '_', string).upper()
965
966
967def shields_list_contains(kconf, _, shield):
968    """
969    Return "n" if cmake environment variable 'SHIELD_AS_LIST' doesn't exist.
970    Return "y" if 'shield' is present list obtained after 'SHIELD_AS_LIST'
971    has been split using ";" as a separator and "n" otherwise.
972    """
973    try:
974        list = os.environ['SHIELD_AS_LIST']
975    except KeyError:
976        return "n"
977
978    return "y" if shield in list.split(";") else "n"
979
980
981def substring(kconf, _, string, start, stop=None):
982    """
983    Extracts a portion of the string, removing characters from the front, back or both.
984    """
985    if stop is not None:
986        return string[int(start):int(stop)]
987    else:
988        return string[int(start):]
989
990def arith(kconf, name, *args):
991    """
992    The arithmetic operations on integers.
993    If three or more arguments are given, it returns the result of performing
994    the operation on the first two arguments and operates the same operation as
995    the result and the following argument.
996    For interoperability with inc and dec,
997    each argument can be a single number or a comma-separated list of numbers,
998    but all numbers are processed as if they were individual arguments.
999
1000    Examples in Kconfig:
1001
1002    $(add, 10, 3)          # -> 13
1003    $(add, 10, 3, 2)       # -> 15
1004    $(sub, 10, 3)          # -> 7
1005    $(sub, 10, 3, 2)       # -> 5
1006    $(mul, 10, 3)          # -> 30
1007    $(mul, 10, 3, 2)       # -> 60
1008    $(div, 10, 3)          # -> 3
1009    $(div, 10, 3, 2)       # -> 1
1010    $(mod, 10, 3)          # -> 1
1011    $(mod, 10, 3, 2)       # -> 1
1012    $(inc, 1)              # -> 2
1013    $(inc, 1, 1)           # -> "2,2"
1014    $(inc, $(inc, 1, 1))   # -> "3,3"
1015    $(dec, 1)              # -> 0
1016    $(dec, 1, 1)           # -> "0,0"
1017    $(dec, $(dec, 1, 1))   # -> "-1,-1"
1018    $(add, $(inc, 1, 1))   # -> 4
1019    $(div, $(dec, 1, 1))   # Error (0 div 0)
1020    """
1021
1022    intarray = (int(val, base=0) for arg in args for val in arg.split(","))
1023
1024    if name == "add":
1025        return str(int(functools.reduce(operator.add, intarray)))
1026    elif name == "add_hex":
1027        return hex(int(functools.reduce(operator.add, intarray)))
1028    elif name == "sub":
1029        return str(int(functools.reduce(operator.sub, intarray)))
1030    elif name == "sub_hex":
1031        return hex(int(functools.reduce(operator.sub, intarray)))
1032    elif name == "mul":
1033        return str(int(functools.reduce(operator.mul, intarray)))
1034    elif name == "mul_hex":
1035        return hex(int(functools.reduce(operator.mul, intarray)))
1036    elif name == "div":
1037        return str(int(functools.reduce(operator.truediv, intarray)))
1038    elif name == "div_hex":
1039        return hex(int(functools.reduce(operator.truediv, intarray)))
1040    elif name == "mod":
1041        return str(int(functools.reduce(operator.mod, intarray)))
1042    elif name == "mod_hex":
1043        return hex(int(functools.reduce(operator.mod, intarray)))
1044    elif name == "max":
1045        return str(int(functools.reduce(max, intarray)))
1046    elif name == "max_hex":
1047        return hex(int(functools.reduce(max, intarray)))
1048    elif name == "min":
1049        return str(int(functools.reduce(min, intarray)))
1050    elif name == "min_hex":
1051        return hex(int(functools.reduce(min, intarray)))
1052    else:
1053        assert False
1054
1055
1056def inc_dec(kconf, name, *args):
1057    """
1058    Calculate the increment and the decrement of integer sequence.
1059    Returns a string that concatenates numbers with a comma as a separator.
1060    """
1061
1062    intarray = (int(val, base=0) for arg in args for val in arg.split(","))
1063
1064    if name == "inc":
1065        return ",".join(map(lambda a: str(a + 1), intarray))
1066    if name == "inc_hex":
1067        return ",".join(map(lambda a: hex(a + 1), intarray))
1068    elif name == "dec":
1069        return ",".join(map(lambda a: str(a - 1), intarray))
1070    elif name == "dec_hex":
1071        return ",".join(map(lambda a: hex(a - 1), intarray))
1072    else:
1073        assert False
1074
1075
1076# Keys in this dict are the function names as they appear
1077# in Kconfig files. The values are tuples in this form:
1078#
1079#       (python_function, minimum_number_of_args, maximum_number_of_args)
1080#
1081# Each python function is given a kconf object and its name in the
1082# Kconfig file, followed by arguments from the Kconfig file.
1083#
1084# See the kconfiglib documentation for more details.
1085functions = {
1086        "dt_has_compat": (dt_has_compat, 1, 1),
1087        "dt_compat_enabled": (dt_compat_enabled, 1, 1),
1088        "dt_compat_enabled_num": (dt_compat_enabled_num, 1, 1),
1089        "dt_compat_on_bus": (dt_compat_on_bus, 2, 2),
1090        "dt_compat_any_has_prop": (dt_compat_any_has_prop, 2, 3),
1091        "dt_compat_any_not_has_prop": (dt_compat_any_not_has_prop, 2, 2),
1092        "dt_chosen_label": (dt_chosen_label, 1, 1),
1093        "dt_chosen_enabled": (dt_chosen_enabled, 1, 1),
1094        "dt_chosen_path": (dt_chosen_path, 1, 1),
1095        "dt_chosen_has_compat": (dt_chosen_has_compat, 2, 2),
1096        "dt_path_enabled": (dt_node_enabled, 1, 1),
1097        "dt_alias_enabled": (dt_node_enabled, 1, 1),
1098        "dt_nodelabel_exists": (dt_nodelabel_exists, 1, 1),
1099        "dt_nodelabel_enabled": (dt_nodelabel_enabled, 1, 1),
1100        "dt_nodelabel_enabled_with_compat": (dt_nodelabel_enabled_with_compat, 2, 2),
1101        "dt_chosen_reg_addr_int": (dt_chosen_reg, 1, 3),
1102        "dt_chosen_reg_addr_hex": (dt_chosen_reg, 1, 3),
1103        "dt_chosen_reg_size_int": (dt_chosen_reg, 1, 3),
1104        "dt_chosen_reg_size_hex": (dt_chosen_reg, 1, 3),
1105        "dt_node_reg_addr_int": (dt_node_reg, 1, 3),
1106        "dt_node_reg_addr_hex": (dt_node_reg, 1, 3),
1107        "dt_node_reg_size_int": (dt_node_reg, 1, 3),
1108        "dt_node_reg_size_hex": (dt_node_reg, 1, 3),
1109        "dt_nodelabel_reg_addr_int": (dt_nodelabel_reg, 1, 3),
1110        "dt_nodelabel_reg_addr_hex": (dt_nodelabel_reg, 1, 3),
1111        "dt_nodelabel_reg_size_int": (dt_nodelabel_reg, 1, 3),
1112        "dt_nodelabel_reg_size_hex": (dt_nodelabel_reg, 1, 3),
1113        "dt_node_bool_prop": (dt_node_bool_prop, 2, 2),
1114        "dt_nodelabel_bool_prop": (dt_nodelabel_bool_prop, 2, 2),
1115        "dt_nodelabel_int_prop": (dt_nodelabel_int_prop, 2, 2),
1116        "dt_chosen_bool_prop": (dt_chosen_bool_prop, 2, 2),
1117        "dt_node_has_prop": (dt_node_has_prop, 2, 2),
1118        "dt_nodelabel_has_prop": (dt_nodelabel_has_prop, 2, 2),
1119        "dt_node_int_prop_int": (dt_node_int_prop, 2, 3),
1120        "dt_node_int_prop_hex": (dt_node_int_prop, 2, 3),
1121        "dt_node_array_prop_int": (dt_node_array_prop, 3, 4),
1122        "dt_node_array_prop_hex": (dt_node_array_prop, 3, 4),
1123        "dt_node_ph_array_prop_int": (dt_node_ph_array_prop, 4, 5),
1124        "dt_node_ph_array_prop_hex": (dt_node_ph_array_prop, 4, 5),
1125        "dt_node_ph_prop_path": (dt_node_ph_prop_path, 2, 2),
1126        "dt_node_str_prop_equals": (dt_node_str_prop_equals, 3, 3),
1127        "dt_nodelabel_has_compat": (dt_nodelabel_has_compat, 2, 2),
1128        "dt_node_has_compat": (dt_node_has_compat, 2, 2),
1129        "dt_nodelabel_path": (dt_nodelabel_path, 1, 1),
1130        "dt_node_parent": (dt_node_parent, 1, 1),
1131        "dt_nodelabel_array_prop_has_val": (dt_nodelabel_array_prop_has_val, 3, 3),
1132        "dt_gpio_hogs_enabled": (dt_gpio_hogs_enabled, 0, 0),
1133        "dt_chosen_partition_addr_int": (dt_chosen_partition_addr, 1, 3),
1134        "dt_chosen_partition_addr_hex": (dt_chosen_partition_addr, 1, 3),
1135        "normalize_upper": (normalize_upper, 1, 1),
1136        "shields_list_contains": (shields_list_contains, 1, 1),
1137        "substring": (substring, 2, 3),
1138        "add": (arith, 1, 255),
1139        "add_hex": (arith, 1, 255),
1140        "sub": (arith, 1, 255),
1141        "sub_hex": (arith, 1, 255),
1142        "mul": (arith, 1, 255),
1143        "mul_hex": (arith, 1, 255),
1144        "div": (arith, 1, 255),
1145        "div_hex": (arith, 1, 255),
1146        "mod": (arith, 1, 255),
1147        "mod_hex": (arith, 1, 255),
1148        "max": (arith, 1, 255),
1149        "max_hex": (arith, 1, 255),
1150        "min": (arith, 1, 255),
1151        "min_hex": (arith, 1, 255),
1152        "inc": (inc_dec, 1, 255),
1153        "inc_hex": (inc_dec, 1, 255),
1154        "dec": (inc_dec, 1, 255),
1155        "dec_hex": (inc_dec, 1, 255),
1156}
1157