Skip to content

Commit 2ab3b1a

Browse files
57300anangl
authored andcommitted
[nrf fromlist] sysbuild: dts: Introduce sysbuild_dt_* API
Add new functions to `sysbuild_extensions.cmake`, which will mirror the familiar dt_* API from Zephyr `extensions.cmake`. For example: dt_nodelabel(<var> NODELABEL <label>) gets the following sysbuild counterpart, with one extra argument: sysbuild_dt_nodelabel(<var> IMAGE <image> NODELABEL <label>) This API allows sysbuild to retrieve devicetree information for a given <image>, only after its respective `ExternalZephyrProject_Cmake()` call. This works by importing the generated `dts.cmake` files from each image's build directory, and creating multiple CMake targets to hold the generated properties - much like how the `CMakeCache.txt` and `.config` are also imported to be used by the related `sysbuild_get()` function. The dt_* API itself also has to be updated, in order to read properties from a variable `DEVICETREE_TARGET` set in the parent scope. Upstream PR #: 73903 Signed-off-by: Grzegorz Swiderski <grzegorz.swiderski@nordicsemi.no> (cherry picked from commit 38fdd95)
1 parent be1162e commit 2ab3b1a

File tree

2 files changed

+144
-12
lines changed

2 files changed

+144
-12
lines changed

cmake/modules/extensions.cmake

+59-12
Original file line numberDiff line numberDiff line change
@@ -3799,6 +3799,9 @@ endfunction()
37993799
# alias at the beginning of a path interchangeably with the full
38003800
# path to the aliased node in these functions. The usage comments
38013801
# will make this clear in each case.
3802+
#
3803+
# - Each of these methods also has a sysbuild_dt_* counterpart.
3804+
# See share/sysbuild/cmake/modules/sysbuild_extensions.cmake.
38023805

38033806
# Usage:
38043807
# dt_nodelabel(<var> NODELABEL <label>)
@@ -3826,6 +3829,10 @@ endfunction()
38263829
# NODELABEL <label> : Node label
38273830
# REQUIRED : Generate a fatal error if the node-label is not found
38283831
function(dt_nodelabel var)
3832+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
3833+
message(FATAL_ERROR "dt_nodelabel(${ARGV0} ...) devicetree is not available.")
3834+
endif()
3835+
38293836
set(options "REQUIRED")
38303837
set(req_single_args "NODELABEL")
38313838
cmake_parse_arguments(DT_LABEL "${options}" "${req_single_args}" "" ${ARGN})
@@ -3842,7 +3849,7 @@ function(dt_nodelabel var)
38423849
endif()
38433850
endforeach()
38443851

3845-
get_target_property(${var} devicetree_target "DT_NODELABEL|${DT_LABEL_NODELABEL}")
3852+
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_NODELABEL|${DT_LABEL_NODELABEL}")
38463853
if(${${var}} STREQUAL ${var}-NOTFOUND)
38473854
if(DT_LABEL_REQUIRED)
38483855
message(FATAL_ERROR "required nodelabel not found: ${DT_LABEL_NODELABEL}")
@@ -3874,6 +3881,10 @@ endfunction()
38743881
# PROPERTY <prop> : The alias to check
38753882
# REQUIRED : Generate a fatal error if the alias is not found
38763883
function(dt_alias var)
3884+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
3885+
message(FATAL_ERROR "dt_alias(${ARGV0} ...) devicetree is not available.")
3886+
endif()
3887+
38773888
set(options "REQUIRED")
38783889
set(req_single_args "PROPERTY")
38793890
cmake_parse_arguments(DT_ALIAS "${options}" "${req_single_args}" "" ${ARGN})
@@ -3890,7 +3901,7 @@ function(dt_alias var)
38903901
endif()
38913902
endforeach()
38923903

3893-
get_target_property(${var} devicetree_target "DT_ALIAS|${DT_ALIAS_PROPERTY}")
3904+
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_ALIAS|${DT_ALIAS_PROPERTY}")
38943905
if(${${var}} STREQUAL ${var}-NOTFOUND)
38953906
if(DT_ALIAS_REQUIRED)
38963907
message(FATAL_ERROR "required alias not found: ${DT_ALIAS_PROPERTY}")
@@ -3918,6 +3929,10 @@ endfunction()
39183929
# <var> : Return variable where the check result will be returned
39193930
# PATH <path> : Node path
39203931
function(dt_node_exists var)
3932+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
3933+
message(FATAL_ERROR "dt_node_exists(${ARGV0} ...) devicetree is not available.")
3934+
endif()
3935+
39213936
set(req_single_args "PATH")
39223937
cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})
39233938

