|  | # SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | include_guard(GLOBAL) | 
|  |  | 
|  | include(extensions) | 
|  | include(python) | 
|  | include(boards) | 
|  | include(generic_toolchain) | 
|  |  | 
|  | file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include/generated) | 
|  |  | 
|  | # Zephyr code can configure itself based on a KConfig'uration with the | 
|  | # header file autoconf.h. There exists an analogous file devicetree_unfixed.h | 
|  | # that allows configuration based on information encoded in DTS. | 
|  | # | 
|  | # Here we call on dtc, the gcc preprocessor and | 
|  | # scripts/dts/gen_defines.py to generate various DT-related files at | 
|  | # CMake configure-time. | 
|  | # | 
|  | # See the Devicetree user guide in the Zephyr documentation for details. | 
|  | set(GEN_DEFINES_SCRIPT          ${ZEPHYR_BASE}/scripts/dts/gen_defines.py) | 
|  | set(ZEPHYR_DTS                  ${PROJECT_BINARY_DIR}/zephyr.dts) | 
|  | # This contains the edtlib.EDT object created from zephyr.dts in Python's | 
|  | # pickle data marshalling format (https://docs.python.org/3/library/pickle.html) | 
|  | # | 
|  | # Its existence is an implementation detail used to speed up further | 
|  | # use of the devicetree by processes that run later on in the build, | 
|  | # and should not be made part of the documentation. | 
|  | set(EDT_PICKLE                  ${PROJECT_BINARY_DIR}/edt.pickle) | 
|  | set(DEVICETREE_UNFIXED_H        ${PROJECT_BINARY_DIR}/include/generated/devicetree_unfixed.h) | 
|  | set(DEVICE_EXTERN_H             ${PROJECT_BINARY_DIR}/include/generated/device_extern.h) | 
|  | set(DTS_POST_CPP                ${PROJECT_BINARY_DIR}/zephyr.dts.pre) | 
|  | set(DTS_DEPS                    ${PROJECT_BINARY_DIR}/zephyr.dts.d) | 
|  | # The location of a list of known vendor prefixes. | 
|  | # This is relative to each element of DTS_ROOT. | 
|  | set(VENDOR_PREFIXES             dts/bindings/vendor-prefixes.txt) | 
|  |  | 
|  | # Devicetree in CMake. | 
|  | set(DTS_CMAKE_SCRIPT            ${ZEPHYR_BASE}/scripts/dts/gen_dts_cmake.py) | 
|  | set(DTS_CMAKE                   ${PROJECT_BINARY_DIR}/dts.cmake) | 
|  |  | 
|  | set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts) | 
|  |  | 
|  | zephyr_file(APPLICATION_ROOT DTS_ROOT) | 
|  |  | 
|  | # 'DTS_ROOT' is a list of directories where a directory tree with DT | 
|  | # files may be found. It always includes the application directory, | 
|  | # the board directory, and ${ZEPHYR_BASE}. | 
|  | list(APPEND | 
|  | DTS_ROOT | 
|  | ${APPLICATION_SOURCE_DIR} | 
|  | ${BOARD_DIR} | 
|  | ${SHIELD_DIRS} | 
|  | ${ZEPHYR_BASE} | 
|  | ) | 
|  | list(REMOVE_DUPLICATES | 
|  | DTS_ROOT | 
|  | ) | 
|  |  | 
|  | # TODO: What to do about non-posix platforms where NOT CONFIG_HAS_DTS (xtensa)? | 
|  | # Drop support for NOT CONFIG_HAS_DTS perhaps? | 
|  | if(EXISTS ${DTS_SOURCE}) | 
|  | set(SUPPORTS_DTS 1) | 
|  | if(BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) | 
|  | list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) | 
|  | endif() | 
|  | else() | 
|  | set(SUPPORTS_DTS 0) | 
|  | endif() | 
|  |  | 
|  | set(dts_files | 
|  | ${DTS_SOURCE} | 
|  | ${shield_dts_files} | 
|  | ) | 
|  |  | 
|  | if(SUPPORTS_DTS) | 
|  | if(DTC_OVERLAY_FILE) | 
|  | # Convert from space-separated files into file list | 
|  | string(REPLACE " " ";" DTC_OVERLAY_FILE_RAW_LIST "${DTC_OVERLAY_FILE}") | 
|  | foreach(file ${DTC_OVERLAY_FILE_RAW_LIST}) | 
|  | file(TO_CMAKE_PATH "${file}" cmake_path_file) | 
|  | list(APPEND DTC_OVERLAY_FILE_AS_LIST ${cmake_path_file}) | 
|  | endforeach() | 
|  | list(APPEND | 
|  | dts_files | 
|  | ${DTC_OVERLAY_FILE_AS_LIST} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | set(i 0) | 
|  | unset(DTC_INCLUDE_FLAG_FOR_DTS) | 
|  | foreach(dts_file ${dts_files}) | 
|  | list(APPEND DTC_INCLUDE_FLAG_FOR_DTS | 
|  | -include ${dts_file}) | 
|  |  | 
|  | if(i EQUAL 0) | 
|  | message(STATUS "Found BOARD.dts: ${dts_file}") | 
|  | else() | 
|  | message(STATUS "Found devicetree overlay: ${dts_file}") | 
|  | endif() | 
|  |  | 
|  | math(EXPR i "${i}+1") | 
|  | endforeach() | 
|  |  | 
|  | unset(DTS_ROOT_SYSTEM_INCLUDE_DIRS) | 
|  | unset(DTS_ROOT_BINDINGS) | 
|  | foreach(dts_root ${DTS_ROOT}) | 
|  | foreach(dts_root_path | 
|  | include | 
|  | include/zephyr | 
|  | dts/common | 
|  | dts/${ARCH} | 
|  | dts | 
|  | ) | 
|  | get_filename_component(full_path ${dts_root}/${dts_root_path} REALPATH) | 
|  | if(EXISTS ${full_path}) | 
|  | list(APPEND | 
|  | DTS_ROOT_SYSTEM_INCLUDE_DIRS | 
|  | -isystem ${full_path} | 
|  | ) | 
|  | endif() | 
|  | endforeach() | 
|  |  | 
|  | set(bindings_path ${dts_root}/dts/bindings) | 
|  | if(EXISTS ${bindings_path}) | 
|  | list(APPEND | 
|  | DTS_ROOT_BINDINGS | 
|  | ${bindings_path} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | set(vendor_prefixes ${dts_root}/${VENDOR_PREFIXES}) | 
|  | if(EXISTS ${vendor_prefixes}) | 
|  | list(APPEND EXTRA_GEN_DEFINES_ARGS --vendor-prefixes ${vendor_prefixes}) | 
|  | endif() | 
|  | endforeach() | 
|  |  | 
|  | # Cache the location of the root bindings so they can be used by | 
|  | # scripts which use the build directory. | 
|  | set(CACHED_DTS_ROOT_BINDINGS ${DTS_ROOT_BINDINGS} CACHE INTERNAL | 
|  | "DT bindings root directories") | 
|  |  | 
|  | if(NOT DEFINED CMAKE_DTS_PREPROCESSOR) | 
|  | set(CMAKE_DTS_PREPROCESSOR ${CMAKE_C_COMPILER}) | 
|  | endif() | 
|  |  | 
|  | # TODO: Cut down on CMake configuration time by avoiding | 
|  | # regeneration of devicetree_unfixed.h on every configure. How | 
|  | # challenging is this? What are the dts dependencies? We run the | 
|  | # preprocessor, and it seems to be including all kinds of | 
|  | # directories with who-knows how many header files. | 
|  |  | 
|  | # Run the preprocessor on the DTS input files. We are leaving | 
|  | # linemarker directives enabled on purpose. This tells dtlib where | 
|  | # each line actually came from, which improves error reporting. | 
|  | execute_process( | 
|  | COMMAND ${CMAKE_DTS_PREPROCESSOR} | 
|  | -x assembler-with-cpp | 
|  | -nostdinc | 
|  | ${DTS_ROOT_SYSTEM_INCLUDE_DIRS} | 
|  | ${DTC_INCLUDE_FLAG_FOR_DTS}  # include the DTS source and overlays | 
|  | ${NOSYSDEF_CFLAG} | 
|  | -D__DTS__ | 
|  | ${DTS_EXTRA_CPPFLAGS} | 
|  | -E   # Stop after preprocessing | 
|  | -MD  # Generate a dependency file as a side-effect | 
|  | -MF ${DTS_DEPS} | 
|  | -o ${DTS_POST_CPP} | 
|  | ${ZEPHYR_BASE}/misc/empty_file.c | 
|  | WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} | 
|  | RESULT_VARIABLE ret | 
|  | ) | 
|  | if(NOT "${ret}" STREQUAL "0") | 
|  | message(FATAL_ERROR "command failed with return code: ${ret}") | 
|  | endif() | 
|  |  | 
|  | # Parse the generated dependency file to find the DT sources that | 
|  | # were included, including any transitive includes, and then add | 
|  | # them to the list of files that trigger a re-run of CMake. | 
|  | toolchain_parse_make_rule(${DTS_DEPS} | 
|  | include_files # Output parameter | 
|  | ) | 
|  |  | 
|  | set_property(DIRECTORY APPEND PROPERTY | 
|  | CMAKE_CONFIGURE_DEPENDS | 
|  | ${include_files} | 
|  | ${GEN_DEFINES_SCRIPT} | 
|  | ${DTS_CMAKE_SCRIPT} | 
|  | ) | 
|  |  | 
|  | # | 
|  | # Run gen_defines.py to create a header file, zephyr.dts, and edt.pickle. | 
|  | # | 
|  |  | 
|  | string(REPLACE ";" " " EXTRA_DTC_FLAGS_RAW "${EXTRA_DTC_FLAGS}") | 
|  | set(CMD_EXTRACT ${PYTHON_EXECUTABLE} ${GEN_DEFINES_SCRIPT} | 
|  | --dts ${DTS_POST_CPP} | 
|  | --dtc-flags '${EXTRA_DTC_FLAGS_RAW}' | 
|  | --bindings-dirs ${DTS_ROOT_BINDINGS} | 
|  | --header-out ${DEVICETREE_UNFIXED_H}.new | 
|  | --device-header-out ${DEVICE_EXTERN_H}.new | 
|  | --dts-out ${ZEPHYR_DTS}.new # for debugging and dtc | 
|  | --edt-pickle-out ${EDT_PICKLE} | 
|  | ${EXTRA_GEN_DEFINES_ARGS} | 
|  | ) | 
|  |  | 
|  | execute_process( | 
|  | COMMAND ${CMD_EXTRACT} | 
|  | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} | 
|  | RESULT_VARIABLE ret | 
|  | ) | 
|  | if(NOT "${ret}" STREQUAL "0") | 
|  | message(FATAL_ERROR "gen_defines.py failed with return code: ${ret}") | 
|  | else() | 
|  | zephyr_file_copy(${ZEPHYR_DTS}.new ${ZEPHYR_DTS} ONLY_IF_DIFFERENT) | 
|  | zephyr_file_copy(${DEVICETREE_UNFIXED_H}.new ${DEVICETREE_UNFIXED_H} ONLY_IF_DIFFERENT) | 
|  | zephyr_file_copy(${DEVICE_EXTERN_H}.new ${DEVICE_EXTERN_H}) | 
|  | file(REMOVE ${ZEPHYR_DTS}.new ${DEVICETREE_UNFIXED_H}.new ${DEVICE_EXTERN_H}.new) | 
|  | message(STATUS "Generated zephyr.dts: ${ZEPHYR_DTS}") | 
|  | message(STATUS "Generated devicetree_unfixed.h: ${DEVICETREE_UNFIXED_H}") | 
|  | message(STATUS "Generated device_extern.h: ${DEVICE_EXTERN_H}") | 
|  | endif() | 
|  |  | 
|  | execute_process( | 
|  | COMMAND ${PYTHON_EXECUTABLE} ${DTS_CMAKE_SCRIPT} | 
|  | --edt-pickle ${EDT_PICKLE} | 
|  | --cmake-out ${DTS_CMAKE} | 
|  | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} | 
|  | RESULT_VARIABLE ret | 
|  | ) | 
|  | if(NOT "${ret}" STREQUAL "0") | 
|  | message(FATAL_ERROR "gen_dts_cmake.py failed with return code: ${ret}") | 
|  | else() | 
|  | message(STATUS "Including generated dts.cmake file: ${DTS_CMAKE}") | 
|  | include(${DTS_CMAKE}) | 
|  | endif() | 
|  |  | 
|  | # | 
|  | # Run dtc on the final devicetree source, just to catch any | 
|  | # warnings/errors from it. dtlib and edtlib parse the devicetree files | 
|  | # themselves, so we don't rely on dtc otherwise. | 
|  | # | 
|  |  | 
|  | if(DTC) | 
|  | set(DTC_WARN_UNIT_ADDR_IF_ENABLED "") | 
|  | check_dtc_flag("-Wunique_unit_address_if_enabled" check) | 
|  | if (check) | 
|  | set(DTC_WARN_UNIT_ADDR_IF_ENABLED "-Wunique_unit_address_if_enabled") | 
|  | endif() | 
|  | set(DTC_NO_WARN_UNIT_ADDR "") | 
|  | check_dtc_flag("-Wno-unique_unit_address" check) | 
|  | if (check) | 
|  | set(DTC_NO_WARN_UNIT_ADDR "-Wno-unique_unit_address") | 
|  | endif() | 
|  | set(VALID_EXTRA_DTC_FLAGS "") | 
|  | foreach(extra_opt ${EXTRA_DTC_FLAGS}) | 
|  | check_dtc_flag(${extra_opt} check) | 
|  | if (check) | 
|  | list(APPEND VALID_EXTRA_DTC_FLAGS ${extra_opt}) | 
|  | endif() | 
|  | endforeach() | 
|  | set(EXTRA_DTC_FLAGS ${VALID_EXTRA_DTC_FLAGS}) | 
|  | execute_process( | 
|  | COMMAND ${DTC} | 
|  | -O dts | 
|  | -o - # Write output to stdout, which we discard below | 
|  | -b 0 | 
|  | -E unit_address_vs_reg | 
|  | ${DTC_NO_WARN_UNIT_ADDR} | 
|  | ${DTC_WARN_UNIT_ADDR_IF_ENABLED} | 
|  | ${EXTRA_DTC_FLAGS} # User settable | 
|  | ${ZEPHYR_DTS} | 
|  | OUTPUT_QUIET # Discard stdout | 
|  | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} | 
|  | RESULT_VARIABLE ret | 
|  | ) | 
|  | if(NOT "${ret}" STREQUAL "0") | 
|  | message(FATAL_ERROR "command failed with return code: ${ret}") | 
|  | endif() | 
|  | endif(DTC) | 
|  | else() | 
|  | set(header_template ${ZEPHYR_BASE}/misc/generated/generated_header.template) | 
|  | zephyr_file_copy(${header_template} ${DEVICETREE_UNFIXED_H} ONLY_IF_DIFFERENT) | 
|  | zephyr_file_copy(${header_template} ${DEVICE_EXTERN_H} ONLY_IF_DIFFERENT) | 
|  | endif(SUPPORTS_DTS) |