kconfig: Add new functions to kconfigfunctions to use EDT

Add a new set of functions that utilize EDT so we can move away from the
generated .conf file.

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
This commit is contained in:
Kumar Gala 2019-08-28 09:30:23 -05:00 committed by Kumar Gala
commit 5735397b9b
4 changed files with 234 additions and 38 deletions

View file

@ -14,6 +14,7 @@ file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include/generated)
# See ~/zephyr/doc/dts
set(GENERATED_DTS_BOARD_UNFIXED_H ${PROJECT_BINARY_DIR}/include/generated/generated_dts_board_unfixed.h)
set(GENERATED_DTS_BOARD_CONF ${PROJECT_BINARY_DIR}/include/generated/generated_dts_board.conf)
set(DTS_POST_CPP ${PROJECT_BINARY_DIR}/${BOARD}.dts.pre.tmp)
set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts)
set_ifndef(DTS_COMMON_OVERLAYS ${ZEPHYR_BASE}/dts/common/common.dts)

View file

@ -39,6 +39,8 @@ set(ENV{SOC_DIR} ${SOC_DIR})
set(ENV{CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR})
set(ENV{ARCH_DIR} ${ARCH_DIR})
set(ENV{GENERATED_DTS_BOARD_CONF} ${GENERATED_DTS_BOARD_CONF})
set(ENV{DTS_POST_CPP} ${DTS_POST_CPP})
set(ENV{DTS_ROOT_BINDINGS} ${DTS_ROOT_BINDINGS})
# Allow out-of-tree users to add their own Kconfig python frontend
# targets by appending targets to the CMake list
@ -77,6 +79,8 @@ foreach(kconfig_target
ZEPHYR_TOOLCHAIN_VARIANT=${ZEPHYR_TOOLCHAIN_VARIANT}
ARCH_DIR=$ENV{ARCH_DIR}
GENERATED_DTS_BOARD_CONF=${GENERATED_DTS_BOARD_CONF}
DTS_POST_CPP=${DTS_POST_CPP}
DTS_ROOT_BINDINGS=${DTS_ROOT_BINDINGS}
${PYTHON_EXECUTABLE}
${EXTRA_KCONFIG_TARGET_COMMAND_FOR_${kconfig_target}}
${KCONFIG_ROOT}

View file

@ -815,62 +815,52 @@ from the device tree.
Device Tree Related Functions
=============================
See the Python docstrings in ``scripts/kconfig/kconfigfunctions.py`` for more
details on the functions.
.. code-block:: none
dt_int_val(kconf, _, name, unit):
This function looks up 'name' in the DTS generated "conf" style database
(generated_dts_board.conf in <build_dir>/zephyr/include/generated/)
and if it's found it will return the value as an decimal integer. 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)
dt_hex_val(kconf, _, name, unit):
This function looks up 'name' in the DTS generated "conf" style database
(generated_dts_board.conf in <build_dir>/zephyr/include/generated/)
and if it's found it will return the value as an hex integer. 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)
dt_str_val(kconf, _, name):
This function looks up 'name' in the DTS generated "conf" style database
(generated_dts_board.conf in <build_dir>/zephyr/include/generated/)
and if it's found it will return the value as string. if it's not found we
return an empty string.
dt_chosen_reg_addr(kconf, _, chosen, index=0, unit=None):
dt_chosen_reg_size(kconf, _, chosen, index=0, unit=None):
dt_node_reg_addr(kconf, _, path, index=0, unit=None):
dt_node_reg_size(kconf, _, path, index=0, unit=None):
dt_compat_enabled(kconf, _, compat):
dt_node_has_bool_prop(kconf, _, path, prop):
Example Usage
=============
-------------
The following example shows the usage of the ``dt_int_val`` function:
The following example shows the usage of the ``dt_node_reg_addr`` function.
This function will take a path to a device tree node and register the register
address of that node:
.. code-block:: none
boards/arm/mimxrt1020_evk/Kconfig.defconfig
boards/riscv/hifive1_revb/Kconfig.defconfig
config FLASH_SIZE
default $(dt_int_val,DT_NXP_IMX_FLEXSPI_402A8000_SIZE_1,K)
config FLASH_BASE_ADDRESS
default $(dt_node_reg_addr,/soc/spi@10014000,1)
In this example if we examine the generated generated_dts_board.conf file
as part of the Zephyr build we'd find the following entry:
In this example if we examine the dts file for the board:
.. code-block:: none
DT_NXP_IMX_FLEXSPI_402A8000_SIZE_1=8388608
spi0: spi@10014000 {
compatible = "sifive,spi0";
reg = <0x10014000 0x1000 0x20010000 0x3c0900>;
reg-names = "control", "mem";
...
};
The ``dt_int_val`` will search the generated_dts_board.conf that is derived from
the dts for the board and match the ``DT_NXP_IMX_FLEXSPI_402A8000_SIZE_1`` entry.
The function than will than scale the value by ``1024``. This effective causes
The ``dt_node_reg_addr`` will search the dts file for a node at the path
``/soc/spi@10014000``. The function than will extract the register address
at the index 1. This effective gets the value of ``0x20010000`` and causes
the above to look like:
.. code-block:: none
config FLASH_SIZE
default 8192
config FLASH_BASE_ADDRESS
default 0x20010000
Other resources

View file

@ -5,6 +5,12 @@
# SPDX-License-Identifier: Apache-2.0
import os
import sys
ZEPHYR_BASE = os.environ.get("ZEPHYR_BASE")
sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/dts"))
import edtlib
# Types we support
# 'string', 'int', 'hex', 'bool'
@ -13,6 +19,15 @@ doc_mode = os.environ.get('KCONFIG_DOC_MODE') == "1"
dt_defines = {}
if not doc_mode:
DTS_POST_CPP = os.environ["DTS_POST_CPP"]
BINDINGS_DIR = os.environ.get("DTS_ROOT_BINDINGS")
# if a board port doesn't use DTS than these might not be set
if os.path.isfile(DTS_POST_CPP) and BINDINGS_DIR is not None:
edt = edtlib.EDT(DTS_POST_CPP, [BINDINGS_DIR])
else:
edt = None
# The env var 'GENERATED_DTS_BOARD_CONF' must be set unless we are in
# doc mode
GENERATED_DTS_BOARD_CONF = os.environ['GENERATED_DTS_BOARD_CONF']
@ -91,8 +106,194 @@ def dt_str_val(kconf, _, name):
return dt_defines[name].strip('"')
def dt_chosen_label(kconf, _, chosen):
"""
This function takes a 'chosen' property and treats that property as a path
to a EDT device. If it finds a EDT device, it will look to see if that
device has a "label" property and return the value of that "label", if not
we return an empty string.
"""
if doc_mode or edt is None:
return ""
dev = edt.chosen_dev(chosen)
if not dev:
return ""
if "label" not in dev.props:
return ""
return dev.props["label"].val
def _dev_reg_addr(dev, index, unit):
if not dev:
return "0x0"
if not dev.regs:
return "0x0"
if int(index) >= len(dev.regs):
return "0x0"
return hex(dev.regs[int(index)].addr >> _dt_units_to_scale(unit))
def _dev_reg_size(dev, index, unit):
if not dev:
return "0"
if not dev.regs:
return "0"
if int(index) >= len(dev.regs):
return "0"
return str(dev.regs[int(index)].size >> _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 a EDT device. If it finds a EDT device, it will look to see if that
device has a register at the give '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)
"""
if doc_mode or edt is None:
return "0x0"
dev = edt.chosen_dev(chosen)
return _dev_reg_addr(dev, 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 a EDT device. If it finds a EDT device, it will look to see if that
device has a register at the give '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)
"""
if doc_mode or edt is None:
return "0"
dev = edt.chosen_dev(chosen)
return _dev_reg_size(dev, index, unit)
def dt_node_reg_addr(kconf, _, path, index=0, unit=None):
"""
This function takes a 'path' and looks for a EDT device at that path.
If it finds a EDT device, it will look to see if that device has a
register at the give '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)
"""
if doc_mode or edt is None:
return "0"
try:
dev = edt.get_dev(path)
except edtlib.EDTError:
return "0"
return _dev_reg_addr(dev, index, unit)
def dt_node_reg_size(kconf, _, path, index=0, unit=None):
"""
This function takes a 'path' and looks for a EDT device at that path.
If it finds a EDT device, it will look to see if that device has a
register at the give '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)
"""
if doc_mode or edt is None:
return "0"
try:
dev = edt.get_dev(path)
except edtlib.EDTError:
return "0"
return _dev_reg_size(dev, index, unit)
def dt_node_has_bool_prop(kconf, _, path, prop):
"""
This function takes a 'path' and looks for a EDT device at that path.
If it finds a EDT device, it will look to see if that device 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"
try:
dev = edt.get_dev(path)
except edtlib.EDTError:
return "n"
if prop not in dev.props:
return "n"
if dev.props[prop].type != "boolean":
return "n"
if dev.props[prop].val:
return "y"
return "n"
def dt_compat_enabled(kconf, _, compat):
"""
This function takes a 'compat' and returns "y" if we find an "enabled"
compatible device in the EDT otherwise we return "n"
"""
if doc_mode or edt is None:
return "n"
for dev in edt.devices:
if compat in dev.compats and dev.enabled:
return "y"
return "n"
functions = {
"dt_int_val": (dt_int_val, 1, 2),
"dt_hex_val": (dt_hex_val, 1, 2),
"dt_str_val": (dt_str_val, 1, 1),
"dt_compat_enabled": (dt_compat_enabled, 1, 1),
"dt_chosen_label": (dt_chosen_label, 1, 1),
"dt_chosen_reg_addr": (dt_chosen_reg_addr, 1, 3),
"dt_chosen_reg_size": (dt_chosen_reg_size, 1, 3),
"dt_node_reg_addr": (dt_node_reg_addr, 1, 3),
"dt_node_reg_size": (dt_node_reg_size, 1, 3),
"dt_node_has_bool_prop": (dt_node_has_bool_prop, 2, 2),
}