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