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# - the build system will be regenerated if any devicetree files 61# used in this build change, including transitive includes 62# - the devicetree extensions in the extensions.cmake module 63# will be ready for use in other CMake list files that run 64# after this module 65# 66# Required variables: 67# - BINARY_DIR_INCLUDE_GENERATED: where to put generated include files 68# - KCONFIG_BINARY_DIR: where to put generated Kconfig files 69# 70# Optional variables: 71# - BOARD: board name to use when looking for DTS_SOURCE 72# - BOARD_DIR: board directory to use when looking for DTS_SOURCE 73# - BOARD_REVISION_STRING: used when looking for a board revision's 74# devicetree overlay file in BOARD_DIR 75# - DTC_OVERLAY_FILE: list of devicetree overlay files which will be 76# used to modify or extend the base devicetree. 77# - EXTRA_DTC_OVERLAY_FILE: list of extra devicetree overlay files. 78# This variable is is similar to DTC_OVERLAY_FILE but the files in 79# EXTRA_DTC_OVERLAY_FILE will be applied after DTC_OVERLAY_FILE and 80# thus files specified by EXTRA_DTC_OVERLAY_FILE have higher precedence. 81# - EXTRA_DTC_FLAGS: list of extra command line options to pass to 82# dtc when using it to check for additional errors and warnings; 83# invalid flags are automatically filtered out of the list 84# - DTS_EXTRA_CPPFLAGS: extra command line options to pass to the 85# C preprocessor when generating the devicetree from DTS_SOURCE 86# - DTS_SOURCE: the devicetree source file to use may be pre-set 87# with this variable; otherwise, it defaults to 88# ${BOARD_DIR}/${BOARD}.dts 89# 90# Variables set by this module and not mentioned above are for internal 91# use only, and may be removed, renamed, or re-purposed without prior notice. 92 93# The directory containing devicetree related scripts. 94set(DT_SCRIPTS ${ZEPHYR_BASE}/scripts/dts) 95 96# This generates DT information needed by the C macro APIs, 97# along with a few other things. 98set(GEN_DEFINES_SCRIPT ${DT_SCRIPTS}/gen_defines.py) 99# The edtlib.EDT object in pickle format. 100set(EDT_PICKLE ${PROJECT_BINARY_DIR}/edt.pickle) 101# The generated file containing the final DTS, for debugging. 102set(ZEPHYR_DTS ${PROJECT_BINARY_DIR}/zephyr.dts) 103# The generated C header needed by <zephyr/devicetree.h> 104set(DEVICETREE_GENERATED_H ${BINARY_DIR_INCLUDE_GENERATED}/devicetree_generated.h) 105# Generated build system internals. 106set(DTS_POST_CPP ${PROJECT_BINARY_DIR}/zephyr.dts.pre) 107set(DTS_DEPS ${PROJECT_BINARY_DIR}/zephyr.dts.d) 108 109# This generates DT information needed by the Kconfig APIs. 110set(GEN_DRIVER_KCONFIG_SCRIPT ${DT_SCRIPTS}/gen_driver_kconfig_dts.py) 111# Generated Kconfig symbols go here. 112set(DTS_KCONFIG ${KCONFIG_BINARY_DIR}/Kconfig.dts) 113 114# This generates DT information needed by the CMake APIs. 115set(GEN_DTS_CMAKE_SCRIPT ${DT_SCRIPTS}/gen_dts_cmake.py) 116# The generated information itself, which we include() after 117# creating it. 118set(DTS_CMAKE ${PROJECT_BINARY_DIR}/dts.cmake) 119 120# The location of a file containing known vendor prefixes, relative to 121# each element of DTS_ROOT. Users can define their own in their own 122# modules. 123set(VENDOR_PREFIXES dts/bindings/vendor-prefixes.txt) 124 125set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts) 126if(EXISTS ${DTS_SOURCE}) 127 # We found a devicetree. Check for a board revision overlay. 128 if(DEFINED BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) 129 list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) 130 endif() 131else() 132 # If we don't have a devicetree, provide an empty stub 133 set(DTS_SOURCE ${ZEPHYR_BASE}/boards/common/stub.dts) 134endif() 135 136# 137# Find all the DTS files we need to concatenate and preprocess, as 138# well as all the devicetree bindings and vendor prefixes associated 139# with them. 140# 141 142zephyr_file(CONF_FILES ${BOARD_EXTENSION_DIRS} DTS board_extension_dts_files) 143 144set(dts_files 145 ${DTS_SOURCE} 146 ${board_extension_dts_files} 147 ${shield_dts_files} 148 ) 149 150if(DTC_OVERLAY_FILE) 151 zephyr_list(TRANSFORM DTC_OVERLAY_FILE NORMALIZE_PATHS 152 OUTPUT_VARIABLE DTC_OVERLAY_FILE_AS_LIST) 153 list(APPEND 154 dts_files 155 ${DTC_OVERLAY_FILE_AS_LIST} 156 ) 157endif() 158 159if(EXTRA_DTC_OVERLAY_FILE) 160 zephyr_list(TRANSFORM EXTRA_DTC_OVERLAY_FILE NORMALIZE_PATHS 161 OUTPUT_VARIABLE EXTRA_DTC_OVERLAY_FILE_AS_LIST) 162 list(APPEND 163 dts_files 164 ${EXTRA_DTC_OVERLAY_FILE_AS_LIST} 165 ) 166endif() 167 168set(i 0) 169foreach(dts_file ${dts_files}) 170 if(i EQUAL 0) 171 message(STATUS "Found BOARD.dts: ${dts_file}") 172 else() 173 message(STATUS "Found devicetree overlay: ${dts_file}") 174 endif() 175 176 math(EXPR i "${i}+1") 177endforeach() 178 179unset(DTS_ROOT_BINDINGS) 180foreach(dts_root ${DTS_ROOT}) 181 set(bindings_path ${dts_root}/dts/bindings) 182 if(EXISTS ${bindings_path}) 183 list(APPEND 184 DTS_ROOT_BINDINGS 185 ${bindings_path} 186 ) 187 endif() 188 189 set(vendor_prefixes ${dts_root}/${VENDOR_PREFIXES}) 190 if(EXISTS ${vendor_prefixes}) 191 list(APPEND EXTRA_GEN_DEFINES_ARGS --vendor-prefixes ${vendor_prefixes}) 192 endif() 193endforeach() 194 195# Cache the location of the root bindings so they can be used by 196# scripts which use the build directory. 197set(CACHED_DTS_ROOT_BINDINGS ${DTS_ROOT_BINDINGS} CACHE INTERNAL 198 "DT bindings root directories") 199 200# 201# Run the C preprocessor on the devicetree source, so we can parse it 202# (using the Python devicetree package) in later steps. 203# 204 205# TODO: Cut down on CMake configuration time by avoiding 206# regeneration of devicetree_generated.h on every configure. How 207# challenging is this? Can we cache the dts dependencies? 208 209# Run the preprocessor on the DTS input files. 210if(DEFINED CMAKE_DTS_PREPROCESSOR) 211 set(dts_preprocessor ${CMAKE_DTS_PREPROCESSOR}) 212else() 213 set(dts_preprocessor ${CMAKE_C_COMPILER}) 214endif() 215zephyr_dt_preprocess( 216 CPP ${dts_preprocessor} 217 SOURCE_FILES ${dts_files} 218 OUT_FILE ${DTS_POST_CPP} 219 DEPS_FILE ${DTS_DEPS} 220 EXTRA_CPPFLAGS ${DTS_EXTRA_CPPFLAGS} 221 INCLUDE_DIRECTORIES ${DTS_ROOT_SYSTEM_INCLUDE_DIRS} 222 WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} 223 ) 224 225# 226# Make sure we re-run CMake if any devicetree sources or transitive 227# includes change. 228# 229 230# Parse the generated dependency file to find the DT sources that 231# were included, including any transitive includes. 232toolchain_parse_make_rule(${DTS_DEPS} 233 include_files # Output parameter 234 ) 235 236# Add the results to the list of files that, when change, force the 237# build system to re-run CMake. 238set_property(DIRECTORY APPEND PROPERTY 239 CMAKE_CONFIGURE_DEPENDS 240 ${include_files} 241 ${GEN_DEFINES_SCRIPT} 242 ${GEN_DRIVER_KCONFIG_SCRIPT} 243 ${GEN_DTS_CMAKE_SCRIPT} 244 ) 245 246# 247# Run GEN_DEFINES_SCRIPT. 248# 249 250string(REPLACE ";" " " EXTRA_DTC_FLAGS_RAW "${EXTRA_DTC_FLAGS}") 251set(CMD_GEN_DEFINES ${PYTHON_EXECUTABLE} ${GEN_DEFINES_SCRIPT} 252--dts ${DTS_POST_CPP} 253--dtc-flags '${EXTRA_DTC_FLAGS_RAW}' 254--bindings-dirs ${DTS_ROOT_BINDINGS} 255--header-out ${DEVICETREE_GENERATED_H}.new 256--dts-out ${ZEPHYR_DTS}.new # for debugging and dtc 257--edt-pickle-out ${EDT_PICKLE} 258${EXTRA_GEN_DEFINES_ARGS} 259) 260 261execute_process( 262 COMMAND ${CMD_GEN_DEFINES} 263 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 264 RESULT_VARIABLE ret 265 ) 266if(NOT "${ret}" STREQUAL "0") 267 message(STATUS "In: ${PROJECT_BINARY_DIR}, command: ${CMD_GEN_DEFINES}") 268 message(FATAL_ERROR "gen_defines.py failed with return code: ${ret}") 269else() 270 zephyr_file_copy(${ZEPHYR_DTS}.new ${ZEPHYR_DTS} ONLY_IF_DIFFERENT) 271 zephyr_file_copy(${DEVICETREE_GENERATED_H}.new ${DEVICETREE_GENERATED_H} ONLY_IF_DIFFERENT) 272 file(REMOVE ${ZEPHYR_DTS}.new ${DEVICETREE_GENERATED_H}.new) 273 message(STATUS "Generated zephyr.dts: ${ZEPHYR_DTS}") 274 message(STATUS "Generated devicetree_generated.h: ${DEVICETREE_GENERATED_H}") 275endif() 276 277# 278# Run GEN_DRIVER_KCONFIG_SCRIPT. 279# 280 281execute_process( 282 COMMAND ${PYTHON_EXECUTABLE} ${GEN_DRIVER_KCONFIG_SCRIPT} 283 --kconfig-out ${DTS_KCONFIG} 284 --bindings-dirs ${DTS_ROOT_BINDINGS} 285 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 286 RESULT_VARIABLE ret 287 ) 288if(NOT "${ret}" STREQUAL "0") 289 message(FATAL_ERROR "gen_driver_kconfig_dts.py failed with return code: ${ret}") 290endif() 291 292# 293# Run GEN_DTS_CMAKE_SCRIPT. 294# 295 296execute_process( 297 COMMAND ${PYTHON_EXECUTABLE} ${GEN_DTS_CMAKE_SCRIPT} 298 --edt-pickle ${EDT_PICKLE} 299 --cmake-out ${DTS_CMAKE} 300 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 301 RESULT_VARIABLE ret 302 ) 303if(NOT "${ret}" STREQUAL "0") 304 message(FATAL_ERROR "gen_dts_cmake.py failed with return code: ${ret}") 305else() 306 message(STATUS "Including generated dts.cmake file: ${DTS_CMAKE}") 307 include(${DTS_CMAKE}) 308endif() 309 310# 311# Run dtc if it was found. 312# 313# This is just to generate warnings and errors; we discard the output. 314# 315 316if(DTC) 317 318set(DTC_WARN_UNIT_ADDR_IF_ENABLED "") 319check_dtc_flag("-Wunique_unit_address_if_enabled" check) 320if (check) 321 set(DTC_WARN_UNIT_ADDR_IF_ENABLED "-Wunique_unit_address_if_enabled") 322endif() 323 324set(DTC_NO_WARN_UNIT_ADDR "") 325check_dtc_flag("-Wno-unique_unit_address" check) 326if (check) 327 set(DTC_NO_WARN_UNIT_ADDR "-Wno-unique_unit_address") 328endif() 329 330set(VALID_EXTRA_DTC_FLAGS "") 331foreach(extra_opt ${EXTRA_DTC_FLAGS}) 332 check_dtc_flag(${extra_opt} check) 333 if (check) 334 list(APPEND VALID_EXTRA_DTC_FLAGS ${extra_opt}) 335 endif() 336endforeach() 337set(EXTRA_DTC_FLAGS ${VALID_EXTRA_DTC_FLAGS}) 338 339execute_process( 340 COMMAND ${DTC} 341 -O dts 342 -o - # Write output to stdout, which we discard below 343 -b 0 344 -E unit_address_vs_reg 345 ${DTC_NO_WARN_UNIT_ADDR} 346 ${DTC_WARN_UNIT_ADDR_IF_ENABLED} 347 ${EXTRA_DTC_FLAGS} # User settable 348 ${ZEPHYR_DTS} 349 OUTPUT_QUIET # Discard stdout 350 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 351 RESULT_VARIABLE ret 352 ) 353 354if(NOT "${ret}" STREQUAL "0") 355 message(FATAL_ERROR "command failed with return code: ${ret}") 356endif() 357endif(DTC) 358