1058 lines
34 KiB
Python
1058 lines
34 KiB
Python
# Copyright (c) 2018-2019 Linaro
|
|
# Copyright (c) 2019 Nordic Semiconductor ASA
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
import functools
|
|
import inspect
|
|
import operator
|
|
import os
|
|
import pickle
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ZEPHYR_BASE = str(Path(__file__).resolve().parents[2])
|
|
sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts", "dts",
|
|
"python-devicetree", "src"))
|
|
|
|
# Types we support
|
|
# 'string', 'int', 'hex', 'bool'
|
|
|
|
doc_mode = os.environ.get('KCONFIG_DOC_MODE') == "1"
|
|
|
|
if not doc_mode:
|
|
EDT_PICKLE = os.environ.get("EDT_PICKLE")
|
|
|
|
# The "if" handles a missing dts.
|
|
if EDT_PICKLE is not None and os.path.isfile(EDT_PICKLE):
|
|
with open(EDT_PICKLE, 'rb') as f:
|
|
edt = pickle.load(f)
|
|
edtlib = inspect.getmodule(edt)
|
|
else:
|
|
edt = None
|
|
edtlib = None
|
|
|
|
|
|
def _warn(kconf, msg):
|
|
print("{}:{}: WARNING: {}".format(kconf.filename, kconf.linenr, msg))
|
|
|
|
|
|
def _dt_units_to_scale(unit):
|
|
if not unit:
|
|
return 0
|
|
if unit in {'k', 'K'}:
|
|
return 10
|
|
if unit in {'m', 'M'}:
|
|
return 20
|
|
if unit in {'g', 'G'}:
|
|
return 30
|
|
if unit in {'kb', 'Kb'}:
|
|
return 13
|
|
if unit in {'mb', 'Mb'}:
|
|
return 23
|
|
if unit in {'gb', 'Gb'}:
|
|
return 33
|
|
|
|
|
|
def dt_chosen_label(kconf, _, chosen):
|
|
"""
|
|
This function takes a 'chosen' property and treats that property as a path
|
|
to an EDT node. If it finds an EDT node, it will look to see if that node
|
|
has a "label" property and return the value of that "label". If not, we
|
|
return the node's name in the devicetree.
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return ""
|
|
|
|
node = edt.chosen_node(chosen)
|
|
if not node:
|
|
return ""
|
|
|
|
if "label" not in node.props:
|
|
return node.name
|
|
|
|
return node.props["label"].val
|
|
|
|
|
|
def dt_chosen_enabled(kconf, _, chosen):
|
|
"""
|
|
This function returns "y" if /chosen contains a property named 'chosen'
|
|
that points to an enabled node, and "n" otherwise
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
node = edt.chosen_node(chosen)
|
|
return "y" if node and node.status == "okay" else "n"
|
|
|
|
|
|
def dt_chosen_path(kconf, _, chosen):
|
|
"""
|
|
This function takes a /chosen node property and returns the path
|
|
to the node in the property value, or the empty string.
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
node = edt.chosen_node(chosen)
|
|
|
|
return node.path if node else ""
|
|
|
|
def dt_chosen_has_compat(kconf, _, chosen, compat):
|
|
"""
|
|
This function takes a /chosen node property and returns 'y' if the
|
|
chosen node has the provided compatible string 'compat'
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
node = edt.chosen_node(chosen)
|
|
|
|
if node is None:
|
|
return "n"
|
|
|
|
if compat in node.compats:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
def dt_node_enabled(kconf, name, node):
|
|
"""
|
|
This function is used to test if a node is enabled (has status
|
|
'okay') or not.
|
|
|
|
The 'node' argument is a string which is either a path or an
|
|
alias, or both, depending on 'name'.
|
|
|
|
If 'name' is 'dt_path_enabled', 'node' is an alias or a path. If
|
|
'name' is 'dt_alias_enabled, 'node' is an alias.
|
|
"""
|
|
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
if name == "dt_alias_enabled":
|
|
if node.startswith("/"):
|
|
# EDT.get_node() works with either aliases or paths. If we
|
|
# are specifically being asked about an alias, reject paths.
|
|
return "n"
|
|
else:
|
|
# Make sure this is being called appropriately.
|
|
assert name == "dt_path_enabled"
|
|
|
|
try:
|
|
node = edt.get_node(node)
|
|
except edtlib.EDTError:
|
|
return "n"
|
|
|
|
return "y" if node and node.status == "okay" else "n"
|
|
|
|
|
|
def dt_nodelabel_enabled(kconf, _, label):
|
|
"""
|
|
This function is like dt_node_enabled(), but the 'label' argument
|
|
should be a node label, like "foo" is here:
|
|
|
|
foo: some-node { ... };
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
node = edt.label2node.get(label)
|
|
|
|
return "y" if node and node.status == "okay" else "n"
|
|
|
|
|
|
def _node_reg_addr(node, index, unit):
|
|
if not node:
|
|
return 0
|
|
|
|
if not node.regs:
|
|
return 0
|
|
|
|
if int(index) >= len(node.regs):
|
|
return 0
|
|
|
|
if node.regs[int(index)].addr is None:
|
|
return 0
|
|
|
|
return node.regs[int(index)].addr >> _dt_units_to_scale(unit)
|
|
|
|
|
|
def _node_reg_size(node, index, unit):
|
|
if not node:
|
|
return 0
|
|
|
|
if not node.regs:
|
|
return 0
|
|
|
|
if int(index) >= len(node.regs):
|
|
return 0
|
|
|
|
if node.regs[int(index)].size is None:
|
|
return 0
|
|
|
|
return node.regs[int(index)].size >> _dt_units_to_scale(unit)
|
|
|
|
|
|
def _node_int_prop(node, prop, unit=None):
|
|
"""
|
|
This function takes a 'node' and will look to see if that 'node' has a
|
|
property called 'prop' and if that 'prop' is an integer type will return
|
|
the value of the property 'prop' as either a string int or string hex
|
|
value, if not we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
'kb' or 'Kb' divide by 8192 (1 << 13)
|
|
'mb' or 'Mb' divide by 8,388,608 (1 << 23)
|
|
'gb' or 'Gb' divide by 8,589,934,592 (1 << 33)
|
|
"""
|
|
if not node:
|
|
return 0
|
|
|
|
if prop not in node.props:
|
|
return 0
|
|
|
|
if node.props[prop].type != "int":
|
|
return 0
|
|
|
|
return node.props[prop].val >> _dt_units_to_scale(unit)
|
|
|
|
|
|
def _node_array_prop(node, prop, index=0, unit=None):
|
|
"""
|
|
This function takes a 'node' and will look to see if that 'node' has a
|
|
property called 'prop' and if that 'prop' is an array type will return
|
|
the value of the property 'prop' at the given 'index' as either a string int
|
|
or string hex value. If the property 'prop' is not found or the given 'index'
|
|
is out of range it will return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
"""
|
|
if not node:
|
|
return 0
|
|
|
|
if prop not in node.props:
|
|
return 0
|
|
if node.props[prop].type != "array":
|
|
return 0
|
|
if int(index) >= len(node.props[prop].val):
|
|
return 0
|
|
return node.props[prop].val[int(index)] >> _dt_units_to_scale(unit)
|
|
|
|
def _node_ph_array_prop(node, prop, index, cell, unit=None):
|
|
"""
|
|
This function takes a 'node', a property name ('prop'), index ('index') and
|
|
a cell ('cell') and it will look to see if that node has a property
|
|
called 'prop' and if that 'prop' is an phandle-array type.
|
|
Then it will check if that phandle array has a cell matching the given index
|
|
and then return the value of the cell named 'cell' in this array index.
|
|
If not found it will return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
"""
|
|
if not node:
|
|
return 0
|
|
|
|
if prop not in node.props:
|
|
return 0
|
|
if node.props[prop].type != "phandle-array":
|
|
return 0
|
|
if int(index) >= len(node.props[prop].val):
|
|
return 0
|
|
if cell not in node.props[prop].val[int(index)].data.keys():
|
|
return 0
|
|
return node.props[prop].val[int(index)].data[cell] >> _dt_units_to_scale(unit)
|
|
|
|
def _dt_chosen_reg_addr(kconf, chosen, index=0, unit=None):
|
|
"""
|
|
This function takes a 'chosen' property and treats that property as a path
|
|
to an EDT node. If it finds an EDT node, it will look to see if that
|
|
node has a register at the given 'index' and return the address value of
|
|
that reg, if not we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
'kb' or 'Kb' divide by 8192 (1 << 13)
|
|
'mb' or 'Mb' divide by 8,388,608 (1 << 23)
|
|
'gb' or 'Gb' divide by 8,589,934,592 (1 << 33)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return 0
|
|
|
|
node = edt.chosen_node(chosen)
|
|
|
|
return _node_reg_addr(node, index, unit)
|
|
|
|
|
|
def _dt_chosen_reg_size(kconf, chosen, index=0, unit=None):
|
|
"""
|
|
This function takes a 'chosen' property and treats that property as a path
|
|
to an EDT node. If it finds an EDT node, it will look to see if that node
|
|
has a register at the given 'index' and return the size value of that reg,
|
|
if not we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
'kb' or 'Kb' divide by 8192 (1 << 13)
|
|
'mb' or 'Mb' divide by 8,388,608 (1 << 23)
|
|
'gb' or 'Gb' divide by 8,589,934,592 (1 << 33)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return 0
|
|
|
|
node = edt.chosen_node(chosen)
|
|
|
|
return _node_reg_size(node, index, unit)
|
|
|
|
|
|
def dt_chosen_reg(kconf, name, chosen, index=0, unit=None):
|
|
"""
|
|
This function just routes to the proper function and converts
|
|
the result to either a string int or string hex value.
|
|
"""
|
|
if name == "dt_chosen_reg_size_int":
|
|
return str(_dt_chosen_reg_size(kconf, chosen, index, unit))
|
|
if name == "dt_chosen_reg_size_hex":
|
|
return hex(_dt_chosen_reg_size(kconf, chosen, index, unit))
|
|
if name == "dt_chosen_reg_addr_int":
|
|
return str(_dt_chosen_reg_addr(kconf, chosen, index, unit))
|
|
if name == "dt_chosen_reg_addr_hex":
|
|
return hex(_dt_chosen_reg_addr(kconf, chosen, index, unit))
|
|
|
|
|
|
def _dt_chosen_partition_addr(kconf, chosen, index=0, unit=None):
|
|
"""
|
|
This function takes a 'chosen' property and treats that property as a path
|
|
to an EDT node. If it finds an EDT node, it will look to see if that
|
|
node has a register, and if that node has a grandparent that has a register
|
|
at the given 'index'. The addition of both addresses will be returned, if
|
|
not, we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
'kb' or 'Kb' divide by 8192 (1 << 13)
|
|
'mb' or 'Mb' divide by 8,388,608 (1 << 23)
|
|
'gb' or 'Gb' divide by 8,589,934,592 (1 << 33)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return 0
|
|
|
|
node = edt.chosen_node(chosen)
|
|
if not node:
|
|
return 0
|
|
|
|
p_node = node.parent
|
|
if not p_node:
|
|
return 0
|
|
|
|
return _node_reg_addr(p_node.parent, index, unit) + _node_reg_addr(node, 0, unit)
|
|
|
|
|
|
def dt_chosen_partition_addr(kconf, name, chosen, index=0, unit=None):
|
|
"""
|
|
This function just routes to the proper function and converts
|
|
the result to either a string int or string hex value.
|
|
"""
|
|
if name == "dt_chosen_partition_addr_int":
|
|
return str(_dt_chosen_partition_addr(kconf, chosen, index, unit))
|
|
if name == "dt_chosen_partition_addr_hex":
|
|
return hex(_dt_chosen_partition_addr(kconf, chosen, index, unit))
|
|
|
|
|
|
def _dt_node_reg_addr(kconf, path, index=0, unit=None):
|
|
"""
|
|
This function takes a 'path' and looks for an EDT node at that path. If it
|
|
finds an EDT node, it will look to see if that node has a register at the
|
|
given 'index' and return the address value of that reg, if not we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
'kb' or 'Kb' divide by 8192 (1 << 13)
|
|
'mb' or 'Mb' divide by 8,388,608 (1 << 23)
|
|
'gb' or 'Gb' divide by 8,589,934,592 (1 << 33)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return 0
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return 0
|
|
|
|
return _node_reg_addr(node, index, unit)
|
|
|
|
|
|
def _dt_node_reg_size(kconf, path, index=0, unit=None):
|
|
"""
|
|
This function takes a 'path' and looks for an EDT node at that path. If it
|
|
finds an EDT node, it will look to see if that node has a register at the
|
|
given 'index' and return the size value of that reg, if not we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
'kb' or 'Kb' divide by 8192 (1 << 13)
|
|
'mb' or 'Mb' divide by 8,388,608 (1 << 23)
|
|
'gb' or 'Gb' divide by 8,589,934,592 (1 << 33)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return 0
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return 0
|
|
|
|
return _node_reg_size(node, index, unit)
|
|
|
|
|
|
def dt_node_reg(kconf, name, path, index=0, unit=None):
|
|
"""
|
|
This function just routes to the proper function and converts
|
|
the result to either a string int or string hex value.
|
|
"""
|
|
if name == "dt_node_reg_size_int":
|
|
return str(_dt_node_reg_size(kconf, path, index, unit))
|
|
if name == "dt_node_reg_size_hex":
|
|
return hex(_dt_node_reg_size(kconf, path, index, unit))
|
|
if name == "dt_node_reg_addr_int":
|
|
return str(_dt_node_reg_addr(kconf, path, index, unit))
|
|
if name == "dt_node_reg_addr_hex":
|
|
return hex(_dt_node_reg_addr(kconf, path, index, unit))
|
|
|
|
def dt_nodelabel_reg(kconf, name, label, index=0, unit=None):
|
|
"""
|
|
This function is like dt_node_reg(), but the 'label' argument
|
|
should be a node label, like "foo" is here:
|
|
|
|
foo: some-node { ... };
|
|
"""
|
|
if doc_mode or edt is None:
|
|
node = None
|
|
else:
|
|
node = edt.label2node.get(label)
|
|
|
|
if name == "dt_nodelabel_reg_size_int":
|
|
return str(_dt_node_reg_size(kconf, node.path, index, unit)) if node else "0"
|
|
if name == "dt_nodelabel_reg_size_hex":
|
|
return hex(_dt_node_reg_size(kconf, node.path, index, unit)) if node else "0x0"
|
|
if name == "dt_nodelabel_reg_addr_int":
|
|
return str(_dt_node_reg_addr(kconf, node.path, index, unit)) if node else "0"
|
|
if name == "dt_nodelabel_reg_addr_hex":
|
|
return hex(_dt_node_reg_addr(kconf, node.path, index, unit)) if node else "0x0"
|
|
|
|
|
|
def _dt_node_bool_prop_generic(node_search_function, search_arg, prop):
|
|
"""
|
|
This function takes the 'node_search_function' and uses it to search for
|
|
a node with 'search_arg' and if node exists, checks if 'prop' exists
|
|
inside the node and is a boolean, if it is true, returns "y".
|
|
Otherwise, it returns "n".
|
|
"""
|
|
try:
|
|
node = node_search_function(search_arg)
|
|
except edtlib.EDTError:
|
|
return "n"
|
|
|
|
if node is None:
|
|
return "n"
|
|
|
|
if prop not in node.props:
|
|
return "n"
|
|
|
|
if node.props[prop].type != "boolean":
|
|
return "n"
|
|
|
|
if node.props[prop].val:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
def dt_node_bool_prop(kconf, _, path, prop):
|
|
"""
|
|
This function takes a 'path' and looks for an EDT node at that path. If it
|
|
finds an EDT node, it will look to see if that node has a boolean property
|
|
by the name of 'prop'. If the 'prop' exists it will return "y" otherwise
|
|
we return "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
return _dt_node_bool_prop_generic(edt.get_node, path, prop)
|
|
|
|
def dt_nodelabel_bool_prop(kconf, _, label, prop):
|
|
"""
|
|
This function takes a 'label' and looks for an EDT node with that label.
|
|
If it finds an EDT node, it will look to see if that node has a boolean
|
|
property by the name of 'prop'. If the 'prop' exists it will return "y"
|
|
otherwise we return "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
return _dt_node_bool_prop_generic(edt.label2node.get, label, prop)
|
|
|
|
def dt_chosen_bool_prop(kconf, _, chosen, prop):
|
|
"""
|
|
This function takes a /chosen node property named 'chosen', and
|
|
looks for the chosen node. If that node exists and has a boolean
|
|
property 'prop', it returns "y". Otherwise, it returns "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
return _dt_node_bool_prop_generic(edt.chosen_node, chosen, prop)
|
|
|
|
def _dt_node_has_prop_generic(node_search_function, search_arg, prop):
|
|
"""
|
|
This function takes the 'node_search_function' and uses it to search for
|
|
a node with 'search_arg' and if node exists, then checks if 'prop'
|
|
exists inside the node and returns "y". Otherwise, it returns "n".
|
|
"""
|
|
try:
|
|
node = node_search_function(search_arg)
|
|
except edtlib.EDTError:
|
|
return "n"
|
|
|
|
if node is None:
|
|
return "n"
|
|
|
|
if prop in node.props:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
def dt_node_has_prop(kconf, _, path, prop):
|
|
"""
|
|
This function takes a 'path' and looks for an EDT node at that path. If it
|
|
finds an EDT node, it will look to see if that node has a property
|
|
by the name of 'prop'. If the 'prop' exists it will return "y" otherwise
|
|
it returns "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
return _dt_node_has_prop_generic(edt.get_node, path, prop)
|
|
|
|
def dt_nodelabel_has_prop(kconf, _, label, prop):
|
|
"""
|
|
This function takes a 'label' and looks for an EDT node with that label.
|
|
If it finds an EDT node, it will look to see if that node has a property
|
|
by the name of 'prop'. If the 'prop' exists it will return "y" otherwise
|
|
it returns "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
return _dt_node_has_prop_generic(edt.label2node.get, label, prop)
|
|
|
|
def dt_node_int_prop(kconf, name, path, prop, unit=None):
|
|
"""
|
|
This function takes a 'path' and property name ('prop') looks for an EDT
|
|
node at that path. If it finds an EDT node, it will look to see if that
|
|
node has a property called 'prop' and if that 'prop' is an integer type
|
|
will return the value of the property 'prop' as either a string int or
|
|
string hex value, if not we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
'kb' or 'Kb' divide by 8192 (1 << 13)
|
|
'mb' or 'Mb' divide by 8,388,608 (1 << 23)
|
|
'gb' or 'Gb' divide by 8,589,934,592 (1 << 33)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "0"
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return "0"
|
|
|
|
if name == "dt_node_int_prop_int":
|
|
return str(_node_int_prop(node, prop, unit))
|
|
if name == "dt_node_int_prop_hex":
|
|
return hex(_node_int_prop(node, prop, unit))
|
|
|
|
|
|
def dt_node_array_prop(kconf, name, path, prop, index, unit=None):
|
|
"""
|
|
This function takes a 'path', property name ('prop') and index ('index')
|
|
and looks for an EDT node at that path. If it finds an EDT node, it will
|
|
look to see if that node has a property called 'prop' and if that 'prop'
|
|
is an array type will return the value of the property 'prop' at the given
|
|
'index' as either a string int or string hex value. If not found we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "0"
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return "0"
|
|
if name == "dt_node_array_prop_int":
|
|
return str(_node_array_prop(node, prop, index, unit))
|
|
if name == "dt_node_array_prop_hex":
|
|
return hex(_node_array_prop(node, prop, index, unit))
|
|
|
|
|
|
def dt_node_ph_array_prop(kconf, name, path, prop, index, cell, unit=None):
|
|
"""
|
|
This function takes a 'path', property name ('prop'), index ('index') and
|
|
a cell ('cell') and looks for an EDT node at that path.
|
|
If it finds an EDT node, it will look to see if that node has a property
|
|
called 'prop' and if that 'prop' is an phandle-array type.
|
|
Then it will check if that phandle array has a cell matching the given index
|
|
and ten return the value of the cell named 'cell' in this array index as
|
|
either a string int or string hex value. If not found we return 0.
|
|
|
|
The function will divide the value based on 'unit':
|
|
None No division
|
|
'k' or 'K' divide by 1024 (1 << 10)
|
|
'm' or 'M' divide by 1,048,576 (1 << 20)
|
|
'g' or 'G' divide by 1,073,741,824 (1 << 30)
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "0"
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return "0"
|
|
if name == "dt_node_ph_array_prop_int":
|
|
return str(_node_ph_array_prop(node, prop, index, cell, unit))
|
|
if name == "dt_node_ph_array_prop_hex":
|
|
return hex(_node_ph_array_prop(node, prop, index, cell, unit))
|
|
|
|
def dt_node_ph_prop_path(kconf, name, path, prop):
|
|
"""
|
|
This function takes a 'path' and a property name ('prop') and
|
|
looks for an EDT node at that path. If it finds an EDT node,
|
|
it will look to see if that node has a property called 'prop'
|
|
and if that 'prop' is an phandle type. Then it will return the
|
|
path to the pointed-to node, or an empty string if there is
|
|
no such node.
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return ""
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return ""
|
|
|
|
if prop not in node.props:
|
|
return ""
|
|
if node.props[prop].type != "phandle":
|
|
return ""
|
|
|
|
phandle = node.props[prop].val
|
|
|
|
return phandle.path if phandle else ""
|
|
|
|
def dt_node_str_prop_equals(kconf, _, path, prop, val):
|
|
"""
|
|
This function takes a 'path' and property name ('prop') looks for an EDT
|
|
node at that path. If it finds an EDT node, it will look to see if that
|
|
node has a property 'prop' of type string. If that 'prop' is equal to 'val'
|
|
it will return "y" otherwise return "n".
|
|
"""
|
|
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return "n"
|
|
|
|
if prop not in node.props:
|
|
return "n"
|
|
|
|
if node.props[prop].type != "string":
|
|
return "n"
|
|
|
|
if node.props[prop].val == val:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
|
|
def dt_has_compat(kconf, _, compat):
|
|
"""
|
|
This function takes a 'compat' and returns "y" if any compatible node
|
|
can be found in the EDT, otherwise it returns "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
return "y" if compat in edt.compat2nodes else "n"
|
|
|
|
|
|
def dt_compat_enabled(kconf, _, compat):
|
|
"""
|
|
This function takes a 'compat' and returns "y" if we find a status "okay"
|
|
compatible node in the EDT otherwise we return "n"
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
return "y" if compat in edt.compat2okay else "n"
|
|
|
|
|
|
def dt_compat_on_bus(kconf, _, compat, bus):
|
|
"""
|
|
This function takes a 'compat' and returns "y" if we find an "enabled"
|
|
compatible node in the EDT which is on bus 'bus'. It returns "n" otherwise.
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
if compat in edt.compat2okay:
|
|
for node in edt.compat2okay[compat]:
|
|
if node.on_buses is not None and bus in node.on_buses:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
def dt_compat_any_has_prop(kconf, _, compat, prop):
|
|
"""
|
|
This function takes a 'compat' and a 'prop' and returns "y" if any
|
|
node with compatible 'compat' also has a valid property 'prop'.
|
|
It returns "n" otherwise.
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
if compat in edt.compat2okay:
|
|
for node in edt.compat2okay[compat]:
|
|
if prop in node.props:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
def dt_nodelabel_has_compat(kconf, _, label, compat):
|
|
"""
|
|
This function takes a 'label' and looks for an EDT node with that label.
|
|
If it finds such node, it returns "y" if this node is compatible with
|
|
the provided 'compat'. Otherwise, it return "n" .
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
node = edt.label2node.get(label)
|
|
|
|
if node and compat in node.compats:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
def dt_node_has_compat(kconf, _, path, compat):
|
|
"""
|
|
This function takes a 'path' and looks for an EDT node at that path. If it
|
|
finds an EDT node, it returns "y" if this node is compatible with
|
|
the provided 'compat'. Otherwise, it return "n" .
|
|
"""
|
|
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return "n"
|
|
|
|
if node and compat in node.compats:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
def dt_nodelabel_enabled_with_compat(kconf, _, label, compat):
|
|
"""
|
|
This function takes a 'label' and returns "y" if an "enabled" node with
|
|
such label can be found in the EDT and that node is compatible with the
|
|
provided 'compat', otherwise it returns "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
if compat in edt.compat2okay:
|
|
for node in edt.compat2okay[compat]:
|
|
if label in node.labels:
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
|
|
def dt_nodelabel_array_prop_has_val(kconf, _, label, prop, val):
|
|
"""
|
|
This function looks for a node with node label 'label'.
|
|
If the node exists, it checks if the node node has a property
|
|
'prop' with type "array". If so, and the property contains
|
|
an element equal to the integer 'val', it returns "y".
|
|
Otherwise, it returns "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
node = edt.label2node.get(label)
|
|
|
|
if not node or (prop not in node.props) or (node.props[prop].type != "array"):
|
|
return "n"
|
|
else:
|
|
return "y" if int(val, base=0) in node.props[prop].val else "n"
|
|
|
|
|
|
def dt_nodelabel_path(kconf, _, label):
|
|
"""
|
|
This function takes a node label (not a label property) and
|
|
returns the path to the node which has that label, or an empty
|
|
string if there is no such node.
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return ""
|
|
|
|
node = edt.label2node.get(label)
|
|
|
|
return node.path if node else ""
|
|
|
|
def dt_node_parent(kconf, _, path):
|
|
"""
|
|
This function takes a 'path' and looks for an EDT node at that path. If it
|
|
finds an EDT node, it will look for the parent of that node. If the parent
|
|
exists, it will return the path to that parent. Otherwise, an empty string
|
|
will be returned.
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return ""
|
|
|
|
try:
|
|
node = edt.get_node(path)
|
|
except edtlib.EDTError:
|
|
return ""
|
|
|
|
if node is None:
|
|
return ""
|
|
|
|
return node.parent.path if node.parent else ""
|
|
|
|
def dt_gpio_hogs_enabled(kconf, _):
|
|
"""
|
|
Return "y" if any GPIO hog node is enabled. Otherwise, return "n".
|
|
"""
|
|
if doc_mode or edt is None:
|
|
return "n"
|
|
|
|
for node in edt.nodes:
|
|
if node.gpio_hogs and node.status == "okay":
|
|
return "y"
|
|
|
|
return "n"
|
|
|
|
|
|
def normalize_upper(kconf, _, string):
|
|
"""
|
|
Normalize the string, so that the string only contains alpha-numeric
|
|
characters or underscores. All non-alpha-numeric characters are replaced
|
|
with an underscore, '_'.
|
|
When string has been normalized it will be converted into upper case.
|
|
"""
|
|
return re.sub(r'[^a-zA-Z0-9_]', '_', string).upper()
|
|
|
|
|
|
def shields_list_contains(kconf, _, shield):
|
|
"""
|
|
Return "n" if cmake environment variable 'SHIELD_AS_LIST' doesn't exist.
|
|
Return "y" if 'shield' is present list obtained after 'SHIELD_AS_LIST'
|
|
has been split using ";" as a separator and "n" otherwise.
|
|
"""
|
|
try:
|
|
list = os.environ['SHIELD_AS_LIST']
|
|
except KeyError:
|
|
return "n"
|
|
|
|
return "y" if shield in list.split(";") else "n"
|
|
|
|
|
|
def substring(kconf, _, string, start, stop=None):
|
|
"""
|
|
Extracts a portion of the string, removing characters from the front, back or both.
|
|
"""
|
|
if stop is not None:
|
|
return string[int(start):int(stop)]
|
|
else:
|
|
return string[int(start):]
|
|
|
|
def arith(kconf, name, *args):
|
|
"""
|
|
The arithmetic operations on integers.
|
|
If three or more arguments are given, it returns the result of performing
|
|
the operation on the first two arguments and operates the same operation as
|
|
the result and the following argument.
|
|
For interoperability with inc and dec,
|
|
if there is only one argument, it will be split with a comma and processed
|
|
as a sequence of numbers.
|
|
|
|
Examples in Kconfig:
|
|
|
|
$(add, 10, 3) # -> 13
|
|
$(add, 10, 3, 2) # -> 15
|
|
$(sub, 10, 3) # -> 7
|
|
$(sub, 10, 3, 2) # -> 5
|
|
$(mul, 10, 3) # -> 30
|
|
$(mul, 10, 3, 2) # -> 60
|
|
$(div, 10, 3) # -> 3
|
|
$(div, 10, 3, 2) # -> 1
|
|
$(mod, 10, 3) # -> 1
|
|
$(mod, 10, 3, 2) # -> 1
|
|
$(inc, 1) # -> 2
|
|
$(inc, 1, 1) # -> "2,2"
|
|
$(inc, $(inc, 1, 1)) # -> "3,3"
|
|
$(dec, 1) # -> 0
|
|
$(dec, 1, 1) # -> "0,0"
|
|
$(dec, $(dec, 1, 1)) # -> "-1,-1"
|
|
$(add, $(inc, 1, 1)) # -> 4
|
|
$(div, $(dec, 1, 1)) # Error (0 div 0)
|
|
"""
|
|
|
|
intarray = map(int, args if len(args) > 1 else args[0].split(","))
|
|
|
|
if name == "add":
|
|
return str(int(functools.reduce(operator.add, intarray)))
|
|
elif name == "sub":
|
|
return str(int(functools.reduce(operator.sub, intarray)))
|
|
elif name == "mul":
|
|
return str(int(functools.reduce(operator.mul, intarray)))
|
|
elif name == "div":
|
|
return str(int(functools.reduce(operator.truediv, intarray)))
|
|
elif name == "mod":
|
|
return str(int(functools.reduce(operator.mod, intarray)))
|
|
elif name == "max":
|
|
return str(int(functools.reduce(max, intarray)))
|
|
elif name == "min":
|
|
return str(int(functools.reduce(min, intarray)))
|
|
else:
|
|
assert False
|
|
|
|
|
|
def inc_dec(kconf, name, *args):
|
|
"""
|
|
Calculate the increment and the decrement of integer sequence.
|
|
Returns a string that concatenates numbers with a comma as a separator.
|
|
"""
|
|
|
|
intarray = map(int, args if len(args) > 1 else args[0].split(","))
|
|
|
|
if name == "inc":
|
|
return ",".join(map(lambda a: str(a + 1), intarray))
|
|
elif name == "dec":
|
|
return ",".join(map(lambda a: str(a - 1), intarray))
|
|
else:
|
|
assert False
|
|
|
|
|
|
# Keys in this dict are the function names as they appear
|
|
# in Kconfig files. The values are tuples in this form:
|
|
#
|
|
# (python_function, minimum_number_of_args, maximum_number_of_args)
|
|
#
|
|
# Each python function is given a kconf object and its name in the
|
|
# Kconfig file, followed by arguments from the Kconfig file.
|
|
#
|
|
# See the kconfiglib documentation for more details.
|
|
functions = {
|
|
"dt_has_compat": (dt_has_compat, 1, 1),
|
|
"dt_compat_enabled": (dt_compat_enabled, 1, 1),
|
|
"dt_compat_on_bus": (dt_compat_on_bus, 2, 2),
|
|
"dt_compat_any_has_prop": (dt_compat_any_has_prop, 2, 2),
|
|
"dt_chosen_label": (dt_chosen_label, 1, 1),
|
|
"dt_chosen_enabled": (dt_chosen_enabled, 1, 1),
|
|
"dt_chosen_path": (dt_chosen_path, 1, 1),
|
|
"dt_chosen_has_compat": (dt_chosen_has_compat, 2, 2),
|
|
"dt_path_enabled": (dt_node_enabled, 1, 1),
|
|
"dt_alias_enabled": (dt_node_enabled, 1, 1),
|
|
"dt_nodelabel_enabled": (dt_nodelabel_enabled, 1, 1),
|
|
"dt_nodelabel_enabled_with_compat": (dt_nodelabel_enabled_with_compat, 2, 2),
|
|
"dt_chosen_reg_addr_int": (dt_chosen_reg, 1, 3),
|
|
"dt_chosen_reg_addr_hex": (dt_chosen_reg, 1, 3),
|
|
"dt_chosen_reg_size_int": (dt_chosen_reg, 1, 3),
|
|
"dt_chosen_reg_size_hex": (dt_chosen_reg, 1, 3),
|
|
"dt_node_reg_addr_int": (dt_node_reg, 1, 3),
|
|
"dt_node_reg_addr_hex": (dt_node_reg, 1, 3),
|
|
"dt_node_reg_size_int": (dt_node_reg, 1, 3),
|
|
"dt_node_reg_size_hex": (dt_node_reg, 1, 3),
|
|
"dt_nodelabel_reg_addr_int": (dt_nodelabel_reg, 1, 3),
|
|
"dt_nodelabel_reg_addr_hex": (dt_nodelabel_reg, 1, 3),
|
|
"dt_nodelabel_reg_size_int": (dt_nodelabel_reg, 1, 3),
|
|
"dt_nodelabel_reg_size_hex": (dt_nodelabel_reg, 1, 3),
|
|
"dt_node_bool_prop": (dt_node_bool_prop, 2, 2),
|
|
"dt_nodelabel_bool_prop": (dt_nodelabel_bool_prop, 2, 2),
|
|
"dt_chosen_bool_prop": (dt_chosen_bool_prop, 2, 2),
|
|
"dt_node_has_prop": (dt_node_has_prop, 2, 2),
|
|
"dt_nodelabel_has_prop": (dt_nodelabel_has_prop, 2, 2),
|
|
"dt_node_int_prop_int": (dt_node_int_prop, 2, 3),
|
|
"dt_node_int_prop_hex": (dt_node_int_prop, 2, 3),
|
|
"dt_node_array_prop_int": (dt_node_array_prop, 3, 4),
|
|
"dt_node_array_prop_hex": (dt_node_array_prop, 3, 4),
|
|
"dt_node_ph_array_prop_int": (dt_node_ph_array_prop, 4, 5),
|
|
"dt_node_ph_array_prop_hex": (dt_node_ph_array_prop, 4, 5),
|
|
"dt_node_ph_prop_path": (dt_node_ph_prop_path, 2, 2),
|
|
"dt_node_str_prop_equals": (dt_node_str_prop_equals, 3, 3),
|
|
"dt_nodelabel_has_compat": (dt_nodelabel_has_compat, 2, 2),
|
|
"dt_node_has_compat": (dt_node_has_compat, 2, 2),
|
|
"dt_nodelabel_path": (dt_nodelabel_path, 1, 1),
|
|
"dt_node_parent": (dt_node_parent, 1, 1),
|
|
"dt_nodelabel_array_prop_has_val": (dt_nodelabel_array_prop_has_val, 3, 3),
|
|
"dt_gpio_hogs_enabled": (dt_gpio_hogs_enabled, 0, 0),
|
|
"dt_chosen_partition_addr_int": (dt_chosen_partition_addr, 1, 3),
|
|
"dt_chosen_partition_addr_hex": (dt_chosen_partition_addr, 1, 3),
|
|
"normalize_upper": (normalize_upper, 1, 1),
|
|
"shields_list_contains": (shields_list_contains, 1, 1),
|
|
"substring": (substring, 2, 3),
|
|
"add": (arith, 1, 255),
|
|
"sub": (arith, 1, 255),
|
|
"mul": (arith, 1, 255),
|
|
"div": (arith, 1, 255),
|
|
"mod": (arith, 1, 255),
|
|
"max": (arith, 1, 255),
|
|
"min": (arith, 1, 255),
|
|
"inc": (inc_dec, 1, 255),
|
|
"dec": (inc_dec, 1, 255),
|
|
}
|