Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sysbuild: dts: Introduce sysbuild_dt_* API #73903

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmake/modules/dts.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ set(GEN_DTS_CMAKE_SCRIPT ${DT_SCRIPTS}/gen_dts_cmake.py)
# The generated information itself, which we include() after
# creating it.
set(DTS_CMAKE ${PROJECT_BINARY_DIR}/dts.cmake)
# The CMake target to be initialized by including ${DTS_CMAKE}.
set(DEVICETREE_TARGET devicetree_target)

# The location of a file containing known vendor prefixes, relative to
# each element of DTS_ROOT. Users can define their own in their own
Expand Down
71 changes: 59 additions & 12 deletions cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3611,6 +3611,9 @@ endfunction()
# alias at the beginning of a path interchangeably with the full
# path to the aliased node in these functions. The usage comments
# will make this clear in each case.
#
# - Each of these methods also has a sysbuild_dt_* counterpart.
# See share/sysbuild/cmake/modules/sysbuild_extensions.cmake.

# Usage:
# dt_nodelabel(<var> NODELABEL <label>)
Expand Down Expand Up @@ -3638,6 +3641,10 @@ endfunction()
# NODELABEL <label> : Node label
# REQUIRED : Generate a fatal error if the node-label is not found
function(dt_nodelabel var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_nodelabel(${ARGV0} ...) devicetree is not available.")
endif()

set(options "REQUIRED")
set(req_single_args "NODELABEL")
cmake_parse_arguments(DT_LABEL "${options}" "${req_single_args}" "" ${ARGN})
Expand All @@ -3654,7 +3661,7 @@ function(dt_nodelabel var)
endif()
endforeach()

get_target_property(${var} devicetree_target "DT_NODELABEL|${DT_LABEL_NODELABEL}")
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_NODELABEL|${DT_LABEL_NODELABEL}")
if(${${var}} STREQUAL ${var}-NOTFOUND)
if(DT_LABEL_REQUIRED)
message(FATAL_ERROR "required nodelabel not found: ${DT_LABEL_NODELABEL}")
Expand Down Expand Up @@ -3686,6 +3693,10 @@ endfunction()
# PROPERTY <prop> : The alias to check
# REQUIRED : Generate a fatal error if the alias is not found
function(dt_alias var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_alias(${ARGV0} ...) devicetree is not available.")
endif()

set(options "REQUIRED")
set(req_single_args "PROPERTY")
cmake_parse_arguments(DT_ALIAS "${options}" "${req_single_args}" "" ${ARGN})
Expand All @@ -3702,7 +3713,7 @@ function(dt_alias var)
endif()
endforeach()

get_target_property(${var} devicetree_target "DT_ALIAS|${DT_ALIAS_PROPERTY}")
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_ALIAS|${DT_ALIAS_PROPERTY}")
if(${${var}} STREQUAL ${var}-NOTFOUND)
if(DT_ALIAS_REQUIRED)
message(FATAL_ERROR "required alias not found: ${DT_ALIAS_PROPERTY}")
Expand Down Expand Up @@ -3730,6 +3741,10 @@ endfunction()
# <var> : Return variable where the check result will be returned
# PATH <path> : Node path
function(dt_node_exists var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_node_exists(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "PATH")
cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})

Expand Down Expand Up @@ -3775,6 +3790,10 @@ endfunction()
# PATH <path> : Node path
# STATUS <status> : Status to check
function(dt_node_has_status var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_node_has_status(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "PATH;STATUS")
cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})

