zephyr/cmake/dts.cmake

276 lines
8.9 KiB
CMake
Raw Normal View History

# SPDX-License-Identifier: Apache-2.0
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}/${BOARD}.dts.pre.tmp)
# 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)
cmake: support versioning of board This commit introduces support for versioning of boards. The existing board handling is limited in such a way that it is not possible to support a specific board in multiple variants. This commit introduces versioning of board revisions so that it is possible to support minor variations to a board without having to defining a completely new board. This can be done by adding a revision.cmake file in the board folder: boards/<arch>/<board-dir>/revision.cmake Depending on the revision format chosen, additional configuration files for each revision available must also be added, those have the form: boards/<arch>/<board-dir>/<board>_<revision>.conf Examples: boards/<arch>/<board-dir>/<board>_defconfig: Common board settings Revision format: MAJOR.MINOR.PATCH boards/<arch>/<board-dir>/<board>_0_5_0.conf: Revision 0.5.0 boards/<arch>/<board-dir>/<board>_1_0_0.conf: Revision 1.0.0 boards/<arch>/<board-dir>/<board>_1_5_0.conf: Revision 1.5.0 Revision format: LETTER boards/<arch>/<board-dir>/<board>_A.conf: Revision A boards/<arch>/<board-dir>/<board>_B.conf: Revision B The `board_check_revision` function is available in `extensions.cmake` to facilitate board revision handling in `revision.cmake`. User select the board revision using: `-DBOARD=<board>@<revision>`, as example `-DBOARD=plank@0.5.0`. If a shield, test, sample, or application needs to specify DTS overlay or Kconfig fragments, this can be done by adding revision specific configuration files in the sample/test/shield folder, like this: <shield/sample-path>/boards/<board>.conf <shield/sample-path>/boards/<board>_<revision>.conf or if there is there is only a need for adjusting on a given board revision: <shield/sample-path>/boards/<board>_<revision>.conf Similar for DTS overlay files: <shield-path>/boards/<board>.overlay <shield-path>/boards/<board>_<revision>.overlay or: <shield-path>/boards/<board>_<revision>.conf For test/samples/apps: <sample-path>/<board>.overlay <sample-path>/<board>_<revision>.overlay or: <sample-path>/<board>_<revision>.overlay Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no> Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-11-11 17:10:41 +08:00
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()
cmake: support versioning of board This commit introduces support for versioning of boards. The existing board handling is limited in such a way that it is not possible to support a specific board in multiple variants. This commit introduces versioning of board revisions so that it is possible to support minor variations to a board without having to defining a completely new board. This can be done by adding a revision.cmake file in the board folder: boards/<arch>/<board-dir>/revision.cmake Depending on the revision format chosen, additional configuration files for each revision available must also be added, those have the form: boards/<arch>/<board-dir>/<board>_<revision>.conf Examples: boards/<arch>/<board-dir>/<board>_defconfig: Common board settings Revision format: MAJOR.MINOR.PATCH boards/<arch>/<board-dir>/<board>_0_5_0.conf: Revision 0.5.0 boards/<arch>/<board-dir>/<board>_1_0_0.conf: Revision 1.0.0 boards/<arch>/<board-dir>/<board>_1_5_0.conf: Revision 1.5.0 Revision format: LETTER boards/<arch>/<board-dir>/<board>_A.conf: Revision A boards/<arch>/<board-dir>/<board>_B.conf: Revision B The `board_check_revision` function is available in `extensions.cmake` to facilitate board revision handling in `revision.cmake`. User select the board revision using: `-DBOARD=<board>@<revision>`, as example `-DBOARD=plank@0.5.0`. If a shield, test, sample, or application needs to specify DTS overlay or Kconfig fragments, this can be done by adding revision specific configuration files in the sample/test/shield folder, like this: <shield/sample-path>/boards/<board>.conf <shield/sample-path>/boards/<board>_<revision>.conf or if there is there is only a need for adjusting on a given board revision: <shield/sample-path>/boards/<board>_<revision>.conf Similar for DTS overlay files: <shield-path>/boards/<board>.overlay <shield-path>/boards/<board>_<revision>.overlay or: <shield-path>/boards/<board>_<revision>.conf For test/samples/apps: <sample-path>/<board>.overlay <sample-path>/<board>_<revision>.overlay or: <sample-path>/<board>_<revision>.overlay Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no> Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-11-11 17:10:41 +08:00
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
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 C preprocessor on an empty C source file that has one or
# more DTS source files -include'd into it to create the
# intermediary file *.dts.pre.tmp. Also, generate a dependency file
# so that changes to DT sources are detected.
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}
-P
-E # Stop after preprocessing
-MD # Generate a dependency file as a side-effect
-MF ${PROJECT_BINARY_DIR}/${BOARD}.dts.pre.d
-o ${PROJECT_BINARY_DIR}/${BOARD}.dts.pre.tmp
${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 and then add them to the list of files that trigger
# a re-run of CMake.
toolchain_parse_make_rule(
${PROJECT_BINARY_DIR}/${BOARD}.dts.pre.d
include_files # Output parameter
)
set_property(DIRECTORY APPEND PROPERTY
CMAKE_CONFIGURE_DEPENDS
${include_files}
${GEN_DEFINES_SCRIPT}
${DTS_CMAKE_SCRIPT}
)
#
# Run the C devicetree compiler on *.dts.pre.tmp, just to catch any
# warnings/errors from it. dtlib and edtlib parse the devicetree files
# themselves, so we don't rely on the C compiler 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
${BOARD}.dts.pre.tmp
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)
dts: Add new DTS/binding parser Add a new DTS/binding parser to scripts/dts/ for generating generated_dts_board.conf and generated_dts_board_unfixed.h. The old code is kept to generate some deprecated defines, using the --deprecated-only flag. It will be removed later. The new parser is implemented in three files in scripts/dts/: dtlib.py: A low-level .dts parsing library. This is similar to devicetree.py in the old code, but is a general robust DTS parser that doesn't rely on preprocessing. edtlib.py (e for extended): A library built on top of dtlib.py that brings together data from DTS files and bindings and creates Device instances with all the data for a device. gen_defines.py: A script that uses edtlib.py to generate generated_dts_board.conf and generated_dts_board_unfixed.h. Corresponds to extract_dts_includes.py and the files in extract/ in the old code. testdtlib.py: Test suite for dtlib.py. Can be run directly as a script. testedtlib.py (uses test.dts and test-bindings/): Test suite for edtlib.py. Can be run directly as a script. The test suites will be run automatically in CI. The new code turns some things that were warnings (or not checked) in the old code into errors, like missing properties that are specified with 'category: required' in the binding for the node. The code includes lots of documentation and tries to give helpful error messages instead of Python errors. Co-authored-by: Kumar Gala <kumar.gala@linaro.org> Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2018-12-18 03:09:47 +08:00
#
# Run gen_defines.py to create a header file, zephyr.dts, and edt.pickle.
dts: Add new DTS/binding parser Add a new DTS/binding parser to scripts/dts/ for generating generated_dts_board.conf and generated_dts_board_unfixed.h. The old code is kept to generate some deprecated defines, using the --deprecated-only flag. It will be removed later. The new parser is implemented in three files in scripts/dts/: dtlib.py: A low-level .dts parsing library. This is similar to devicetree.py in the old code, but is a general robust DTS parser that doesn't rely on preprocessing. edtlib.py (e for extended): A library built on top of dtlib.py that brings together data from DTS files and bindings and creates Device instances with all the data for a device. gen_defines.py: A script that uses edtlib.py to generate generated_dts_board.conf and generated_dts_board_unfixed.h. Corresponds to extract_dts_includes.py and the files in extract/ in the old code. testdtlib.py: Test suite for dtlib.py. Can be run directly as a script. testedtlib.py (uses test.dts and test-bindings/): Test suite for edtlib.py. Can be run directly as a script. The test suites will be run automatically in CI. The new code turns some things that were warnings (or not checked) in the old code into errors, like missing properties that are specified with 'category: required' in the binding for the node. The code includes lots of documentation and tries to give helpful error messages instead of Python errors. Co-authored-by: Kumar Gala <kumar.gala@linaro.org> Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2018-12-18 03:09:47 +08:00
#
string(REPLACE ";" " " EXTRA_DTC_FLAGS_RAW "${EXTRA_DTC_FLAGS}")
set(CMD_EXTRACT ${PYTHON_EXECUTABLE} ${GEN_DEFINES_SCRIPT}
dts: Add new DTS/binding parser Add a new DTS/binding parser to scripts/dts/ for generating generated_dts_board.conf and generated_dts_board_unfixed.h. The old code is kept to generate some deprecated defines, using the --deprecated-only flag. It will be removed later. The new parser is implemented in three files in scripts/dts/: dtlib.py: A low-level .dts parsing library. This is similar to devicetree.py in the old code, but is a general robust DTS parser that doesn't rely on preprocessing. edtlib.py (e for extended): A library built on top of dtlib.py that brings together data from DTS files and bindings and creates Device instances with all the data for a device. gen_defines.py: A script that uses edtlib.py to generate generated_dts_board.conf and generated_dts_board_unfixed.h. Corresponds to extract_dts_includes.py and the files in extract/ in the old code. testdtlib.py: Test suite for dtlib.py. Can be run directly as a script. testedtlib.py (uses test.dts and test-bindings/): Test suite for edtlib.py. Can be run directly as a script. The test suites will be run automatically in CI. The new code turns some things that were warnings (or not checked) in the old code into errors, like missing properties that are specified with 'category: required' in the binding for the node. The code includes lots of documentation and tries to give helpful error messages instead of Python errors. Co-authored-by: Kumar Gala <kumar.gala@linaro.org> Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2018-12-18 03:09:47 +08:00
--dts ${BOARD}.dts.pre.tmp
--dtc-flags '${EXTRA_DTC_FLAGS_RAW}'
--bindings-dirs ${DTS_ROOT_BINDINGS}
--header-out ${DEVICETREE_UNFIXED_H}
--device-header-out ${DEVICE_EXTERN_H}
--dts-out ${ZEPHYR_DTS} # As a debugging aid
--edt-pickle-out ${EDT_PICKLE}
${EXTRA_GEN_DEFINES_ARGS}
)
dts: Add new DTS/binding parser Add a new DTS/binding parser to scripts/dts/ for generating generated_dts_board.conf and generated_dts_board_unfixed.h. The old code is kept to generate some deprecated defines, using the --deprecated-only flag. It will be removed later. The new parser is implemented in three files in scripts/dts/: dtlib.py: A low-level .dts parsing library. This is similar to devicetree.py in the old code, but is a general robust DTS parser that doesn't rely on preprocessing. edtlib.py (e for extended): A library built on top of dtlib.py that brings together data from DTS files and bindings and creates Device instances with all the data for a device. gen_defines.py: A script that uses edtlib.py to generate generated_dts_board.conf and generated_dts_board_unfixed.h. Corresponds to extract_dts_includes.py and the files in extract/ in the old code. testdtlib.py: Test suite for dtlib.py. Can be run directly as a script. testedtlib.py (uses test.dts and test-bindings/): Test suite for edtlib.py. Can be run directly as a script. The test suites will be run automatically in CI. The new code turns some things that were warnings (or not checked) in the old code into errors, like missing properties that are specified with 'category: required' in the binding for the node. The code includes lots of documentation and tries to give helpful error messages instead of Python errors. Co-authored-by: Kumar Gala <kumar.gala@linaro.org> Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2018-12-18 03:09:47 +08:00
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()
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()
else()
file(WRITE ${DEVICETREE_UNFIXED_H} "/* WARNING. THIS FILE IS AUTO-GENERATED. DO NOT MODIFY! */")
file(WRITE ${DEVICE_EXTERN_H} "/* WARNING. THIS FILE IS AUTO-GENERATED. DO NOT MODIFY! */")
endif(SUPPORTS_DTS)