1# SPDX-License-Identifier: Apache-2.0 2 3include_guard(GLOBAL) 4 5include(extensions) 6include(python) 7include(boards) 8include(pre_dt) 9find_package(HostTools) 10find_package(Dtc 1.4.6) 11 12# This module makes information from the devicetree available to 13# various build stages, as well as to other arbitrary Python scripts: 14# 15# - To Zephyr and application source code files, as a C macro API 16# defined in <zephyr/devicetree.h> 17# 18# - To other arbitrary Python scripts (like twister) using a 19# serialized edtlib.EDT object in Python's pickle format 20# (https://docs.python.org/3/library/pickle.html) 21# 22# - To users as a final devicetree source (DTS) file which can 23# be used for debugging 24# 25# - To CMake files, after this module has finished running, using 26# devicetree extensions defined in cmake/modules/extensions.cmake 27# 28# - To Kconfig files, both using some Kconfig symbols we generate 29# here as well as the extension functions defined in 30# scripts/kconfig/kconfigfunctions.py 31# 32# See the specific API documentation for each of these cases for more 33# information on what is currently available to you. 34# 35# We rely on the C preprocessor, the devicetree python package, and 36# files in scripts/dts to make all this work. We also optionally will 37# run the dtc tool if it is found, in order to catch any additional 38# warnings or errors it generates. 39# 40# Outcome: 41# 42# 1. The following has happened: 43# 44# - The pre_dt module has been included; refer to its outcome 45# section for more information on the consequences 46# - DTS_SOURCE: set to the path to the devicetree file which 47# was used, if one was provided or found 48# - ${BINARY_DIR_INCLUDE_GENERATED}/devicetree_generated.h exists 49# 50# 2. The following has happened if a devicetree was found and 51# no errors occurred: 52# 53# - CACHED_DTS_ROOT_BINDINGS is set in the cache to the 54# value of DTS_ROOT_BINDINGS 55# - DTS_ROOT_BINDINGS is set to a ;-list of locations where DT 56# bindings were found 57# - ${PROJECT_BINARY_DIR}/zephyr.dts exists 58# - ${PROJECT_BINARY_DIR}/edt.pickle exists 59# - ${KCONFIG_BINARY_DIR}/Kconfig.dts exists 60# - DTS_INCLUDE_FILES is set to a ;-list of all devicetree files 61# used in this build, including transitive includes (the build 62# system will be regenerated if any of those files change) 63# - the devicetree extensions in the extensions.cmake module 64# will be ready for use in other CMake list files that run 65# after this module 66# 67# Required variables: 68# - BINARY_DIR_INCLUDE_GENERATED: where to put generated include files 69# - DTS_ROOT: a deduplicated list of places where devicetree 70# implementation files (like bindings, vendor prefixes, etc.) are 71# found 72# - DTS_ROOT_SYSTEM_INCLUDE_DIRS: set to "PATH1 PATH2 ...", 73# with one path per potential location where C preprocessor #includes 74# may be found for devicetree files 75# - KCONFIG_BINARY_DIR: where to put generated Kconfig files 76# 77# Optional variables: 78# - BOARD: board name to use when looking for DTS_SOURCE 79# - BOARD_DIRECTORIES: list of board directories to use when looking for DTS_SOURCE 80# - BOARD_REVISION_STRING: used when looking for a board revision's 81# devicetree overlay file in one of the BOARD_DIRECTORIES 82# - CMAKE_DTS_PREPROCESSOR: the path to the preprocessor to use 83# for devicetree files 84# - DTC_OVERLAY_FILE: list of devicetree overlay files which will be 85# used to modify or extend the base devicetree. 86# - EXTRA_DTC_OVERLAY_FILE: list of extra devicetree overlay files. 87# This variable is similar to DTC_OVERLAY_FILE but the files in 88# EXTRA_DTC_OVERLAY_FILE will be applied after DTC_OVERLAY_FILE and 89# thus files specified by EXTRA_DTC_OVERLAY_FILE have higher precedence. 90# - EXTRA_DTC_FLAGS: list of extra command line options to pass to 91# dtc when using it to check for additional errors and warnings; 92# invalid flags are automatically filtered out of the list 93# - DTS_EXTRA_CPPFLAGS: extra command line options to pass to the 94# C preprocessor when generating the devicetree from DTS_SOURCE 95# - DTS_SOURCE: the devicetree source file to use may be pre-set 96# with this variable; otherwise, it defaults to 97# ${BOARD_DIRECTORIES}/<normalized_board_target>.dts 98# 99# Variables set by this module and not mentioned above are for internal 100# use only, and may be removed, renamed, or re-purposed without prior notice. 101 102# The directory containing devicetree related scripts. 103set(DT_SCRIPTS ${ZEPHYR_BASE}/scripts/dts) 104 105# This parses and collects the DT information 106set(GEN_EDT_SCRIPT ${DT_SCRIPTS}/gen_edt.py) 107# This generates DT information needed by the C macro APIs, 108# along with a few other things. 109set(GEN_DEFINES_SCRIPT ${DT_SCRIPTS}/gen_defines.py) 110# The edtlib.EDT object in pickle format. 111set(EDT_PICKLE ${PROJECT_BINARY_DIR}/edt.pickle) 112# The generated file containing the final DTS, for debugging. 113set(ZEPHYR_DTS ${PROJECT_BINARY_DIR}/zephyr.dts) 114# The generated C header needed by <zephyr/devicetree.h> 115set(DEVICETREE_GENERATED_H ${BINARY_DIR_INCLUDE_GENERATED}/devicetree_generated.h) 116# Generated build system internals. 117set(DTS_POST_CPP ${PROJECT_BINARY_DIR}/zephyr.dts.pre) 118set(DTS_DEPS ${PROJECT_BINARY_DIR}/zephyr.dts.d) 119 120# This generates DT information needed by the Kconfig APIs. 121set(GEN_DRIVER_KCONFIG_SCRIPT ${DT_SCRIPTS}/gen_driver_kconfig_dts.py) 122# Generated Kconfig symbols go here. 123set(DTS_KCONFIG ${KCONFIG_BINARY_DIR}/Kconfig.dts) 124 125# The location of a file containing known vendor prefixes, relative to 126# each element of DTS_ROOT. Users can define their own in their own 127# modules. 128set(VENDOR_PREFIXES dts/bindings/vendor-prefixes.txt) 129 130if(NOT DEFINED DTS_SOURCE) 131 zephyr_build_string(board_string SHORT shortened_board_string 132 BOARD ${BOARD} BOARD_QUALIFIERS ${BOARD_QUALIFIERS} 133 ) 134 foreach(dir ${BOARD_DIRECTORIES}) 135 if(EXISTS ${dir}/${shortened_board_string}.dts AND NOT BOARD_${BOARD}_SINGLE_SOC) 136 message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name " 137 "(${shortened_board_string}.dts) not allowed, use '<board>_<soc>.dts' naming" 138 ) 139 elseif(EXISTS ${dir}/${board_string}.dts AND EXISTS ${dir}/${shortened_board_string}.dts) 140 message(FATAL_ERROR "Conflicting file names discovered. Cannot use both " 141 "${board_string}.dts and ${shortened_board_string}.dts. " 142 "Please choose one naming style, ${board_string}.dts is recommended." 143 ) 144 elseif(EXISTS ${dir}/${board_string}.dts) 145 set(DTS_SOURCE ${dir}/${board_string}.dts) 146 elseif(EXISTS ${dir}/${shortened_board_string}.dts) 147 set(DTS_SOURCE ${dir}/${shortened_board_string}.dts) 148 endif() 149 endforeach() 150endif() 151 152if(EXISTS ${DTS_SOURCE}) 153 # We found a devicetree. Append all relevant dts overlays we can find... 154 zephyr_file(CONF_FILES ${BOARD_DIRECTORIES} DTS DTS_SOURCE) 155 156 zephyr_file( 157 CONF_FILES ${BOARD_DIRECTORIES} 158 DTS no_rev_suffix_dts_board_overlays 159 BOARD ${BOARD} 160 BOARD_QUALIFIERS ${BOARD_QUALIFIERS} 161 ) 162 163 # ...but remove the ones that do not include the revision suffix 164 list(REMOVE_ITEM DTS_SOURCE ${no_rev_suffix_dts_board_overlays}) 165else() 166 # If we don't have a devicetree, provide an empty stub 167 set(DTS_SOURCE ${ZEPHYR_BASE}/boards/common/stub.dts) 168endif() 169 170# 171# Find all the DTS files we need to concatenate and preprocess, as 172# well as all the devicetree bindings and vendor prefixes associated 173# with them. 174# 175 176zephyr_file(CONF_FILES ${BOARD_EXTENSION_DIRS} DTS board_extension_dts_files) 177 178set(dts_files 179 ${DTS_SOURCE} 180 ${board_extension_dts_files} 181 ${shield_dts_files} 182 ) 183 184if(DTC_OVERLAY_FILE) 185 zephyr_list(TRANSFORM DTC_OVERLAY_FILE NORMALIZE_PATHS 186 OUTPUT_VARIABLE DTC_OVERLAY_FILE_AS_LIST) 187 build_info(devicetree user-files PATH ${DTC_OVERLAY_FILE_AS_LIST}) 188 list(APPEND 189 dts_files 190 ${DTC_OVERLAY_FILE_AS_LIST} 191 ) 192endif() 193 194if(EXTRA_DTC_OVERLAY_FILE) 195 zephyr_list(TRANSFORM EXTRA_DTC_OVERLAY_FILE NORMALIZE_PATHS 196 OUTPUT_VARIABLE EXTRA_DTC_OVERLAY_FILE_AS_LIST) 197 build_info(devicetree extra-user-files PATH ${EXTRA_DTC_OVERLAY_FILE_AS_LIST}) 198 list(APPEND 199 dts_files 200 ${EXTRA_DTC_OVERLAY_FILE_AS_LIST} 201 ) 202endif() 203 204set(i 0) 205foreach(dts_file ${dts_files}) 206 if(i EQUAL 0) 207 message(STATUS "Found BOARD.dts: ${dts_file}") 208 else() 209 message(STATUS "Found devicetree overlay: ${dts_file}") 210 endif() 211 212 math(EXPR i "${i}+1") 213endforeach() 214 215unset(DTS_ROOT_BINDINGS) 216foreach(dts_root ${DTS_ROOT}) 217 set(bindings_path ${dts_root}/dts/bindings) 218 if(EXISTS ${bindings_path}) 219 list(APPEND 220 DTS_ROOT_BINDINGS 221 ${bindings_path} 222 ) 223 endif() 224 225 set(vendor_prefixes ${dts_root}/${VENDOR_PREFIXES}) 226 if(EXISTS ${vendor_prefixes}) 227 list(APPEND EXTRA_GEN_EDT_ARGS --vendor-prefixes ${vendor_prefixes}) 228 endif() 229endforeach() 230 231# Cache the location of the root bindings so they can be used by 232# scripts which use the build directory. 233set(CACHED_DTS_ROOT_BINDINGS ${DTS_ROOT_BINDINGS} CACHE INTERNAL 234 "DT bindings root directories") 235 236# 237# Run the C preprocessor on the devicetree source, so we can parse it 238# (using the Python devicetree package) in later steps. 239# 240 241# TODO: Cut down on CMake configuration time by avoiding 242# regeneration of devicetree_generated.h on every configure. How 243# challenging is this? Can we cache the dts dependencies? 244 245# Run the preprocessor on the DTS input files. 246if(DEFINED CMAKE_DTS_PREPROCESSOR) 247 set(dts_preprocessor ${CMAKE_DTS_PREPROCESSOR}) 248else() 249 set(dts_preprocessor ${CMAKE_C_COMPILER}) 250endif() 251zephyr_dt_preprocess( 252 CPP ${dts_preprocessor} 253 SOURCE_FILES ${dts_files} 254 OUT_FILE ${DTS_POST_CPP} 255 DEPS_FILE ${DTS_DEPS} 256 EXTRA_CPPFLAGS ${DTS_EXTRA_CPPFLAGS} 257 INCLUDE_DIRECTORIES ${DTS_ROOT_SYSTEM_INCLUDE_DIRS} 258 WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} 259 ) 260 261# 262# Make sure we re-run CMake if any devicetree sources or transitive 263# includes change. 264# 265 266# Parse the generated dependency file to find the DT sources that 267# were included, including any transitive includes. 268toolchain_parse_make_rule(${DTS_DEPS} 269 DTS_INCLUDE_FILES # Output parameter 270 ) 271 272# Add the results to the list of files that, when change, force the 273# build system to re-run CMake. 274set_property(DIRECTORY APPEND PROPERTY 275 CMAKE_CONFIGURE_DEPENDS 276 ${DTS_INCLUDE_FILES} 277 ${GEN_EDT_SCRIPT} 278 ${GEN_DEFINES_SCRIPT} 279 ${GEN_DRIVER_KCONFIG_SCRIPT} 280 ) 281 282# 283# Run GEN_EDT_SCRIPT. 284# 285 286if(WEST_TOPDIR) 287 set(GEN_EDT_WORKSPACE_DIR ${WEST_TOPDIR}) 288else() 289 # If West is not available, define the parent directory of ZEPHYR_BASE as 290 # the workspace. This will create comments that reference the files in the 291 # Zephyr tree with a 'zephyr/' prefix. 292 set(GEN_EDT_WORKSPACE_DIR ${ZEPHYR_BASE}/..) 293endif() 294 295string(REPLACE ";" " " EXTRA_DTC_FLAGS_RAW "${EXTRA_DTC_FLAGS}") 296set(CMD_GEN_EDT ${PYTHON_EXECUTABLE} ${GEN_EDT_SCRIPT} 297--dts ${DTS_POST_CPP} 298--dtc-flags '${EXTRA_DTC_FLAGS_RAW}' 299--bindings-dirs ${DTS_ROOT_BINDINGS} 300--workspace-dir ${GEN_EDT_WORKSPACE_DIR} 301--dts-out ${ZEPHYR_DTS}.new # for debugging and dtc 302--edt-pickle-out ${EDT_PICKLE}.new 303${EXTRA_GEN_EDT_ARGS} 304) 305 306execute_process( 307 COMMAND ${CMD_GEN_EDT} 308 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 309 COMMAND_ERROR_IS_FATAL ANY 310 ) 311zephyr_file_copy(${ZEPHYR_DTS}.new ${ZEPHYR_DTS} ONLY_IF_DIFFERENT) 312zephyr_file_copy(${EDT_PICKLE}.new ${EDT_PICKLE} ONLY_IF_DIFFERENT) 313file(REMOVE ${ZEPHYR_DTS}.new ${EDT_PICKLE}.new) 314message(STATUS "Generated zephyr.dts: ${ZEPHYR_DTS}") 315message(STATUS "Generated pickled edt: ${EDT_PICKLE}") 316 317# 318# Run GEN_DEFINES_SCRIPT. 319# 320 321set(CMD_GEN_DEFINES ${PYTHON_EXECUTABLE} ${GEN_DEFINES_SCRIPT} 322--header-out ${DEVICETREE_GENERATED_H}.new 323--edt-pickle ${EDT_PICKLE} 324${EXTRA_GEN_DEFINES_ARGS} 325) 326 327execute_process( 328 COMMAND ${CMD_GEN_DEFINES} 329 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 330 COMMAND_ERROR_IS_FATAL ANY 331 ) 332zephyr_file_copy(${DEVICETREE_GENERATED_H}.new ${DEVICETREE_GENERATED_H} ONLY_IF_DIFFERENT) 333file(REMOVE ${DEVICETREE_GENERATED_H}.new) 334message(STATUS "Generated devicetree_generated.h: ${DEVICETREE_GENERATED_H}") 335 336# 337# Run GEN_DRIVER_KCONFIG_SCRIPT. 338# 339 340execute_process( 341 COMMAND ${PYTHON_EXECUTABLE} ${GEN_DRIVER_KCONFIG_SCRIPT} 342 --kconfig-out ${DTS_KCONFIG} 343 --bindings-dirs ${DTS_ROOT_BINDINGS} 344 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 345 RESULT_VARIABLE ret 346 ) 347if(NOT "${ret}" STREQUAL "0") 348 message(FATAL_ERROR "gen_driver_kconfig_dts.py failed with return code: ${ret}") 349endif() 350 351# 352# Import devicetree contents into CMake. 353# This enables the CMake dt_* API. 354# 355 356add_custom_target(devicetree_target) 357zephyr_dt_import(EDT_PICKLE_FILE ${EDT_PICKLE} TARGET devicetree_target) 358 359# 360# Run dtc if it was found. 361# 362# This is just to generate warnings and errors; we discard the output. 363# 364 365if(DTC) 366 367set(DTC_WARN_UNIT_ADDR_IF_ENABLED "") 368check_dtc_flag("-Wunique_unit_address_if_enabled" check) 369if (check) 370 set(DTC_WARN_UNIT_ADDR_IF_ENABLED "-Wunique_unit_address_if_enabled") 371endif() 372 373set(DTC_NO_WARN_UNIT_ADDR "") 374check_dtc_flag("-Wno-unique_unit_address" check) 375if (check) 376 set(DTC_NO_WARN_UNIT_ADDR "-Wno-unique_unit_address") 377endif() 378 379set(VALID_EXTRA_DTC_FLAGS "") 380foreach(extra_opt ${EXTRA_DTC_FLAGS}) 381 check_dtc_flag(${extra_opt} check) 382 if (check) 383 list(APPEND VALID_EXTRA_DTC_FLAGS ${extra_opt}) 384 endif() 385endforeach() 386set(EXTRA_DTC_FLAGS ${VALID_EXTRA_DTC_FLAGS}) 387 388execute_process( 389 COMMAND ${DTC} 390 -O dts 391 -o - # Write output to stdout, which we discard below 392 -b 0 393 -E unit_address_vs_reg 394 ${DTC_NO_WARN_UNIT_ADDR} 395 ${DTC_WARN_UNIT_ADDR_IF_ENABLED} 396 ${EXTRA_DTC_FLAGS} # User settable 397 ${ZEPHYR_DTS} 398 OUTPUT_QUIET # Discard stdout 399 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 400 COMMAND_ERROR_IS_FATAL ANY 401 ) 402 403endif(DTC) 404 405build_info(devicetree files PATH ${dts_files}) 406build_info(devicetree include-dirs PATH ${DTS_ROOT_SYSTEM_INCLUDE_DIRS}) 407build_info(devicetree bindings-dirs PATH ${DTS_ROOT_BINDINGS}) 408