Expand Down Expand Up @@ -3861,6 +3880,10 @@ endfunction()
# INDEX <idx> : Optional index when retrieving a value in an array property
# REQUIRED : Generate a fatal error if the property is not found
function(dt_prop var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_prop(${ARGV0} ...) devicetree is not available.")
endif()

set(options "REQUIRED")
set(req_single_args "PATH;PROPERTY")
set(single_args "INDEX")
Expand All @@ -3879,7 +3902,7 @@ function(dt_prop var)
endforeach()

dt_path_internal(canonical "${DT_PROP_PATH}")
get_property(exists TARGET devicetree_target
get_property(exists TARGET "${DEVICETREE_TARGET}"
PROPERTY "DT_PROP|${canonical}|${DT_PROP_PROPERTY}"
SET
)
Expand All @@ -3892,7 +3915,7 @@ function(dt_prop var)
return()
endif()

get_target_property(val devicetree_target
get_target_property(val "${DEVICETREE_TARGET}"
"DT_PROP|${canonical}|${DT_PROP_PROPERTY}"
)

Expand Down Expand Up @@ -3921,6 +3944,10 @@ endfunction()
# INDEX <idx> : Optional index when retrieving a value in an array property

function(dt_comp_path var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_comp_path(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "COMPATIBLE")
set(single_args "INDEX")
cmake_parse_arguments(DT_COMP "" "${req_single_args};${single_args}" "" ${ARGN})
Expand All @@ -3937,7 +3964,7 @@ function(dt_comp_path var)
endif()
endforeach()

get_property(exists TARGET devicetree_target
get_property(exists TARGET "${DEVICETREE_TARGET}"
PROPERTY "DT_COMP|${DT_COMP_COMPATIBLE}"
SET
)
Expand All @@ -3947,7 +3974,7 @@ function(dt_comp_path var)
return()
endif()

get_target_property(val devicetree_target
get_target_property(val "${DEVICETREE_TARGET}"
"DT_COMP|${DT_COMP_COMPATIBLE}"
)

Expand Down Expand Up @@ -3976,6 +4003,10 @@ endfunction()
# <var> : Return variable where the property value will be stored
# PATH <path> : Node path
function(dt_num_regs var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_num_regs(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "PATH")
cmake_parse_arguments(DT_REG "" "${req_single_args}" "" ${ARGN})

Expand All @@ -3992,7 +4023,7 @@ function(dt_num_regs var)
endforeach()

dt_path_internal(canonical "${DT_REG_PATH}")
get_target_property(${var} devicetree_target "DT_REG|${canonical}|NUM")
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_REG|${canonical}|NUM")

set(${var} ${${var}} PARENT_SCOPE)
endfunction()
Expand Down Expand Up @@ -4022,6 +4053,10 @@ endfunction()
# INDEX <idx> : Register block index number
# NAME <name> : Register block name
function(dt_reg_addr var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_reg_addr(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "PATH")
set(single_args "INDEX;NAME")
cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
Expand Down Expand Up @@ -4051,7 +4086,7 @@ function(dt_reg_addr var)
endif()

dt_path_internal(canonical "${DT_REG_PATH}")
get_target_property(${var}_list devicetree_target "DT_REG|${canonical}|ADDR")
get_target_property(${var}_list "${DEVICETREE_TARGET}" "DT_REG|${canonical}|ADDR")

list(GET ${var}_list ${DT_REG_INDEX} ${var})

Expand Down Expand Up @@ -4082,6 +4117,10 @@ endfunction()
# INDEX <idx> : Register block index number
# NAME <name> : Register block name
function(dt_reg_size var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_reg_size(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "PATH")
set(single_args "INDEX;NAME")
cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
Expand Down Expand Up @@ -4111,7 +4150,7 @@ function(dt_reg_size var)
endif()

dt_path_internal(canonical "${DT_REG_PATH}")
get_target_property(${var}_list devicetree_target "DT_REG|${canonical}|SIZE")
get_target_property(${var}_list "${DEVICETREE_TARGET}" "DT_REG|${canonical}|SIZE")

list(GET ${var}_list ${DT_REG_INDEX} ${var})

Expand Down Expand Up @@ -4159,6 +4198,10 @@ endfunction()
# <var> : Return variable
# PROPERTY <prop> : Chosen property
function(dt_has_chosen var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_has_chosen(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "PROPERTY")
cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})

Expand All @@ -4174,7 +4217,7 @@ function(dt_has_chosen var)
endif()
endforeach()

get_target_property(exists devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
get_target_property(exists "${DEVICETREE_TARGET}" "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")

if(${exists} STREQUAL exists-NOTFOUND)
set(${var} FALSE PARENT_SCOPE)
Expand All @@ -4194,6 +4237,10 @@ endfunction()
# <var> : Return variable where the node path will be stored
# PROPERTY <prop> : Chosen property
function(dt_chosen var)
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
message(FATAL_ERROR "dt_chosen(${ARGV0} ...) devicetree is not available.")
endif()

set(req_single_args "PROPERTY")
cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})

Expand All @@ -4209,7 +4256,7 @@ function(dt_chosen var)
endif()
endforeach()

get_target_property(${var} devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")

if(${${var}} STREQUAL ${var}-NOTFOUND)
set(${var} PARENT_SCOPE)
Expand Down Expand Up @@ -4281,7 +4328,7 @@ endfunction()
# to an existing node. Set it to FALSE otherwise. See
# dt_path_internal for a definition and examples of 'canonical' paths.
function(dt_path_internal_exists var path)
get_target_property(path_prop devicetree_target "DT_NODE|${path}")
get_target_property(path_prop "${DEVICETREE_TARGET}" "DT_NODE|${path}")
if (path_prop)
set(${var} TRUE PARENT_SCOPE)
else()
Expand Down
21 changes: 10 additions & 11 deletions scripts/dts/gen_dts_cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@

The generated CMake file looks like this:

add_custom_target(devicetree_target)
set_target_properties(devicetree_target PROPERTIES
add_custom_target(${DEVICETREE_TARGET})
set_target_properties(${DEVICETREE_TARGET} PROPERTIES
"DT_PROP|/soc|compatible" "vnd,soc;")
...

It defines a special CMake target, and saves various values in the
It takes an input variable - DEVICETREE_TARGET - and creates a special
CMake target with this name, which will contain various values in the
devicetree as CMake target properties.

Be careful:
Expand Down Expand Up @@ -154,15 +155,13 @@ def main():
cmake_comp = f'DT_COMP|{comp}'
cmake_props.append(f'"{cmake_comp}" "{cmake_path}"')

cmake_props = map(
'set_target_properties(${{DEVICETREE_TARGET}} PROPERTIES {})'.format,
cmake_props
)
with open(args.cmake_out, "w", encoding="utf-8") as cmake_file:
print('add_custom_target(devicetree_target)', file=cmake_file)
print(file=cmake_file)

for prop in cmake_props:
print(
f'set_target_properties(devicetree_target PROPERTIES {prop})',
file=cmake_file
)
print('add_custom_target(${DEVICETREE_TARGET})\n', *cmake_props,
sep='\n', file=cmake_file)


if __name__ == "__main__":
Expand Down
85 changes: 85 additions & 0 deletions share/sysbuild/cmake/modules/sysbuild_extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ function(ExternalZephyrProject_Cmake)
endif()
load_cache(IMAGE ${ZCMAKE_APPLICATION} BINARY_DIR ${BINARY_DIR})
import_kconfig(CONFIG_ ${BINARY_DIR}/zephyr/.config TARGET ${ZCMAKE_APPLICATION})
set(DEVICETREE_TARGET ${ZCMAKE_APPLICATION}_devicetree_target)
include(${BINARY_DIR}/zephyr/dts.cmake)

# This custom target informs CMake how the BYPRODUCTS are generated if a target
# depends directly on the BYPRODUCT instead of depending on the image target.
Expand Down Expand Up @@ -750,3 +752,86 @@ function(sysbuild_images_order variable dependency_type)
topological_sort(TARGETS ${SIS_IMAGES} PROPERTY_NAME ${property_name} RESULT sorted)
set(${variable} ${sorted} PARENT_SCOPE)
endfunction()

# Internal macro for defining the sysbuild_dt_* CMake extensions, used to
# retrieve devicetree information from a Zephyr based build system.
#
# It takes a dt_* function <name> and adds common wrapper code, which
# adds an `IMAGE` argument to select the devicetree of a given <image>,
# and forwards all other arguments to the original function, including
# the sole return variable <var> - a common trait of the dt_* API.
#
# For additional documentation of each dt_* CMake extension,
# see section 4.1. of cmake/modules/extensions.cmake.
#
macro(sysbuild_dt_function name)
function(sysbuild_${name} var)
cmake_parse_arguments(PARSE_ARGV 1 SBDT "" "IMAGE" "")
zephyr_check_arguments_required_all("sysbuild_${name}" SBDT IMAGE)

set(DEVICETREE_TARGET ${SBDT_IMAGE}_devicetree_target)
if(NOT TARGET ${SBDT_IMAGE} OR NOT TARGET ${DEVICETREE_TARGET})
message(FATAL_ERROR "sysbuild_${name}(...) image '${SBDT_IMAGE}' "
"does not exist or its devicetree is not loaded yet"
)
endif()

cmake_language(CALL ${name} ${var} ${SBDT_UNPARSED_ARGUMENTS})
set(${var} "${${var}}" PARENT_SCOPE)
endfunction()
endmacro()

# Usage:
# sysbuild_dt_nodelabel(<var> IMAGE <image> NODELABEL <label>)
#
sysbuild_dt_function(dt_nodelabel)

# Usage:
# sysbuild_dt_alias(<var> IMAGE <image> PROPERTY <prop>)
#
sysbuild_dt_function(dt_alias)

# Usage:
# sysbuild_dt_node_exists(<var> IMAGE <image> PATH <path>)
#
sysbuild_dt_function(dt_node_exists)

# Usage:
# sysbuild_dt_node_has_status(<var> IMAGE <image> PATH <path> STATUS <status>)
#
sysbuild_dt_function(dt_node_has_status)

# Usage:
# sysbuild_dt_prop(<var> IMAGE <image> PATH <path> PROPERTY <prop> [INDEX <idx>])
#
sysbuild_dt_function(dt_prop)

# Usage:
# sysbuild_dt_comp_path(<var> IMAGE <image> COMPATIBLE <compatible> [INDEX <idx>])
#
sysbuild_dt_function(dt_comp_path)

# Usage:
# sysbuild_dt_num_regs(<var> IMAGE <image> PATH <path>)
#
sysbuild_dt_function(dt_num_regs)

# Usage:
# sysbuild_dt_reg_addr(<var> IMAGE <image> PATH <path> [INDEX <idx>] [NAME <name>])
#
sysbuild_dt_function(dt_reg_addr)

# Usage:
# sysbuild_dt_reg_size(<var> IMAGE <image> PATH <path> [INDEX <idx>] [NAME <name>])
#
sysbuild_dt_function(dt_reg_size)

# Usage:
# sysbuild_dt_has_chosen(<var> IMAGE <image> PROPERTY <prop>)
#
sysbuild_dt_function(dt_has_chosen)

# Usage:
# sysbuild_dt_chosen(<var> IMAGE <image> PROPERTY <prop>)
#
sysbuild_dt_function(dt_chosen)
Loading