@@ -3963,6 +3978,10 @@ endfunction()
39633978
# PATH <path> : Node path
39643979
# STATUS <status> : Status to check
39653980
function(dt_node_has_status var)
3981+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
3982+
message(FATAL_ERROR "dt_node_has_status(${ARGV0} ...) devicetree is not available.")
3983+
endif()
3984+
39663985
set(req_single_args "PATH;STATUS")
39673986
cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})
39683987

@@ -4049,6 +4068,10 @@ endfunction()
40494068
# INDEX <idx> : Optional index when retrieving a value in an array property
40504069
# REQUIRED : Generate a fatal error if the property is not found
40514070
function(dt_prop var)
4071+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
4072+
message(FATAL_ERROR "dt_prop(${ARGV0} ...) devicetree is not available.")
4073+
endif()
4074+
40524075
set(options "REQUIRED")
40534076
set(req_single_args "PATH;PROPERTY")
40544077
set(single_args "INDEX")
@@ -4067,7 +4090,7 @@ function(dt_prop var)
40674090
endforeach()
40684091

40694092
dt_path_internal(canonical "${DT_PROP_PATH}")
4070-
get_property(exists TARGET devicetree_target
4093+
get_property(exists TARGET "${DEVICETREE_TARGET}"
40714094
PROPERTY "DT_PROP|${canonical}|${DT_PROP_PROPERTY}"
40724095
SET
40734096
)
@@ -4080,7 +4103,7 @@ function(dt_prop var)
40804103
return()
40814104
endif()
40824105

4083-
get_target_property(val devicetree_target
4106+
get_target_property(val "${DEVICETREE_TARGET}"
40844107
"DT_PROP|${canonical}|${DT_PROP_PROPERTY}"
40854108
)
40864109

@@ -4109,6 +4132,10 @@ endfunction()
41094132
# INDEX <idx> : Optional index when retrieving a value in an array property
41104133

41114134
function(dt_comp_path var)
4135+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
4136+
message(FATAL_ERROR "dt_comp_path(${ARGV0} ...) devicetree is not available.")
4137+
endif()
4138+
41124139
set(req_single_args "COMPATIBLE")
41134140
set(single_args "INDEX")
41144141
cmake_parse_arguments(DT_COMP "" "${req_single_args};${single_args}" "" ${ARGN})
@@ -4125,7 +4152,7 @@ function(dt_comp_path var)
41254152
endif()
41264153
endforeach()
41274154

4128-
get_property(exists TARGET devicetree_target
4155+
get_property(exists TARGET "${DEVICETREE_TARGET}"
41294156
PROPERTY "DT_COMP|${DT_COMP_COMPATIBLE}"
41304157
SET
41314158
)
@@ -4135,7 +4162,7 @@ function(dt_comp_path var)
41354162
return()
41364163
endif()
41374164

4138-
get_target_property(val devicetree_target
4165+
get_target_property(val "${DEVICETREE_TARGET}"
41394166
"DT_COMP|${DT_COMP_COMPATIBLE}"
41404167
)
41414168

@@ -4164,6 +4191,10 @@ endfunction()
41644191
# <var> : Return variable where the property value will be stored
41654192
# PATH <path> : Node path
41664193
function(dt_num_regs var)
4194+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
4195+
message(FATAL_ERROR "dt_num_regs(${ARGV0} ...) devicetree is not available.")
4196+
endif()
4197+
41674198
set(req_single_args "PATH")
41684199
cmake_parse_arguments(DT_REG "" "${req_single_args}" "" ${ARGN})
41694200

@@ -4180,7 +4211,7 @@ function(dt_num_regs var)
41804211
endforeach()
41814212

41824213
dt_path_internal(canonical "${DT_REG_PATH}")
4183-
get_target_property(${var} devicetree_target "DT_REG|${canonical}|NUM")
4214+
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_REG|${canonical}|NUM")
41844215

41854216
set(${var} ${${var}} PARENT_SCOPE)
41864217
endfunction()
@@ -4210,6 +4241,10 @@ endfunction()
42104241
# INDEX <idx> : Register block index number
42114242
# NAME <name> : Register block name
42124243
function(dt_reg_addr var)
4244+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
4245+
message(FATAL_ERROR "dt_reg_addr(${ARGV0} ...) devicetree is not available.")
4246+
endif()
4247+
42134248
set(req_single_args "PATH")
42144249
set(single_args "INDEX;NAME")
42154250
cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
@@ -4239,7 +4274,7 @@ function(dt_reg_addr var)
42394274
endif()
42404275

42414276
dt_path_internal(canonical "${DT_REG_PATH}")
4242-
get_target_property(${var}_list devicetree_target "DT_REG|${canonical}|ADDR")
4277+
get_target_property(${var}_list "${DEVICETREE_TARGET}" "DT_REG|${canonical}|ADDR")
42434278

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

@@ -4270,6 +4305,10 @@ endfunction()
42704305
# INDEX <idx> : Register block index number
42714306
# NAME <name> : Register block name
42724307
function(dt_reg_size var)
4308+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
4309+
message(FATAL_ERROR "dt_reg_size(${ARGV0} ...) devicetree is not available.")
4310+
endif()
4311+
42734312
set(req_single_args "PATH")
42744313
set(single_args "INDEX;NAME")
42754314
cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
@@ -4299,7 +4338,7 @@ function(dt_reg_size var)
42994338
endif()
43004339

43014340
dt_path_internal(canonical "${DT_REG_PATH}")
4302-
get_target_property(${var}_list devicetree_target "DT_REG|${canonical}|SIZE")
4341+
get_target_property(${var}_list "${DEVICETREE_TARGET}" "DT_REG|${canonical}|SIZE")
43034342

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

@@ -4347,6 +4386,10 @@ endfunction()
43474386
# <var> : Return variable
43484387
# PROPERTY <prop> : Chosen property
43494388
function(dt_has_chosen var)
4389+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
4390+
message(FATAL_ERROR "dt_has_chosen(${ARGV0} ...) devicetree is not available.")
4391+
endif()
4392+
43504393
set(req_single_args "PROPERTY")
43514394
cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})
43524395

@@ -4362,7 +4405,7 @@ function(dt_has_chosen var)
43624405
endif()
43634406
endforeach()
43644407

4365-
get_target_property(exists devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
4408+
get_target_property(exists "${DEVICETREE_TARGET}" "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
43664409

43674410
if(${exists} STREQUAL exists-NOTFOUND)
43684411
set(${var} FALSE PARENT_SCOPE)
@@ -4382,6 +4425,10 @@ endfunction()
43824425
# <var> : Return variable where the node path will be stored
43834426
# PROPERTY <prop> : Chosen property
43844427
function(dt_chosen var)
4428+
if(NOT DEFINED DEVICETREE_TARGET OR NOT TARGET "${DEVICETREE_TARGET}")
4429+
message(FATAL_ERROR "dt_chosen(${ARGV0} ...) devicetree is not available.")
4430+
endif()
4431+
43854432
set(req_single_args "PROPERTY")
43864433
cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})
43874434

@@ -4397,7 +4444,7 @@ function(dt_chosen var)
43974444
endif()
43984445
endforeach()
43994446

4400-
get_target_property(${var} devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
4447+
get_target_property(${var} "${DEVICETREE_TARGET}" "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
44014448

44024449
if(${${var}} STREQUAL ${var}-NOTFOUND)
44034450
set(${var} PARENT_SCOPE)
@@ -4469,7 +4516,7 @@ endfunction()
44694516
# to an existing node. Set it to FALSE otherwise. See
44704517
# dt_path_internal for a definition and examples of 'canonical' paths.
44714518
function(dt_path_internal_exists var path)
4472-
get_target_property(path_prop devicetree_target "DT_NODE|${path}")
4519+
get_target_property(path_prop "${DEVICETREE_TARGET}" "DT_NODE|${path}")
44734520
if (path_prop)
44744521
set(${var} TRUE PARENT_SCOPE)
44754522
else()

share/sysbuild/cmake/modules/sysbuild_extensions.cmake

+85
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,8 @@ function(ExternalZephyrProject_Cmake)
518518
endif()
519519
load_cache(IMAGE ${ZCMAKE_APPLICATION} BINARY_DIR ${BINARY_DIR})
520520
import_kconfig(CONFIG_ ${BINARY_DIR}/zephyr/.config TARGET ${ZCMAKE_APPLICATION})
521+
set(DEVICETREE_TARGET ${ZCMAKE_APPLICATION}_devicetree_target)
522+
include(${BINARY_DIR}/zephyr/dts.cmake)
521523

522524
# This custom target informs CMake how the BYPRODUCTS are generated if a target
523525
# depends directly on the BYPRODUCT instead of depending on the image target.
@@ -769,3 +771,86 @@ function(sysbuild_images_order variable dependency_type)
769771
topological_sort(TARGETS ${SIS_IMAGES} PROPERTY_NAME ${property_name} RESULT sorted)
770772
set(${variable} ${sorted} PARENT_SCOPE)
771773
endfunction()
774+
775+
# Internal macro for defining the sysbuild_dt_* CMake extensions, used to
776+
# retrieve devicetree information from a Zephyr based build system.
777+
#
778+
# It takes a dt_* function <name> and adds common wrapper code, which
779+
# adds an `IMAGE` argument to select the devicetree of a given <image>,
780+
# and forwards all other arguments to the original function, including
781+
# the sole return variable <var> - a common trait of the dt_* API.
782+
#
783+
# For additional documentation of each dt_* CMake extension,
784+
# see section 4.1. of cmake/modules/extensions.cmake.
785+
#
786+
macro(sysbuild_dt_function name)
787+
function(sysbuild_${name} var)
788+
cmake_parse_arguments(PARSE_ARGV 1 SBDT "" "IMAGE" "")
789+
zephyr_check_arguments_required_all("sysbuild_${name}" SBDT IMAGE)
790+
791+
set(DEVICETREE_TARGET ${SBDT_IMAGE}_devicetree_target)
792+
if(NOT TARGET ${SBDT_IMAGE} OR NOT TARGET ${DEVICETREE_TARGET})
793+
message(FATAL_ERROR "sysbuild_${name}(...) image '${SBDT_IMAGE}' "
794+
"does not exist or its devicetree is not loaded yet"
795+
)
796+
endif()
797+
798+
cmake_language(CALL ${name} ${var} ${SBDT_UNPARSED_ARGUMENTS})
799+
set(${var} "${${var}}" PARENT_SCOPE)
800+
endfunction()
801+
endmacro()
802+
803+
# Usage:
804+
# sysbuild_dt_nodelabel(<var> IMAGE <image> NODELABEL <label>)
805+
#
806+
sysbuild_dt_function(dt_nodelabel)
807+
808+
# Usage:
809+
# sysbuild_dt_alias(<var> IMAGE <image> PROPERTY <prop>)
810+
#
811+
sysbuild_dt_function(dt_alias)
812+
813+
# Usage:
814+
# sysbuild_dt_node_exists(<var> IMAGE <image> PATH <path>)
815+
#
816+
sysbuild_dt_function(dt_node_exists)
817+
818+
# Usage:
819+
# sysbuild_dt_node_has_status(<var> IMAGE <image> PATH <path> STATUS <status>)
820+
#
821+
sysbuild_dt_function(dt_node_has_status)
822+
823+
# Usage:
824+
# sysbuild_dt_prop(<var> IMAGE <image> PATH <path> PROPERTY <prop> [INDEX <idx>])
825+
#
826+
sysbuild_dt_function(dt_prop)
827+
828+
# Usage:
829+
# sysbuild_dt_comp_path(<var> IMAGE <image> COMPATIBLE <compatible> [INDEX <idx>])
830+
#
831+
sysbuild_dt_function(dt_comp_path)
832+
833+
# Usage:
834+
# sysbuild_dt_num_regs(<var> IMAGE <image> PATH <path>)
835+
#
836+
sysbuild_dt_function(dt_num_regs)
837+
838+
# Usage:
839+
# sysbuild_dt_reg_addr(<var> IMAGE <image> PATH <path> [INDEX <idx>] [NAME <name>])
840+
#
841+
sysbuild_dt_function(dt_reg_addr)
842+
843+
# Usage:
844+
# sysbuild_dt_reg_size(<var> IMAGE <image> PATH <path> [INDEX <idx>] [NAME <name>])
845+
#
846+
sysbuild_dt_function(dt_reg_size)
847+
848+
# Usage:
849+
# sysbuild_dt_has_chosen(<var> IMAGE <image> PROPERTY <prop>)
850+
#
851+
sysbuild_dt_function(dt_has_chosen)
852+
853+
# Usage:
854+
# sysbuild_dt_chosen(<var> IMAGE <image> PROPERTY <prop>)
855+
#
856+
sysbuild_dt_function(dt_chosen)

0 commit comments

Comments
 (0)