diff --git a/CMakeLists.txt b/CMakeLists.txt index 226d834181bc..7e5fee294703 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,7 +336,7 @@ add_subdirectory(misc) # property which is set implicitly for custom command outputs include(misc/generated/CMakeLists.txt) -if(EXISTS soc/${ARCH}/CMakeLists.txt) +if(EXISTS ${ZEPHYR_BASE}/soc/${ARCH}/CMakeLists.txt) add_subdirectory(${SOC_DIR}/${ARCH} soc/${ARCH}) else() add_subdirectory(${SOC_DIR}/${ARCH}/${SOC_PATH} soc/${ARCH}/${SOC_PATH}) @@ -348,6 +348,13 @@ add_subdirectory(subsys) add_subdirectory(drivers) add_subdirectory(tests) +# Add all generated zephyr sources in the same context as the zephyr library +# is created. Assure all sub directories that might invoke code generation +# are processed before. +get_property(zephyr_generated_sources GLOBAL PROPERTY zephyr_generated_sources_property) +set_source_files_properties(${zephyr_generated_sources} PROPERTIES GENERATED 1) +target_sources(zephyr PRIVATE ${zephyr_generated_sources}) + set(syscall_macros_h ${ZEPHYR_BINARY_DIR}/include/generated/syscall_macros.h) add_custom_target(syscall_macros_h_target DEPENDS ${syscall_macros_h}) diff --git a/cmake/dts.cmake b/cmake/dts.cmake index f4cf47100539..a67df33d9ae1 100644 --- a/cmake/dts.cmake +++ b/cmake/dts.cmake @@ -10,6 +10,7 @@ # See ~/zephyr/doc/dts set(GENERATED_DTS_BOARD_H ${PROJECT_BINARY_DIR}/include/generated/generated_dts_board.h) set(GENERATED_DTS_BOARD_CONF ${PROJECT_BINARY_DIR}/include/generated/generated_dts_board.conf) +set(GENERATED_EDTS ${PROJECT_BINARY_DIR}/edts.json) set_ifndef(DTS_SOURCE ${BOARD_ROOT}/boards/${ARCH}/${BOARD_FAMILY}/${BOARD}.dts) set_ifndef(DTS_COMMON_OVERLAYS ${ZEPHYR_BASE}/dts/common/common.dts) set_ifndef(DTS_APP_BINDINGS ${APPLICATION_SOURCE_DIR}/dts/bindings) @@ -113,6 +114,7 @@ if(CONFIG_HAS_DTS) ${DTS_FIXUPS} --keyvalue ${GENERATED_DTS_BOARD_CONF} --include ${GENERATED_DTS_BOARD_H} + --edts ${GENERATED_EDTS} ) # Run extract_dts_includes.py to create a .conf and a header file that can be diff --git a/cmake/extensions.cmake b/cmake/extensions.cmake index 9a9979e70ac6..8346c9e8f968 100644 --- a/cmake/extensions.cmake +++ b/cmake/extensions.cmake @@ -344,6 +344,17 @@ function(generate_inc_file_for_gen_target add_dependencies(${target} ${gen_target}) endfunction() +function(get_unique_generated_target_name + generated_file # The generated file + generated_target_name # the unique name + ) + string(RANDOM LENGTH 8 random_chars) + get_filename_component(basename ${generated_file} NAME) + string(REPLACE "." "_" basename ${basename}) + string(REPLACE "@" "_" basename ${basename}) + set(generated_target_name "gen_${basename}_${random_chars}" PARENT_SCOPE) +endfunction() + function(generate_inc_file_for_target target # The cmake target that depends on the generated file source_file # The source file to be converted to hex @@ -353,22 +364,131 @@ function(generate_inc_file_for_target # Ensure 'generated_file' is generated before 'target' by creating a # 'custom_target' for it and setting up a dependency between the two # targets + get_unique_generated_target_name(${generated_file} generated_target_name) + add_custom_target(${generated_target_name} DEPENDS ${generated_file}) + generate_inc_file_for_gen_target(${target} ${source_file} ${generated_file} + ${generated_target_name} ${ARGN}) +endfunction() - # But first create a unique name for the custom target - string( - RANDOM - LENGTH 8 - random_chars +function(target_sources_codegen + target # The cmake target that depends on the generated file ) + set(options) + set(oneValueArgs) + set(multiValueArgs CODEGEN_DEFINES DEPENDS) + cmake_parse_arguments(CODEGEN "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + # prepend -D to all defines + string(REGEX REPLACE "([^;]+)" "-D;\\1" + CODEGEN_CODEGEN_DEFINES "${CODEGEN_CODEGEN_DEFINES}") + # Get all the files that make up codegen for dependency + file(GLOB CODEGEN_SOURCES + ${ZEPHYR_BASE}/scripts/dts/edtsdatabase.py + ${ZEPHYR_BASE}/scripts/codegen/modules/*.py + ${ZEPHYR_BASE}/scripts/codegen/templates/drivers/*.py + ${ZEPHYR_BASE}/scripts/codegen/*.py + ${ZEPHYR_BASE}/scripts/gen_code.py) + + message(STATUS "Will generate for target ${target}") + # Generated file must be generated to the current binary directory. + # Otherwise this would trigger CMake issue #14633: + # https://gitlab.kitware.com/cmake/cmake/issues/14633 + foreach(arg ${CODEGEN_UNPARSED_ARGUMENTS}) + if(IS_ABSOLUTE ${arg}) + set(template_file ${arg}) + get_filename_component(generated_file_name ${arg} NAME) + set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}) + else() + set(template_file ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) + set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${arg}) + endif() + get_filename_component(template_dir ${template_file} DIRECTORY) - get_filename_component(basename ${generated_file} NAME) - string(REPLACE "." "_" basename ${basename}) - string(REPLACE "@" "_" basename ${basename}) + if(IS_DIRECTORY ${template_file}) + message(FATAL_ERROR "target_sources_codegen() was called on a directory") + endif() - set(generated_target_name "gen_${basename}_${random_chars}") + # Generate file from template + message(STATUS " from '${template_file}'") + message(STATUS " to '${generated_file}'") + add_custom_command( + COMMENT "CodeGen ${generated_file}" + OUTPUT ${generated_file} + MAIN_DEPENDENCY ${template_file} + DEPENDS + ${CODEGEN_DEPENDS} + ${CODEGEN_SOURCES} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/gen_code.py + ${CODEGEN_CODEGEN_DEFINES} + -D "PROJECT_NAME=${PROJECT_NAME}" + -D "PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}" + -D "PROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}" + -D "CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}" + -D "CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}" + -D "CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" + -D "CMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}" + -D "CMAKE_CURRENT_LIST_DIR=${CMAKE_CURRENT_LIST_DIR}" + -D "CMAKE_FILES_DIRECTORY=${CMAKE_FILES_DIRECTORY}" + -D "CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME}" + -D "CMAKE_SYSTEM=${CMAKE_SYSTEM}" + -D "CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}" + -D "CMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}" + -D "CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}" + -D "CMAKE_C_COMPILER=${CMAKE_C_COMPILER}" + -D "CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + -D "CMAKE_COMPILER_IS_GNUCC=${CMAKE_COMPILER_IS_GNUCC}" + -D "CMAKE_COMPILER_IS_GNUCXX=${CMAKE_COMPILER_IS_GNUCXX}" + -D "GENERATED_DTS_BOARD_H=${GENERATED_DTS_BOARD_H}" + -D "GENERATED_DTS_BOARD_CONF=${GENERATED_DTS_BOARD_CONF}" + -D "GENERATED_DTS_BOARD_EDTS=${GENERATED_DTS_BOARD_EDTS}" + --input "${template_file}" + --output "${generated_file}" + --log "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CodeGen.log" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + if("${target}" STREQUAL "zephyr") + # zephyr is special + get_unique_generated_target_name(${generated_file} generated_target_name) + add_custom_target(${generated_target_name} DEPENDS ${generated_file}) + add_dependencies(zephyr ${generated_target_name}) + # Remember all the files that are generated for zephyr. + # target_sources(zephyr PRIVATE ${zephyr_generated_sources}) + # is executed in the top level CMakeFile.txt context. + get_property(zephyr_generated_sources GLOBAL PROPERTY zephyr_generated_sources_property) + list(APPEND zephyr_generated_sources ${generated_file}) + set_property(GLOBAL PROPERTY zephyr_generated_sources_property "${zephyr_generated_sources}") + # Add template directory to include path to allow includes with + # relative path in generated file to work + zephyr_include_directories(${template_dir}) + else() + target_sources(${target} PRIVATE ${generated_file}) + # Add template directory to include path to allow includes with + # relative path in generated file to work + target_include_directories(${target} PRIVATE ${template_dir}) + endif() + endforeach() +endfunction() - add_custom_target(${generated_target_name} DEPENDS ${generated_file}) - generate_inc_file_for_gen_target(${target} ${source_file} ${generated_file} ${generated_target_name} ${ARGN}) +function(zephyr_sources_codegen) + target_sources_codegen(zephyr ${ARGN}) +endfunction() + +function(zephyr_sources_codegen_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_sources_codegen(${ARGN}) + endif() +endfunction() + +function(zephyr_library_sources_codegen) + target_sources_codegen(${ZEPHYR_CURRENT_LIBRARY} ${ARGN}) +endfunction() + +function(zephyr_library_sources_codegen_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_library_sources_codegen(${ARGN}) + endif() endfunction() # 1.2 zephyr_library_* @@ -424,6 +544,13 @@ macro(zephyr_library_named name) # This is a macro because we need add_library() to be executed # within the scope of the caller. set(ZEPHYR_CURRENT_LIBRARY ${name}) + + if("${name}" STREQUAL "zephyr") + # We have to mark all the generated files "GENERATED" in this context + get_property(zephyr_generated_files GLOBAL PROPERTY zephyr_generated_files_property) + set_source_files_properties(${zephyr_generated_files} PROPERTIES GENERATED 1) + endif() + add_library(${name} STATIC "") zephyr_append_cmake_library(${name}) diff --git a/doc/contribute/contribute_guidelines.rst b/doc/contribute/contribute_guidelines.rst index c362bb3a05d0..d044cc556059 100644 --- a/doc/contribute/contribute_guidelines.rst +++ b/doc/contribute/contribute_guidelines.rst @@ -326,8 +326,11 @@ On Linux systems, you can install uncrustify with For Windows installation instructions see the `sourceforge listing for uncrustify `_. +Best coding practises +********************* + Coding Style -************ +============ Use these coding guidelines to ensure that your development complies with the project's style and naming conventions. @@ -363,6 +366,25 @@ it to contain: set -e exec exec git diff --cached | ${ZEPHYR_BASE}/scripts/checkpatch.pl - +Keep the code simple +==================== + +Keep the code as simple as possible. + +Code-generation preprocessing tools provide a convenient way to +simplify some repetitive or parameterized coding tasks. While Zephyr +development allows use of such tools, we recommend keeping this +use to a minimum and when it provides an appropriate and simple +coding solution that follows these rules: + +* Use code generation - by preprocessor, :ref:`codegen`, or other - only for + problems that cannot be solved in the source language. +* Limit code generation to declarative data. Avoid generating control logic + whenever possible. +* Use the preprocessor for code generation as the primary tool. +* Use :ref:`codegen` only if the preprocessor can not provide a simple solution. +* Use CMake only if :ref:`codegen` can not be used. + .. _Contribution workflow: Contribution Workflow diff --git a/doc/subsystems/codegen/build.rst b/doc/subsystems/codegen/build.rst new file mode 100644 index 000000000000..4ecc1ccf359b --- /dev/null +++ b/doc/subsystems/codegen/build.rst @@ -0,0 +1,29 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_build: + +Code Generation in the Build Process +#################################### + +Code generation has to be invoked as part of the build process. Zephyr uses +`CMake `_ as the tool to manage building the project. + +A file that contains inline code generation has to be added to the project +by one of the following commands in a :file:`CMakeList.txt` file. + +.. function:: zephyr_sources_codegen(codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +.. function:: zephyr_sources_codegen_ifdef(ifguard codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +.. function:: zephyr_library_sources_codegen(codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +.. function:: zephyr_library_sources_codegen_ifdef(ifguard codegen_file.c [CODEGEN_DEFINES defines..] [DEPENDS target.. file..]) + +The arguments given by the ``CODEGEN_DEFINES`` keyword have to be of the form +``define_name=define_value``. The arguments become globals in the python +snippets and can be accessed by ``define_name``. + +Dependencies given by the ``DEPENDS`` key word are added to the dependencies +of the generated file. diff --git a/doc/subsystems/codegen/codegen.rst b/doc/subsystems/codegen/codegen.rst new file mode 100644 index 000000000000..cc7b1bb3eed3 --- /dev/null +++ b/doc/subsystems/codegen/codegen.rst @@ -0,0 +1,90 @@ +.. + Copyright (c) 2004-2015 Ned Batchelder + SPDX-License-Identifier: MIT + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_intro: + +Introduction +############ + +Python snippets that are inlined in a source file are used as code generators. +The tool to scan the source file for the Python snippets and process them is +Codegen. Codegen and part of this documentation is based on +`Cog `_ from Ned Batchelder. + +The processing of source files is controlled by the CMake extension functions: +zephyr_sources_codegen(..) or zephyr_library_sources_codegen(..). The generated +source files are added to the Zephyr sources. During build the source files are +processed by Codegen and the generated source files are written to the CMake +binary directory. + +The inlined Python snippets can contain any Python code, they are regular +Python scripts. All Python snippets in a source file and all Python snippets of +included template files are treated as a python script with a common set of +global Python variables. Global data created in one snippet can be used in +another snippet that is processed later on. This feature could be used, for +example, to customize included template files. + +An inlined Python snippet can always access the codegen module. The codegen +module encapsulates and provides all the functions to retrieve information +(options, device tree properties, CMake variables, config properties) and to +output the generated code. + +Codegen transforms files in a very simple way: it finds chunks of Python code +embedded in them, executes the Python code, and places its output combined with +the original file into the generated file. The original file can contain +whatever text you like around the Python code. It will usually be source code. + +For example, if you run this file through Codegen: + +:: + + /* This is my C file. */ + ... + /** + * @code{.codegen} + * fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] + * for fn in fnames: + * codegen.outl("void %s();" % fn) + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ + ... + +it will come out like this: + +:: + + /* This is my C file. */ + ... + /** + * @code{.codegen} + * fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] + * for fn in fnames: + * codegen.outl("void %s();" % fn) + * @endcode{.codegen} + */ + void DoSomething(); + void DoAnotherThing(); + void DoLastThing(); + /** @code{.codeins}@endcode */ + ... + +Lines with ``@code{.codegen}`` or ``@code{.codeins}@endcode`` are marker lines. +The lines between ``@code{.codegen}`` and ``@endcode{.codegen}`` are the +generator Python code. The lines between ``@endcode{.codegen}`` and +``@code{.codeins}@endcode`` are the output from the generator. + +When Codegen runs, it discards the last generated Python output, executes the +generator Python code, and writes its generated output into the file. All text +lines outside of the special markers are passed through unchanged. + +The Codegen marker lines can contain any text in addition to the marker tokens. +This makes it possible to hide the generator Python code from the source file. + +In the sample above, the entire chunk of Python code is a C comment, so the +Python code can be left in place while the file is treated as C code. + + diff --git a/doc/subsystems/codegen/codegen_principle.png b/doc/subsystems/codegen/codegen_principle.png new file mode 100644 index 000000000000..b1f340731f3a Binary files /dev/null and b/doc/subsystems/codegen/codegen_principle.png differ diff --git a/doc/subsystems/codegen/codegen_principle_access.png b/doc/subsystems/codegen/codegen_principle_access.png new file mode 100644 index 000000000000..e0319d463cd8 Binary files /dev/null and b/doc/subsystems/codegen/codegen_principle_access.png differ diff --git a/doc/subsystems/codegen/codegen_principle_import.png b/doc/subsystems/codegen/codegen_principle_import.png new file mode 100644 index 000000000000..e8c681833a0b Binary files /dev/null and b/doc/subsystems/codegen/codegen_principle_import.png differ diff --git a/doc/subsystems/codegen/codegen_principle_include.png b/doc/subsystems/codegen/codegen_principle_include.png new file mode 100644 index 000000000000..1b58b41dd009 Binary files /dev/null and b/doc/subsystems/codegen/codegen_principle_include.png differ diff --git a/doc/subsystems/codegen/functions.rst b/doc/subsystems/codegen/functions.rst new file mode 100644 index 000000000000..45b56c1ab39e --- /dev/null +++ b/doc/subsystems/codegen/functions.rst @@ -0,0 +1,216 @@ +.. + Copyright (c) 2004-2015 Ned Batchelder + SPDX-License-Identifier: MIT + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_functions: + +Code Generation Functions +######################### + +A module called ``codegen`` provides the core functions for inline +code generation. It encapsulates all the functions to retrieve information +(options, device tree properties, CMake variables, config properties) and +to output the generated code. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +The ``codegen`` module is automatically imported by all code snippets. No +explicit import is necessary. + +Output +------ + +.. function:: codegen.out(sOut=’’ [, dedent=False][, trimblanklines=False]) + + Writes text to the output. + + :param sOut: The string to write to the output. + :param dedent: If dedent is True, then common initial white space is + removed from the lines in sOut before adding them to the + output. + :param trimblanklines: If trimblanklines is True, + then an initial and trailing blank line are removed + from sOut before adding them to the output. + + ``dedent`` and ``trimblanklines`` make it easier to use + multi-line strings, and they are only are useful for multi-line strings: + + :: + + codegen.out(""" + These are lines I + want to write into my source file. + """, dedent=True, trimblanklines=True) + +.. function:: codegen.outl + + Same as codegen.out, but adds a trailing newline. + +.. attribute:: codegen.inFile + + An attribute, the path of the input file. + +.. attribute:: codegen.outFile + + An attribute, the path of the output file. + +.. attribute:: codegen.firstLineNum + + An attribute, the line number of the first line of Python code in the + generator. This can be used to distinguish between two generators in the + same input file, if needed. + +.. attribute:: codegen.previous + + An attribute, the text output of the previous run of this generator. This + can be used for whatever purpose you like, including outputting again with + codegen.out() + +The codegen module also provides a set of convenience functions: + + +Code generation module import +----------------------------- + +.. function:: codegen.module_import(module_name) + + Import a module from the codegen/modules package. + + After import the module's functions and variables can be accessed by + module_name.func() and module_name.var. + + :param module_name: Module to import. Specified without any path. + + See :ref:`codegen_modules` for the available modules. + +Template file inclusion +----------------------- + +.. function:: codegen.out_include(include_file) + + Write the text from include_file to the output. The :file:`include_file` + is processed by Codegen. Inline code generation in ``include_file`` + can access the globals defined in the ``including source file`` before + inclusion. The ``including source file`` can access the globals defined in + the ``include_file`` (after inclusion). + + :param include_file: path of include file, either absolute path or relative + to current directory or relative to templates directory + (e.g. 'templates/drivers/simple_tmpl.c') + + See :ref:`codegen_templates` for the templates in the Codegen templates + folders. + +.. function:: codegen.guard_include() + + Prevent the current file to be included by ``codegen.out_include()`` + when called the next time. + +Configuration property access +----------------------------- + +.. function:: codegen.config_property(property_name [, default=""]) + + Get the value of a configuration property from :file:`autoconf.h`. If + ``property_name`` is not given in :file:`autoconf.h` the default value is + returned. + +CMake variable access +--------------------- + +.. function:: codegen.cmake_variable(variable_name [, default=""]) + + Get the value of a CMake variable. If variable_name is not provided to + Codegen by CMake the default value is returned. The following variables + are provided to Codegen: + + - "PROJECT_NAME" + - "PROJECT_SOURCE_DIR" + - "PROJECT_BINARY_DIR" + - "CMAKE_SOURCE_DIR" + - "CMAKE_BINARY_DIR" + - "CMAKE_CURRENT_SOURCE_DIR" + - "CMAKE_CURRENT_BINARY_DIR" + - "CMAKE_CURRENT_LIST_DIR" + - "CMAKE_FILES_DIRECTORY" + - "CMAKE_PROJECT_NAME" + - "CMAKE_SYSTEM" + - "CMAKE_SYSTEM_NAME" + - "CMAKE_SYSTEM_VERSION" + - "CMAKE_SYSTEM_PROCESSOR" + - "CMAKE_C_COMPILER" + - "CMAKE_CXX_COMPILER" + - "CMAKE_COMPILER_IS_GNUCC" + - "CMAKE_COMPILER_IS_GNUCXX" + - "GENERATED_DTS_BOARD_H" + - "GENERATED_DTS_BOARD_CONF" + +.. function:: codegen.cmake_cache_variable(variable_name [, default=""]) + + Get the value of a CMake variable from CMakeCache.txt. If variable_name + is not given in CMakeCache.txt the default value is returned. + +Extended device tree database access +------------------------------------ + +.. function:: codegen.edts() + + Get the extended device tree database. + + :return: extended device tree database + +Guarding chunks of source code +------------------------------ + +.. function:: codegen.outl_guard_config(property_name) + + Write a guard (#if [guard]) C preprocessor directive to output. + + If there is a configuration property of the given name the property value + is used as guard value, otherwise it is set to 0. + + :param property_name: Name of the configuration property. + +.. function:: codegen.outl_unguard_config(property_name) + + Write an unguard (#endif) C preprocessor directive to output. + + This is the closing command for codegen.outl_guard_config(). + + :param property_name: Name of the configuration property. + +Error handling +-------------- + +.. function:: codegen.error(msg='Error raised by codegen.' [, frame_index=0] [, snippet_lineno=0]) + + Raise a codegen.Error exception. + + Instead of raising standard python errors, codegen generators can use + this function. Extra information is added that maps the python snippet + line seen by the Python interpreter to the line of the file that inlines + the python snippet. + + :param msg: Exception message. + :param frame_index: Call frame index. The call frame offset of the function + calling codegen.error(). Zero if directly called in a + snippet. Add one for every level of function call. + :param snippet_lineno: Line number within snippet. + +Logging +------- + +.. function:: codegen.log(message [, message_type=None] [, end="\n"] [, logonly=True]) + +.. function:: codegen.msg(msg) + + Prints msg to stdout with a “Message: ” prefix. + +.. function:: codegen.prout(s [, end="\n"]) + +.. function:: codegen.prerr(s [, end="\n"]) diff --git a/doc/subsystems/codegen/index.rst b/doc/subsystems/codegen/index.rst new file mode 100644 index 000000000000..129749e02530 --- /dev/null +++ b/doc/subsystems/codegen/index.rst @@ -0,0 +1,29 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen: + +Inline Code Generation +###################### + +For some repetitive or parameterized coding tasks, it's convenient to +use a code generating tool to build C code fragments, instead of writing +(or editing) that source code by hand. Such a tool can also access CMake build +parameters and device tree information to generate source code automatically +tailored and tuned to a specific project configuration. + +The Zephyr project supports a code generating tool that processes embedded +Python "snippets" inlined in your source files. It can be used, for example, +to generate source code that creates and fills data structures, adapts +programming logic, creates configuration-specific code fragments, and more. + +.. toctree:: + :maxdepth: 1 + + codegen + functions + modules + templates + build + principle diff --git a/doc/subsystems/codegen/modules.rst b/doc/subsystems/codegen/modules.rst new file mode 100644 index 000000000000..3a53d5d8ad5e --- /dev/null +++ b/doc/subsystems/codegen/modules.rst @@ -0,0 +1,322 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_modules: + +Code Generation Modules +####################### + +Code generation modules provide supporting functions for code generation. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +Modules have to be imported to gain access to the module's functions +and variables. + + :: + + /* This file uses modules. */ + ... + /** + * @code{.codegen} + * codegen.import_module('my_special_module') + * my_special_module.do_everything(): + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ + ... + +Device declare module +********************* + +:: + + codegen.import_module('devicedeclare') + +The devicedeclare module provides functions to generate driver device +instantiations. + +Driver info templates +--------------------- + +The device declaration functions work on templates that feature placeholder +substitution. + +Device instance property placeholders: + +- ${device-name}: device instance name. + Name is generated by the declaration function. +- ${driver-name}: device instance driver name. + Name is taken from the device tree node property 'label'. +- ${device-data}: device instance data structure name. + Name is generated by the declaration function. +- ${device-config-info}: device instance configuration structure name. + Name is generated by the declaration function. +- ${device-config-irq}: device instance interrupt configuration function name. + Name is generated by the declaration function. + +Device instance device tree property placeholders: + +* ${[path to DTS property]}: device instance device tree node property. + The property path supports every node property that is documented in the + node yaml bindings. It also supports yaml heuristics, like 'bus-master' and + will use documented '"#cells"'. + +Device tree property placeholders: + +- ${[device id]:[path to DTS property]}: device node property value. + The device node property is defined by the property path of the device + given by the device id. + The device id is usually also taken from a DTS property e.g. + ${${clocks/0/provider}:device-name}. + +KConfig configuration parameter placeholders: + +- ${CONFIG_[configuration parameter]}: KConfig configuration parameter value. + +Declaration of device instances +------------------------------- + +.. function:: devicedeclare.device_declare(compatibles, init_prio_flag, kernel_level, irq_func, init_func, api, data_struct, config_struct) + + Generate device instances code for all devices activated ('status' = 'ok') + in the board device tree file matching the provided compatibles. + + Most of the parameters aim at filling the DEVICE_AND_API_INIT macro. + Other parameters are there to help code generation to fit driver specifics. + + Instance code will only be generated if the Kconfig variable is set. The + variable name is build with the device node label name (e.g: CONFIG_I2C_1). + + :param compatibles: List of compatibles supported by the driver + (e.g. ['st,stm32-spi-fifo', 'st,stm32-spi']) + :param init_prio_flag: Flag for driver activation priority + (e.g. CONFIG_KERNEL_INIT_PRIORITY_DEVICE) + :param kernel_level: Flag for driver activation priority (e.g. POST_KERNEL) + :param irq_func: Two elements python dict providing driver isr function + prefix (e.g. 'irq_func' \: 'stm32_i2c_isr') and flag to be + used for driver IRQ code control + (e.g. 'irq_flag' \: 'CONFIG_I2C_STM32_INTERRUPT'). + If irq_func is 'None', no IRQ code is generated. + 'device_declare' will generate as much IRQ code as + declared by device node. + If the 'interrupts-names' property is provided in the node, + isr names will be generated using matching values as + function postfixes. + :param init_func: Name of the driver init function (e.g. 'i2c_stm32_init'). + :param api: Name of the driver api structure (e.g. 'api_funcs'). + :param data_struct: Two elements python list providing elements for driver + '_data' structure generation. + :param config_struct: Two elements python list providing elements for driver + '_config' structure generation. + +'data_struct' and 'config_struct' will be processed the same way: + +* First element (e.g. 'i2c_stm32_config') should be the structure name. +* Second element is a 'c' template code between triple double quotes (""" """). + It should provide the expected code to be generated for the structure. + For instance: + +.. code-block:: python + + """ + .i2c = (I2C_TypeDef *)${reg/0/address/0}, + .pclken = { + .enr = ${clocks/0/bits}, + .bus = ${clocks/0/bus}, + }, + #ifdef CONFIG_I2C_STM32_INTERRUPT + .irq_config_func = st_stm32_i2c_v1_${node_index}_config_irq, + #endif + .bitrate = ${clock-frequency}, + """ + +If the second element of 'data_struct' or 'config_struct' list is not provided, +an empty structure is generated. + +Finally, for the above depicted example, 'device_declare' will generate, +for device instance 'I2C1': + +.. code-block:: c + + #ifdef CONFIG_I2C_STM32_INTERRUPT + DEVICE_DECLARE(st_stm32_i2c_v1_i2c_1); + static void st_stm32_i2c_v1_i2c_1_config_irq(struct device *dev) + { + IRQ_CONNECT(31, + 0, + stm32_i2c_isr_event, + DEVICE_GET(st_stm32_i2c_v1_i2c_1), + 0); + irq_enable(31); + IRQ_CONNECT(32, + 0, + stm32_i2c_isr_error, + DEVICE_GET(st_stm32_i2c_v1_i2c_1), + 0); + irq_enable(32); + } + #endif /* CONFIG_I2C_STM32_INTERRUPT */ + + static const struct i2c_stm32_config st_stm32_i2c_v1_i2c_1_config = { + .i2c = (I2C_TypeDef *)0x40005400, + .pclken = { + .enr = 131072, + .bus = 2, + }, + #ifdef CONFIG_I2C_STM32_INTERRUPT + .irq_config_func = st_stm32_i2c_v1_i2c_1_config_irq, + #endif + .bitrate = 400000, + }; + + static struct i2c_stm32_data st_stm32_i2c_v1_i2c_1_data = {}; + + DEVICE_AND_API_INIT(st_stm32_i2c_v1_i2c_1, + "I2C_1", + i2c_stm32_init, + &st_stm32_i2c_v1_i2c_1_data, + &st_stm32_i2c_v1_i2c_1_config, + POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &api_funcs); + +Raw declaration of a single device instance +------------------------------------------- + +.. function:: devicedeclare.device_declare_single(device_config, driver_name, device_init, device_levels device_prio, device_api, device_info) + + Generate device instances code for a device instance that: + + - matches the driver name and that + - is activated ('status' = 'ok') in the board device tree file and that is + - configured by Kconfig. + + The ``device_declare_single`` function enables a detailed control of the + device info definition. It's primary use is for complex device instance + initialisation that can not be accomplished by ``device_declare``. + + :param device_config: + Configuration variables for device instantiation. + (e.g. 'CONFIG_SPI_0') + :param driver_name: + Driver name for device instantiation. + (e.g. 'SPI_0') + :param device_init: + Device initialisation function. + (e.g. 'spi_stm32_init') + :param device_level: + Driver initialisation level. + (e.g. 'PRE_KERNEL_1') + :param device_prios: + Driver initialisation priority definition. + (e.g. 32) + :param device_api: + Identifier of the device api. + (e.g. 'spi_stm32_driver_api') + :param device_info: + Device info template for device driver config, data and interrupt + initialisation. + :param device_defaults: + Default property values. + (e.g. { 'label' : 'My default label' }) + +Raw declaration of multiple device instances +-------------------------------------------- + +.. function:: devicedeclare.device_declare_multi(device_configs, driver_names, device_inits, device_levels, device_prios, device_api, device_info) + + Generate device instances code for all device instances that: + + - match the driver names and that + - are activated ('status' = 'ok') in the board device tree file and that are + - configured by Kconfig. + + The ``device_declare_multi`` function enables a detailed control of the + device info definition. It's primary use is for complex device instance + initialisation that can not be accomplished by ``device_declare``. + + :param device_configs: + A list of configuration variables for device instantiation. + (e.g. ['CONFIG_SPI_0', 'CONFIG_SPI_1']) + :param driver_names: + A list of driver names for device instantiation. The list shall be + ordered the same way as the list of device configs. + (e.g. ['SPI_0', 'SPI_1']) + :param device_inits: + A list of device initialisation functions or a one single function. + The list shall be ordered as the list of device configs. + (e.g. 'spi_stm32_init') + :param device_levels: + A list of driver initialisation levels or one single level definition. + The list shall be ordered as the list of device configs. + (e.g. 'PRE_KERNEL_1') + :param device_prios: + A list of driver initialisation priorities or one single priority + definition. The list shall be ordered as the list of device configs. + (e.g. 32) + :param device_api: + Identifier of the device api. + (e.g. 'spi_stm32_driver_api') + :param device_info: + Device info template for device driver config, data and interrupt + initialisation. + :param device_defaults: + Default property values. + (e.g. { 'label' : 'My default label' }) + +Example: + +.. code-block:: C + + /** + * @code{.codegen} + * codegen.import_module('devicedeclare') + * + * device_configs = ['CONFIG_SPI_{}'.format(x) for x in range(1, 4)] + * driver_names = ['SPI_{}'.format(x) for x in range(1, 4)] + * device_inits = 'spi_stm32_init' + * device_levels = 'POST_KERNEL' + * device_prios = 'CONFIG_SPI_INIT_PRIORITY' + * device_api = 'spi_stm32_driver_api' + * device_info = \ + * """ + * #if CONFIG_SPI_STM32_INTERRUPT + * DEVICE_DECLARE(${device-name}); + * static void ${device-config-irq}(struct device *dev) + * { + * IRQ_CONNECT(${interrupts/0/irq}, ${interrupts/0/priority}, \\ + * spi_stm32_isr, \\ + * DEVICE_GET(${device-name}), 0); + * irq_enable(${interrupts/0/irq}); + * } + * #endif + * static const struct spi_stm32_config ${device-config-info} = { + * .spi = (SPI_TypeDef *)${reg/0/address/0}, + * .pclken.bus = ${clocks/0/bus}, + * .pclken.enr = ${clocks/0/bits}, + * #if CONFIG_SPI_STM32_INTERRUPT + * .config_irq = ${device-config-irq}, + * #endif + * }; + * static struct spi_stm32_data ${device-data} = { + * SPI_CONTEXT_INIT_LOCK(${device-data}, ctx), + * SPI_CONTEXT_INIT_SYNC(${device-data}, ctx), + * }; + * """ + * + * devicedeclare.device_declare_multi( \ + * device_configs, + * driver_names, + * device_inits, + * device_levels, + * device_prios, + * device_api, + * device_info) + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ diff --git a/doc/subsystems/codegen/principle.rst b/doc/subsystems/codegen/principle.rst new file mode 100644 index 000000000000..4fa4a0b3d270 --- /dev/null +++ b/doc/subsystems/codegen/principle.rst @@ -0,0 +1,48 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_principle: + +Code Generation Principle +######################### + +How code generation works in Zephyr. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +Principle +--------- + +.. image:: codegen_principle.png + :width: 500px + :align: center + :alt: Principle + +Inclusion of other inline code +------------------------------ + +.. image:: codegen_principle_include.png + :width: 500px + :align: center + :alt: Include other inline code + +Access to Zephyr data +--------------------- + +.. image:: codegen_principle_access.png + :width: 500px + :align: center + :alt: Access Zephyr data + +Import of Python modules +------------------------ + +.. image:: codegen_principle_import.png + :width: 500px + :align: center + :alt: Import Python modules + diff --git a/doc/subsystems/codegen/templates.rst b/doc/subsystems/codegen/templates.rst new file mode 100644 index 000000000000..da9f3a5ad12b --- /dev/null +++ b/doc/subsystems/codegen/templates.rst @@ -0,0 +1,37 @@ +.. + Copyright (c) 2018 Bobby Noelte + SPDX-License-Identifier: Apache-2.0 + +.. _codegen_templates: + +Code Generation Templates +######################### + +Code generation templates provide sopisticated code generation functions. + +.. contents:: + :depth: 2 + :local: + :backlinks: top + +Templates have to be included to gain access to the template's functions +and variables. + + :: + + /* This file uses templates. */ + ... + /** + * @code{.codegen} + * template_in_var = 1 + * codegen.out_include('templates/template_tmpl.c') + * if template_out_var not None: + * codegen.outl("int x = %s;" % template_out_var) + * @endcode{.codegen} + */ + /** @code{.codeins}@endcode */ + ... + + + + diff --git a/doc/subsystems/subsystems.rst b/doc/subsystems/subsystems.rst index 372fdeec9839..337a6ed17b5e 100644 --- a/doc/subsystems/subsystems.rst +++ b/doc/subsystems/subsystems.rst @@ -11,6 +11,7 @@ to applications. bluetooth/bluetooth.rst c_library + codegen/index dfu logging/index tracing/index diff --git a/dts/bindings/arc/arc,dccm.yaml b/dts/bindings/arc/arc,dccm.yaml index 6cd1a790fb7b..414d9f19c684 100644 --- a/dts/bindings/arc/arc,dccm.yaml +++ b/dts/bindings/arc/arc,dccm.yaml @@ -5,7 +5,7 @@ # --- title: ARC DCCM -id: arc,dccm +type: dccm version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "arc,dccm" + generation: define reg: type: array diff --git a/dts/bindings/arc/arc,iccm.yaml b/dts/bindings/arc/arc,iccm.yaml index 5183e08b9b66..4d87c1bbc774 100644 --- a/dts/bindings/arc/arc,iccm.yaml +++ b/dts/bindings/arc/arc,iccm.yaml @@ -5,7 +5,7 @@ # --- title: ARC ICCM -id: arc,iccm +type: iccm version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "arc,iccm" + generation: define reg: type: array diff --git a/dts/bindings/arm/atmel,sam0-sercom.yaml b/dts/bindings/arm/atmel,sam0-sercom.yaml index 95ecb140372a..bc98a4df4886 100644 --- a/dts/bindings/arm/atmel,sam0-sercom.yaml +++ b/dts/bindings/arm/atmel,sam0-sercom.yaml @@ -1,6 +1,6 @@ --- title: Atmel SERCOM binding -id: atmel,sam0-sercom +type: sercom version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "atmel,sam0-sercom" + generation: define reg: type: array diff --git a/dts/bindings/arm/nxp,kinetis-sim.yaml b/dts/bindings/arm/nxp,kinetis-sim.yaml index 4bd8cd649a77..b001370fd0c1 100644 --- a/dts/bindings/arm/nxp,kinetis-sim.yaml +++ b/dts/bindings/arm/nxp,kinetis-sim.yaml @@ -5,7 +5,7 @@ # --- title: Kinetis System Integration Module (SIM) -id: nxp,kinetis-sim +type: clock-controller version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nxp,kinetis-sim" + generation: define reg: type: int diff --git a/dts/bindings/arm/nxp,lpc-mailbox.yaml b/dts/bindings/arm/nxp,lpc-mailbox.yaml index d2b9dca96d6f..c4e40e520681 100644 --- a/dts/bindings/arm/nxp,lpc-mailbox.yaml +++ b/dts/bindings/arm/nxp,lpc-mailbox.yaml @@ -5,7 +5,7 @@ # --- title: LPC MAILBOX -id: nxp,lpc-mailbox +type: mailbox version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nxp,lpc-mailbox" + generation: define reg: type: array diff --git a/dts/bindings/arm/st,stm32-ccm.yaml b/dts/bindings/arm/st,stm32-ccm.yaml index f39ee5327e43..f94f9f10e3e7 100644 --- a/dts/bindings/arm/st,stm32-ccm.yaml +++ b/dts/bindings/arm/st,stm32-ccm.yaml @@ -1,26 +1,26 @@ --- # SPDX-License-Identifier: Apache-2.0 title: STM32 CCM -id: st,stm32-ccm +type: ccm version: 0.1 description: > This binding gives a base representation of the STM32 CCM (Core Coupled Memory) properties: - compatible: - type: string - category: required - constraint: "st,stm32-ccm" + compatible: + type: string + category: required + constraint: "st,stm32-ccm" + generation: define - reg: - type: int - description: mmio register space - generation: define - category: required + reg: + type: int + description: mmio register space + generation: define + category: required base_label: CCM use-property-label: yes ... - diff --git a/dts/bindings/arm/ti,cc2650-prcm.yaml b/dts/bindings/arm/ti,cc2650-prcm.yaml index 68f8b35fd5fb..27f687b90435 100644 --- a/dts/bindings/arm/ti,cc2650-prcm.yaml +++ b/dts/bindings/arm/ti,cc2650-prcm.yaml @@ -1,6 +1,7 @@ --- # SPDX-License-Identifier: Apache-2.0 title: TI CC2650 PRCM +type: prcm version: 0.1 description: > @@ -13,6 +14,7 @@ properties: category: required description: compatible strings constraint: "ti,cc2650-prcm" + generation: define reg: type: array diff --git a/dts/bindings/audio/ti,tlv320dac.yaml b/dts/bindings/audio/ti,tlv320dac.yaml index 5e7557290620..66db20da72a3 100644 --- a/dts/bindings/audio/ti,tlv320dac.yaml +++ b/dts/bindings/audio/ti,tlv320dac.yaml @@ -5,7 +5,6 @@ # --- title: Texas Instruments TLV320DAC Audio DAC -id: ti,tlv320dac version: 0.1 description: > diff --git a/dts/bindings/bluetooth/st,spbtle-rf.yaml b/dts/bindings/bluetooth/st,spbtle-rf.yaml index 22f07a806486..1530529d56ba 100644 --- a/dts/bindings/bluetooth/st,spbtle-rf.yaml +++ b/dts/bindings/bluetooth/st,spbtle-rf.yaml @@ -5,7 +5,6 @@ # --- title: STMicroelectronics SPBTLE-RF bluetooth module -id: st,spbtle-rf version: 0.1 description: > diff --git a/dts/bindings/bluetooth/zephyr,bt-hci-spi.yaml b/dts/bindings/bluetooth/zephyr,bt-hci-spi.yaml index 11de1a95007a..e660588df740 100644 --- a/dts/bindings/bluetooth/zephyr,bt-hci-spi.yaml +++ b/dts/bindings/bluetooth/zephyr,bt-hci-spi.yaml @@ -5,7 +5,7 @@ # --- title: Bluetooth module based on Zephyr's Bluetooth HCI SPI driver -id: zephyr,bt-hci-spi +type: bt-hci version: 0.1 description: > diff --git a/dts/bindings/can/can-device.yaml b/dts/bindings/can/can-device.yaml index 980f4b9ae59d..1da1010538b4 100644 --- a/dts/bindings/can/can-device.yaml +++ b/dts/bindings/can/can-device.yaml @@ -5,7 +5,7 @@ # --- title: CAN Device Base Structure -id: can-device +type: can-device version: 0.1 description: > @@ -19,6 +19,7 @@ properties: type: string category: required description: compatible strings + generation: define reg: type: array description: register base address diff --git a/dts/bindings/can/can.yaml b/dts/bindings/can/can.yaml index d490304b9a7f..839349d8e8c7 100644 --- a/dts/bindings/can/can.yaml +++ b/dts/bindings/can/can.yaml @@ -1,6 +1,6 @@ --- title: CAN Base Structure -id: can +type: can version: 0.1 description: > @@ -10,6 +10,11 @@ child: bus: can properties: + compatible: + type: string + category: required + description: compatible strings + generation: define "#address-cells": type: int category: required diff --git a/dts/bindings/can/st,stm32-can.yaml b/dts/bindings/can/st,stm32-can.yaml index 93425f993f82..77d6ea48eb8c 100644 --- a/dts/bindings/can/st,stm32-can.yaml +++ b/dts/bindings/can/st,stm32-can.yaml @@ -1,6 +1,5 @@ --- title: STM32 CAN -id: st,stm32-can version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-can" reg: diff --git a/dts/bindings/clock/nxp,imx-ccm.yaml b/dts/bindings/clock/nxp,imx-ccm.yaml index c176e0da5148..a9bb053d3cd9 100644 --- a/dts/bindings/clock/nxp,imx-ccm.yaml +++ b/dts/bindings/clock/nxp,imx-ccm.yaml @@ -5,7 +5,7 @@ # --- title: i.MX Clock Controller Module (CCM) -id: nxp,imx-ccm +type: clock-control version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nxp,imx-ccm" + generation: define reg: type: int diff --git a/dts/bindings/clock/st,stm32-rcc.yaml b/dts/bindings/clock/st,stm32-rcc.yaml index 2e93da9ac83e..e05bb2649f0b 100644 --- a/dts/bindings/clock/st,stm32-rcc.yaml +++ b/dts/bindings/clock/st,stm32-rcc.yaml @@ -1,6 +1,6 @@ --- title: STM32 RCC -id: st,stm32-rcc +type: clock-control version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "st,stm32-rcc" + generation: define reg: type: array diff --git a/dts/bindings/device_node.yaml.template b/dts/bindings/device_node.yaml.template index bb6d77517352..aaca503ba886 100644 --- a/dts/bindings/device_node.yaml.template +++ b/dts/bindings/device_node.yaml.template @@ -1,5 +1,6 @@ --- title: +type: <zephyr generic type for the described device> version: 0.1 description: > @@ -37,6 +38,7 @@ properties: category: required type: string description: compatible of node + generation: define # reg is used to denote mmio registers reg: diff --git a/dts/bindings/flash_controller/atmel,sam0-nvmctrl.yaml b/dts/bindings/flash_controller/atmel,sam0-nvmctrl.yaml index b8cefc44ea9e..8dbc13627be0 100644 --- a/dts/bindings/flash_controller/atmel,sam0-nvmctrl.yaml +++ b/dts/bindings/flash_controller/atmel,sam0-nvmctrl.yaml @@ -1,6 +1,5 @@ --- title: Atmel SAM0 Non-Volatile Memory Controller -id: atmel,sam0-nvmctrl version: 0.1 description: > diff --git a/dts/bindings/flash_controller/flash-controller.yaml b/dts/bindings/flash_controller/flash-controller.yaml index f30ed6628919..b68e2ed431c7 100644 --- a/dts/bindings/flash_controller/flash-controller.yaml +++ b/dts/bindings/flash_controller/flash-controller.yaml @@ -1,6 +1,6 @@ --- title: flash controller Base Structure -id: soc-nv-flash-controller +type: flash-controller version: 0.1 description: > diff --git a/dts/bindings/flash_controller/nordic,nrf51-flash-controller.yaml b/dts/bindings/flash_controller/nordic,nrf51-flash-controller.yaml index a39fc91b365b..ed6ea2887ac7 100644 --- a/dts/bindings/flash_controller/nordic,nrf51-flash-controller.yaml +++ b/dts/bindings/flash_controller/nordic,nrf51-flash-controller.yaml @@ -1,6 +1,5 @@ --- title: Nordic NVMC -id: nordic,nrf51-flash-controller version: 0.1 description: > diff --git a/dts/bindings/flash_controller/nordic,nrf52-flash-controller.yaml b/dts/bindings/flash_controller/nordic,nrf52-flash-controller.yaml index 1c84b23c40f1..da75a257fe83 100644 --- a/dts/bindings/flash_controller/nordic,nrf52-flash-controller.yaml +++ b/dts/bindings/flash_controller/nordic,nrf52-flash-controller.yaml @@ -1,6 +1,5 @@ --- title: Nordic NVMC -id: nordic,nrf52-flash-controller version: 0.1 description: > diff --git a/dts/bindings/flash_controller/nxp,kinetis-ftfa.yaml b/dts/bindings/flash_controller/nxp,kinetis-ftfa.yaml index 4257357c481a..c07bc7a2f72f 100644 --- a/dts/bindings/flash_controller/nxp,kinetis-ftfa.yaml +++ b/dts/bindings/flash_controller/nxp,kinetis-ftfa.yaml @@ -1,6 +1,5 @@ --- title: NXP Kinetis Flash Memory Module (FTFA) -id: nxp,kinetis-ftfa version: 0.1 description: > diff --git a/dts/bindings/flash_controller/nxp,kinetis-ftfe.yaml b/dts/bindings/flash_controller/nxp,kinetis-ftfe.yaml index aaac2faffa60..2ac3b2532272 100644 --- a/dts/bindings/flash_controller/nxp,kinetis-ftfe.yaml +++ b/dts/bindings/flash_controller/nxp,kinetis-ftfe.yaml @@ -1,6 +1,5 @@ --- title: NXP Kinetis Flash Memory Module (FTFE) -id: nxp,kinetis-ftfe version: 0.1 description: > diff --git a/dts/bindings/flash_controller/nxp,kinetis-ftfl.yaml b/dts/bindings/flash_controller/nxp,kinetis-ftfl.yaml index 246d24e3a712..abe691f055e9 100644 --- a/dts/bindings/flash_controller/nxp,kinetis-ftfl.yaml +++ b/dts/bindings/flash_controller/nxp,kinetis-ftfl.yaml @@ -1,6 +1,5 @@ --- title: NXP Kinetis Flash Memory Module (FTFL) -id: nxp,kinetis-ftfl version: 0.1 description: > diff --git a/dts/bindings/flash_controller/st,stm32f0-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32f0-flash-controller.yaml index 3600dcf4be25..3fcee587a3d9 100644 --- a/dts/bindings/flash_controller/st,stm32f0-flash-controller.yaml +++ b/dts/bindings/flash_controller/st,stm32f0-flash-controller.yaml @@ -1,6 +1,5 @@ --- title: STM32 F0 Flash Controller -id: st,stm32f0-flash-controller version: 0.1 description: > diff --git a/dts/bindings/flash_controller/st,stm32f3-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32f3-flash-controller.yaml index 08d37f11055a..14a44c105902 100644 --- a/dts/bindings/flash_controller/st,stm32f3-flash-controller.yaml +++ b/dts/bindings/flash_controller/st,stm32f3-flash-controller.yaml @@ -1,6 +1,5 @@ --- title: STM32 F3 Flash Controller -id: st,stm32f3-flash-controller version: 0.1 description: > diff --git a/dts/bindings/flash_controller/st,stm32f4-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32f4-flash-controller.yaml index 33981d584e98..ef8cb9800cde 100644 --- a/dts/bindings/flash_controller/st,stm32f4-flash-controller.yaml +++ b/dts/bindings/flash_controller/st,stm32f4-flash-controller.yaml @@ -1,6 +1,5 @@ --- title: STM32 F4 Flash Controller -id: st,stm32f4-flash-controller version: 0.1 description: > diff --git a/dts/bindings/flash_controller/st,stm32l4-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32l4-flash-controller.yaml index 978ce593f267..4af50832da23 100644 --- a/dts/bindings/flash_controller/st,stm32l4-flash-controller.yaml +++ b/dts/bindings/flash_controller/st,stm32l4-flash-controller.yaml @@ -1,6 +1,5 @@ --- title: STM32 L4 Flash Controller -id: st,stm32l4-flash-controller version: 0.1 description: > diff --git a/dts/bindings/gpio/arm,cmsdk-gpio.yaml b/dts/bindings/gpio/arm,cmsdk-gpio.yaml index cf8fcd079589..b53852d3a9db 100644 --- a/dts/bindings/gpio/arm,cmsdk-gpio.yaml +++ b/dts/bindings/gpio/arm,cmsdk-gpio.yaml @@ -1,6 +1,6 @@ --- title: ARM CMSDK GPIO -id: arm,cmsdk-gpio +type: gpio version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "arm,cmsdk-gpio" + generation: define reg: type: array diff --git a/dts/bindings/gpio/atmel,sam0-gpio.yaml b/dts/bindings/gpio/atmel,sam0-gpio.yaml index 817c94e3d7a6..b1ad2aa8d953 100644 --- a/dts/bindings/gpio/atmel,sam0-gpio.yaml +++ b/dts/bindings/gpio/atmel,sam0-gpio.yaml @@ -1,6 +1,6 @@ --- title: Atmel SAM0 GPIO PORT driver -id: atmel,sam0-gpio +type: gpio version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "atmel,sam0-gpio" + generation: define reg: type: int diff --git a/dts/bindings/gpio/atmel.sam-gpio.yaml b/dts/bindings/gpio/atmel.sam-gpio.yaml index 8ebf12e2ce69..1879206c1de8 100644 --- a/dts/bindings/gpio/atmel.sam-gpio.yaml +++ b/dts/bindings/gpio/atmel.sam-gpio.yaml @@ -1,6 +1,6 @@ --- title: Atmel SAM GPIO PORT driver -id: atmel,sam-gpio +type: gpio version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "atmel,sam-gpio" + generation: define reg: type: int diff --git a/dts/bindings/gpio/gpio-keys.yaml b/dts/bindings/gpio/gpio-keys.yaml index 3e25bccc1607..798f6b247c52 100644 --- a/dts/bindings/gpio/gpio-keys.yaml +++ b/dts/bindings/gpio/gpio-keys.yaml @@ -5,7 +5,7 @@ # --- title: GPIO KEYS -id: gpio-keys +type: gpio-keys version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "gpio-keys" + generation: define gpios: type: compound diff --git a/dts/bindings/gpio/gpio-leds.yaml b/dts/bindings/gpio/gpio-leds.yaml index 042fa0368660..db47926873b6 100644 --- a/dts/bindings/gpio/gpio-leds.yaml +++ b/dts/bindings/gpio/gpio-leds.yaml @@ -5,7 +5,7 @@ # --- title: GPIO LED -id: gpio-leds +type: gpio-leds version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "gpio-leds" + generation: define gpios: type: compound diff --git a/dts/bindings/gpio/intel,qmsi-gpio.yaml b/dts/bindings/gpio/intel,qmsi-gpio.yaml index d0af21553d93..d3a6bef37d8e 100644 --- a/dts/bindings/gpio/intel,qmsi-gpio.yaml +++ b/dts/bindings/gpio/intel,qmsi-gpio.yaml @@ -5,7 +5,7 @@ # --- title: Intel QMSI GPIO -id: intel,qmsi-gpio +type: gpio version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "intel,qmsi-gpio" + generation: define reg: type: int @@ -41,4 +42,4 @@ cell_string: GPIO "#cells": - pin - flags -... \ No newline at end of file +... diff --git a/dts/bindings/gpio/intel,qmsi-ss-gpio.yaml b/dts/bindings/gpio/intel,qmsi-ss-gpio.yaml index daf2c4cda8c1..df66c8edc244 100644 --- a/dts/bindings/gpio/intel,qmsi-ss-gpio.yaml +++ b/dts/bindings/gpio/intel,qmsi-ss-gpio.yaml @@ -5,7 +5,7 @@ # --- title: Intel QMSI SS GPIO -id: intel,qmsi-ss-gpio +type: gpio version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "intel,qmsi-ss-gpio" + generation: define reg: type: int @@ -41,4 +42,4 @@ cell_string: GPIO "#cells": - pin - flags -... \ No newline at end of file +... diff --git a/dts/bindings/gpio/nordic,nrf-gpio.yaml b/dts/bindings/gpio/nordic,nrf-gpio.yaml index 25cf80222b91..91e7de8a4d24 100644 --- a/dts/bindings/gpio/nordic,nrf-gpio.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpio.yaml @@ -4,12 +4,12 @@ # SPDX-License-Identifier: Apache-2.0 # --- -title: nRF GPIO -id: nordic,nrf-gpio +title: NRF5 GPIO +type: gpio version: 0.1 description: > - This is a representation of the nRF GPIO nodes + This is a representation of the NRF GPIO nodes properties: compatible: @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nordic,nrf-gpio" + generation: define reg: type: int diff --git a/dts/bindings/gpio/nordic,nrf-gpiote.yaml b/dts/bindings/gpio/nordic,nrf-gpiote.yaml index 28eb7702cba1..afb878de65da 100644 --- a/dts/bindings/gpio/nordic,nrf-gpiote.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpiote.yaml @@ -4,12 +4,12 @@ # SPDX-License-Identifier: Apache-2.0 # --- -title: nRF GPIOTE -id: nordic,nrf-gpiote +title: NRF5 GPIOTE +type: gpio version: 0.1 description: > - This is a representation of the nRF GPIOTE node + This is a representation of the NRF GPIOTE node properties: compatible: @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nordic,nrf-gpiote" + generation: define reg: type: int diff --git a/dts/bindings/gpio/nxp,imx-gpio.yaml b/dts/bindings/gpio/nxp,imx-gpio.yaml index 8867b4ad9063..c9f49a556b04 100644 --- a/dts/bindings/gpio/nxp,imx-gpio.yaml +++ b/dts/bindings/gpio/nxp,imx-gpio.yaml @@ -5,7 +5,7 @@ # --- title: i.MX GPIO -id: nxp,imx-gpio +type: gpio version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nxp,imx-gpio" + generation: define reg: type: int diff --git a/dts/bindings/gpio/nxp,kinetis-gpio.yaml b/dts/bindings/gpio/nxp,kinetis-gpio.yaml index c6f032961d1e..5b4723a5a1a0 100644 --- a/dts/bindings/gpio/nxp,kinetis-gpio.yaml +++ b/dts/bindings/gpio/nxp,kinetis-gpio.yaml @@ -1,6 +1,6 @@ --- title: Kinetis GPIO -id: nxp,kinetis-gpio +type: gpio version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "nxp,kinetis-gpio" + generation: define reg: type: int diff --git a/dts/bindings/gpio/semtech,sx1509b-gpio.yaml b/dts/bindings/gpio/semtech,sx1509b-gpio.yaml index 70b4fb3d4d3a..6922a8ab021d 100644 --- a/dts/bindings/gpio/semtech,sx1509b-gpio.yaml +++ b/dts/bindings/gpio/semtech,sx1509b-gpio.yaml @@ -5,7 +5,6 @@ # --- title: Semtech SX1509B I2C GPIO -id: semtech,sx1509b version: 0.1 description: > @@ -17,5 +16,4 @@ inherits: properties: compatible: constraint: "semtech,sx1509b" - ... diff --git a/dts/bindings/gpio/sifive,gpio0.yaml b/dts/bindings/gpio/sifive,gpio0.yaml index 3296d40481a3..9928d313c6e0 100644 --- a/dts/bindings/gpio/sifive,gpio0.yaml +++ b/dts/bindings/gpio/sifive,gpio0.yaml @@ -5,7 +5,7 @@ # --- title: SiFive GPIO -id: sifive,gpio0 +type: gpio version: 0.1 description: > diff --git a/dts/bindings/gpio/snps,designware-gpio.yaml b/dts/bindings/gpio/snps,designware-gpio.yaml index f732f6358212..e2356d880f77 100644 --- a/dts/bindings/gpio/snps,designware-gpio.yaml +++ b/dts/bindings/gpio/snps,designware-gpio.yaml @@ -5,7 +5,7 @@ # --- title: Synopsys Designware GPIO controller -id: snps,designware-gpio +type: gpio version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "snps,designware-gpio" + generation: define reg: type: int @@ -47,4 +48,4 @@ cell_string: GPIO "#cells": - pin - flags -... \ No newline at end of file +... diff --git a/dts/bindings/gpio/st,stm32-gpio.yaml b/dts/bindings/gpio/st,stm32-gpio.yaml index 36b824a3a649..5bd597386a52 100644 --- a/dts/bindings/gpio/st,stm32-gpio.yaml +++ b/dts/bindings/gpio/st,stm32-gpio.yaml @@ -5,7 +5,7 @@ # --- title: STM32 GPIO -id: st,stm32-gpio +type: gpio version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "st,stm32-gpio" + generation: define reg: type: int diff --git a/dts/bindings/gpio/ti,cc2650-gpio.yaml b/dts/bindings/gpio/ti,cc2650-gpio.yaml index 2c163e5afc6a..6a441b26c1f6 100644 --- a/dts/bindings/gpio/ti,cc2650-gpio.yaml +++ b/dts/bindings/gpio/ti,cc2650-gpio.yaml @@ -1,6 +1,7 @@ --- # SPDX-License-Identifier: Apache-2.0 title: TI CC2650 GPIO +type: gpio version: 0.1 description: > @@ -12,6 +13,7 @@ properties: category: required description: compatible strings constraint: "ti,cc2650-gpio" + generation: define reg: type: int diff --git a/dts/bindings/i2c/arm,versatile-i2c.yaml b/dts/bindings/i2c/arm,versatile-i2c.yaml index a59a3f2330bc..ef5747cc6905 100644 --- a/dts/bindings/i2c/arm,versatile-i2c.yaml +++ b/dts/bindings/i2c/arm,versatile-i2c.yaml @@ -5,7 +5,6 @@ # --- title: ARM SBCon two-wire serial bus interface -id: arm,versatile-i2c version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "arm,versatile-i2c" reg: diff --git a/dts/bindings/i2c/atmel,sam-i2c-twi.yaml b/dts/bindings/i2c/atmel,sam-i2c-twi.yaml index 1a8f53d7cf9f..a1f6d42560a9 100644 --- a/dts/bindings/i2c/atmel,sam-i2c-twi.yaml +++ b/dts/bindings/i2c/atmel,sam-i2c-twi.yaml @@ -5,7 +5,6 @@ # --- title: Atmel SAM Family I2C (TWI) node -id: atmel,sam-i2c-twi version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "atmel,sam-i2c-twi" reg: diff --git a/dts/bindings/i2c/atmel,sam-i2c-twihs.yaml b/dts/bindings/i2c/atmel,sam-i2c-twihs.yaml index e4e660488b8f..6afc1c101e43 100644 --- a/dts/bindings/i2c/atmel,sam-i2c-twihs.yaml +++ b/dts/bindings/i2c/atmel,sam-i2c-twihs.yaml @@ -5,7 +5,6 @@ # --- title: Atmel SAM Family I2C (TWIHS) node -id: atmel,sam-i2c-twihs version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "atmel,sam-i2c-twihs" reg: diff --git a/dts/bindings/i2c/fsl,imx7d-i2c.yaml b/dts/bindings/i2c/fsl,imx7d-i2c.yaml index fd9e9e86e09e..0c3542f6f04c 100644 --- a/dts/bindings/i2c/fsl,imx7d-i2c.yaml +++ b/dts/bindings/i2c/fsl,imx7d-i2c.yaml @@ -5,7 +5,6 @@ # --- title: i.MX I2C Controller -id: fsl,imx7d-i2c version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "fsl,imx7d-i2c" reg: diff --git a/dts/bindings/i2c/i2c-device.yaml b/dts/bindings/i2c/i2c-device.yaml index 8e8b61a1f1ee..10c95e259679 100644 --- a/dts/bindings/i2c/i2c-device.yaml +++ b/dts/bindings/i2c/i2c-device.yaml @@ -5,7 +5,7 @@ # --- title: I2C Device Base Structure -id: i2c-device +type: i2c-device version: 0.1 description: > @@ -19,6 +19,7 @@ properties: type: string category: required description: compatible strings + generation: define reg: type: array description: address on i2c bus diff --git a/dts/bindings/i2c/i2c.yaml b/dts/bindings/i2c/i2c.yaml index 664a7346e1f6..2de5dc518f19 100644 --- a/dts/bindings/i2c/i2c.yaml +++ b/dts/bindings/i2c/i2c.yaml @@ -5,7 +5,7 @@ # --- title: I2C Base Structure -id: i2c +type: i2c version: 0.1 description: > @@ -15,6 +15,11 @@ child: bus: i2c properties: + compatible: + type: string + category: required + description: compatible strings + generation: define "#address-cells": type: int category: required diff --git a/dts/bindings/i2c/intel,qmsi-i2c.yaml b/dts/bindings/i2c/intel,qmsi-i2c.yaml index bbf195838535..1736c34140d5 100644 --- a/dts/bindings/i2c/intel,qmsi-i2c.yaml +++ b/dts/bindings/i2c/intel,qmsi-i2c.yaml @@ -5,7 +5,6 @@ # --- title: Intel QMSI i2c -id: intel,qmsi-i2c version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "intel,qmsi-i2c" reg: diff --git a/dts/bindings/i2c/intel,qmsi-ss-i2c.yaml b/dts/bindings/i2c/intel,qmsi-ss-i2c.yaml index d572d4e58d6b..4f27c5fde2ef 100644 --- a/dts/bindings/i2c/intel,qmsi-ss-i2c.yaml +++ b/dts/bindings/i2c/intel,qmsi-ss-i2c.yaml @@ -5,7 +5,6 @@ # --- title: Intel QMSI SS i2c -id: intel,qmsi-ss-i2c version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "intel,qmsi-ss-i2c" reg: diff --git a/dts/bindings/i2c/nordic,nrf-i2c.yaml b/dts/bindings/i2c/nordic,nrf-i2c.yaml index c6d1e73532c6..a47a7dd24517 100644 --- a/dts/bindings/i2c/nordic,nrf-i2c.yaml +++ b/dts/bindings/i2c/nordic,nrf-i2c.yaml @@ -5,8 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 # --- -title: Nordic nRF Family I2C Master node -id: nordic,nrf-i2c +title: Nordic nRF5 Family I2C Master node version: 0.1 description: > diff --git a/dts/bindings/i2c/nxp,kinetis-i2c.yaml b/dts/bindings/i2c/nxp,kinetis-i2c.yaml index ab0ef4dea257..394df1351dd4 100644 --- a/dts/bindings/i2c/nxp,kinetis-i2c.yaml +++ b/dts/bindings/i2c/nxp,kinetis-i2c.yaml @@ -5,7 +5,6 @@ # --- title: Kinetis I2C Controller -id: nxp,kinetis-i2c version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-i2c" reg: diff --git a/dts/bindings/i2c/snps,designware-i2c.yaml b/dts/bindings/i2c/snps,designware-i2c.yaml index 0058ae65bd2d..85ffbd5551f7 100644 --- a/dts/bindings/i2c/snps,designware-i2c.yaml +++ b/dts/bindings/i2c/snps,designware-i2c.yaml @@ -5,7 +5,6 @@ # --- title: Synopys DesignWare I2C controller -id: snps,designware-i2c version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "snps,designware-i2c" reg: diff --git a/dts/bindings/i2c/st,stm32-i2c-v1.yaml b/dts/bindings/i2c/st,stm32-i2c-v1.yaml index 14fd19e09b7c..5115fad7c3ae 100644 --- a/dts/bindings/i2c/st,stm32-i2c-v1.yaml +++ b/dts/bindings/i2c/st,stm32-i2c-v1.yaml @@ -5,7 +5,6 @@ # --- title: STM32 I2C V1 -id: st,stm32-i2c-v1 version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-i2c-v1" reg: diff --git a/dts/bindings/i2c/st,stm32-i2c-v2.yaml b/dts/bindings/i2c/st,stm32-i2c-v2.yaml index c2e462e13b75..204b8c3ca961 100644 --- a/dts/bindings/i2c/st,stm32-i2c-v2.yaml +++ b/dts/bindings/i2c/st,stm32-i2c-v2.yaml @@ -5,7 +5,6 @@ # --- title: STM32 I2C V2 -id: st,stm32-i2c-v2 version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-i2c-v2" reg: diff --git a/dts/bindings/i2c/ti,cc32xx-i2c.yaml b/dts/bindings/i2c/ti,cc32xx-i2c.yaml index df39c7e34763..c07067178a1f 100644 --- a/dts/bindings/i2c/ti,cc32xx-i2c.yaml +++ b/dts/bindings/i2c/ti,cc32xx-i2c.yaml @@ -1,6 +1,5 @@ --- title: CC32XX I2C -id: ti,cc32xx-i2c description: > This binding gives a base representation of the TI CC32XX I2C controller @@ -10,9 +9,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "ti,cc32xx-i2c" reg: diff --git a/dts/bindings/ieee802154/nxp,mcr20a.yaml b/dts/bindings/ieee802154/nxp,mcr20a.yaml index 951a615bc0ba..094fd517b5f3 100644 --- a/dts/bindings/ieee802154/nxp,mcr20a.yaml +++ b/dts/bindings/ieee802154/nxp,mcr20a.yaml @@ -5,7 +5,6 @@ # --- title: NXP MCR20A 802.15.4 Wireless Transceiver -id: nxp,mcr20a version: 0.1 description: > diff --git a/dts/bindings/iio/adc/adc.yaml b/dts/bindings/iio/adc/adc.yaml index 82496bffe770..7cfcb0531961 100644 --- a/dts/bindings/iio/adc/adc.yaml +++ b/dts/bindings/iio/adc/adc.yaml @@ -5,13 +5,19 @@ # --- title: ADC Base Structure -id: adc +type: adc version: 0.1 description: > This binding gives the base structures for all ADC devices properties: + compatible: + type: string + category: required + description: compatible strings + generation: define + clocks: type: array category: required diff --git a/dts/bindings/iio/adc/atmel,sam-afec.yaml b/dts/bindings/iio/adc/atmel,sam-afec.yaml index e652dd0aa8bf..98f966a4afa7 100644 --- a/dts/bindings/iio/adc/atmel,sam-afec.yaml +++ b/dts/bindings/iio/adc/atmel,sam-afec.yaml @@ -1,6 +1,5 @@ --- title: Atmel SAM Family AFEC -id: atmel,sam-afec version: 0.1 description: > diff --git a/dts/bindings/iio/adc/intel,quark-d2000-adc.yaml b/dts/bindings/iio/adc/intel,quark-d2000-adc.yaml index dbb8bdf946d5..f65787059fb4 100644 --- a/dts/bindings/iio/adc/intel,quark-d2000-adc.yaml +++ b/dts/bindings/iio/adc/intel,quark-d2000-adc.yaml @@ -5,7 +5,6 @@ # --- title: Intel Quark D2000 ADC -id: intel,quark-d2000-adc version: 0.1 description: > diff --git a/dts/bindings/iio/adc/nordic,nrf-adc.yaml b/dts/bindings/iio/adc/nordic,nrf-adc.yaml index 2617c22a1a97..4e52a6d1b39d 100644 --- a/dts/bindings/iio/adc/nordic,nrf-adc.yaml +++ b/dts/bindings/iio/adc/nordic,nrf-adc.yaml @@ -5,7 +5,6 @@ # --- title: Nordic Semiconductor nRF Family ADC -id: nordic,nrf-adc version: 0.1 description: > diff --git a/dts/bindings/iio/adc/nordic,nrf-saadc.yaml b/dts/bindings/iio/adc/nordic,nrf-saadc.yaml index 0c988d3717c6..71e78326decd 100644 --- a/dts/bindings/iio/adc/nordic,nrf-saadc.yaml +++ b/dts/bindings/iio/adc/nordic,nrf-saadc.yaml @@ -5,7 +5,6 @@ # --- title: Nordic Semiconductor nRF Family SAADC -id: nordic,nrf-saadc version: 0.1 description: > diff --git a/dts/bindings/iio/adc/nxp,kinetis-adc16.yaml b/dts/bindings/iio/adc/nxp,kinetis-adc16.yaml index b93e0ad13ee7..cb003b1cd374 100644 --- a/dts/bindings/iio/adc/nxp,kinetis-adc16.yaml +++ b/dts/bindings/iio/adc/nxp,kinetis-adc16.yaml @@ -5,7 +5,6 @@ # --- title: Kinetis ADC16 -id: nxp,kinetis-adc16 version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-adc16" reg: diff --git a/dts/bindings/iio/adc/snps,dw-adc.yaml b/dts/bindings/iio/adc/snps,dw-adc.yaml index ea34c5eeb6a0..9590d7eaa0dc 100644 --- a/dts/bindings/iio/adc/snps,dw-adc.yaml +++ b/dts/bindings/iio/adc/snps,dw-adc.yaml @@ -5,7 +5,6 @@ # --- title: DesignWare ADC -id: snps,dw-adc version: 0.1 description: > diff --git a/dts/bindings/interrupt-controller/arm,v6m-nvic.yaml b/dts/bindings/interrupt-controller/arm,v6m-nvic.yaml index c75bd7563d40..80233288e712 100644 --- a/dts/bindings/interrupt-controller/arm,v6m-nvic.yaml +++ b/dts/bindings/interrupt-controller/arm,v6m-nvic.yaml @@ -1,6 +1,6 @@ --- title: ARMv6-M NVIC Interrupt Controller -id: arm,v6m-nvic +type: interrupt-controller version: 0.1 description: > @@ -12,6 +12,7 @@ properties: type: string description: compatible strings constraint: "arm,v6m-nvic" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/arm,v7m-nvic.yaml b/dts/bindings/interrupt-controller/arm,v7m-nvic.yaml index d6fede048b8b..002f83813718 100644 --- a/dts/bindings/interrupt-controller/arm,v7m-nvic.yaml +++ b/dts/bindings/interrupt-controller/arm,v7m-nvic.yaml @@ -1,6 +1,6 @@ --- title: ARMv7-M NVIC Interrupt Controller -id: arm,v7m-nvic +type: interrupt-controller version: 0.1 description: > @@ -12,6 +12,7 @@ properties: type: string description: compatible strings constraint: "arm,v7m-nvic" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/arm,v8m-nvic.yaml b/dts/bindings/interrupt-controller/arm,v8m-nvic.yaml index 786c4b87dc65..bde1f954833a 100644 --- a/dts/bindings/interrupt-controller/arm,v8m-nvic.yaml +++ b/dts/bindings/interrupt-controller/arm,v8m-nvic.yaml @@ -1,6 +1,6 @@ --- title: ARMv8-M NVIC Interrupt Controller -id: arm,v8m-nvic +type: interrupt-controller version: 0.1 description: > @@ -12,6 +12,7 @@ properties: type: string description: compatible strings constraint: "arm,v8m-nvic" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/intel,cavs-intc.yaml b/dts/bindings/interrupt-controller/intel,cavs-intc.yaml index 93562ad32874..07c5510c38d9 100644 --- a/dts/bindings/interrupt-controller/intel,cavs-intc.yaml +++ b/dts/bindings/interrupt-controller/intel,cavs-intc.yaml @@ -1,5 +1,6 @@ --- title: CAVS Interrupt Controller +type: interrupt-controller version: 0.1 description: > @@ -11,6 +12,7 @@ properties: type: string description: compatible strings constraint: "intel,cavs-intc" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/intel,ioapic.yaml b/dts/bindings/interrupt-controller/intel,ioapic.yaml index 6f6504e8911b..9ad38ff7b83a 100644 --- a/dts/bindings/interrupt-controller/intel,ioapic.yaml +++ b/dts/bindings/interrupt-controller/intel,ioapic.yaml @@ -1,5 +1,6 @@ --- title: Intel I/O Advanced Programmable Interrupt Controller +type: interrupt-controller version: 0.1 description: > @@ -12,6 +13,7 @@ properties: type: string description: compatible strings constraint: "intel,ioapic" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/intel,mvic.yaml b/dts/bindings/interrupt-controller/intel,mvic.yaml index 736ed6a0aaa2..d536b085e093 100644 --- a/dts/bindings/interrupt-controller/intel,mvic.yaml +++ b/dts/bindings/interrupt-controller/intel,mvic.yaml @@ -1,5 +1,6 @@ --- title: Intel Quark D2000 Interrupt Controller +type: interrupt-controller version: 0.1 description: > @@ -12,6 +13,7 @@ properties: type: string description: compatible strings constraint: "intel,mvic" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/riscv,plic0.yaml b/dts/bindings/interrupt-controller/riscv,plic0.yaml index 1af86c1da298..dca580b01c97 100644 --- a/dts/bindings/interrupt-controller/riscv,plic0.yaml +++ b/dts/bindings/interrupt-controller/riscv,plic0.yaml @@ -5,7 +5,7 @@ # --- title: RISC-V PLIC -id: riscv,plic0 +type: interrupt-controller version: 0.1 description: > diff --git a/dts/bindings/interrupt-controller/snps,arcv2-intc.yaml b/dts/bindings/interrupt-controller/snps,arcv2-intc.yaml index 4ea7c1c7fbb8..999cbfc9d208 100644 --- a/dts/bindings/interrupt-controller/snps,arcv2-intc.yaml +++ b/dts/bindings/interrupt-controller/snps,arcv2-intc.yaml @@ -5,7 +5,7 @@ # --- title: ARCV2 Interrupt Controller -id: snps,arcv2-intc +type: interrupt-controller version: 0.1 description: > @@ -17,6 +17,7 @@ properties: type: string description: compatible strings constraint: "snps,arcv2-intc" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/snps,designware-intc.yaml b/dts/bindings/interrupt-controller/snps,designware-intc.yaml index 8fcef832d84c..c01da3138534 100644 --- a/dts/bindings/interrupt-controller/snps,designware-intc.yaml +++ b/dts/bindings/interrupt-controller/snps,designware-intc.yaml @@ -1,5 +1,6 @@ --- title: DesignWare Interrupt Controller +type: interrupt-controller version: 0.1 description: > @@ -11,6 +12,7 @@ properties: type: string description: compatible strings constraint: "snps,designware-intc" + generation: define reg: category: required diff --git a/dts/bindings/interrupt-controller/xtensa,intc.yaml b/dts/bindings/interrupt-controller/xtensa,intc.yaml index 0825bb8438d4..48328033fe29 100644 --- a/dts/bindings/interrupt-controller/xtensa,intc.yaml +++ b/dts/bindings/interrupt-controller/xtensa,intc.yaml @@ -1,5 +1,6 @@ --- title: Xtensa Core Interrupt Controller +type: interrupt-controller version: 0.1 description: > @@ -11,6 +12,7 @@ properties: type: string description: compatible strings constraint: "xtensa,core-intc" + generation: define reg: category: required diff --git a/dts/bindings/led/nxp,pca9633.yaml b/dts/bindings/led/nxp,pca9633.yaml index 62a2517bb830..221d7ce5765c 100644 --- a/dts/bindings/led/nxp,pca9633.yaml +++ b/dts/bindings/led/nxp,pca9633.yaml @@ -1,6 +1,6 @@ --- title: NXP PCA9633 LED Driver -id: nxp,pca9633 +type: led version: 0.1 description: NXP PCA9633 LED binding @@ -10,8 +10,5 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,pca9633" ... diff --git a/dts/bindings/led/ti,lp3943.yaml b/dts/bindings/led/ti,lp3943.yaml index 57b8145cdbea..379235b20e90 100644 --- a/dts/bindings/led/ti,lp3943.yaml +++ b/dts/bindings/led/ti,lp3943.yaml @@ -1,6 +1,6 @@ --- title: TI LP3943 LED Driver -id: ti,lp3943 +type: led version: 0.1 description: TI LP3943 LED binding @@ -10,8 +10,5 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "ti,lp3943" ... diff --git a/dts/bindings/led/ti,lp5562.yaml b/dts/bindings/led/ti,lp5562.yaml index b161f1d08b7d..700a98ad85db 100644 --- a/dts/bindings/led/ti,lp5562.yaml +++ b/dts/bindings/led/ti,lp5562.yaml @@ -1,6 +1,6 @@ --- title: TI LP5562 LED Driver -id: ti,lp5562 +type: led version: 0.1 description: TI LP5562 LED binding diff --git a/dts/bindings/led_strip/apa,apa-102.yaml b/dts/bindings/led_strip/apa,apa-102.yaml index 4ee0464fd9e6..d1efb553f539 100644 --- a/dts/bindings/led_strip/apa,apa-102.yaml +++ b/dts/bindings/led_strip/apa,apa-102.yaml @@ -1,6 +1,6 @@ --- title: APA102 SPI LED strip -id: apa,apa102 +type: led-strip version: 0.1 description: APA102 SPI LED strip binding @@ -10,8 +10,5 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "apa,apa102" ... diff --git a/dts/bindings/memory-controllers/nxp,imx-semc.yaml b/dts/bindings/memory-controllers/nxp,imx-semc.yaml index e11578f47f96..8b5f7d99e2af 100644 --- a/dts/bindings/memory-controllers/nxp,imx-semc.yaml +++ b/dts/bindings/memory-controllers/nxp,imx-semc.yaml @@ -5,7 +5,7 @@ # --- title: NXP SEMC -id: nxp,imx-semc +type: memory-controllers version: 0.1 description: > @@ -18,6 +18,7 @@ properties: category: required description: compatible strings constraint: "nxp,imx-semc" + generation: define reg: type: array diff --git a/dts/bindings/modem/wnc,m14a2a.yaml b/dts/bindings/modem/wnc,m14a2a.yaml index 2617aa48f5c0..5182bdc4160c 100644 --- a/dts/bindings/modem/wnc,m14a2a.yaml +++ b/dts/bindings/modem/wnc,m14a2a.yaml @@ -5,7 +5,7 @@ # --- title: WNC-M14A2A LTE-M Modem -id: wnc,m14a2a +type: modem version: 0.1 description: > @@ -19,6 +19,7 @@ properties: type: string category: required constraint: "wnc,m14a2a" + generation: define mdm-boot-mode-sel-gpios: type: compound diff --git a/dts/bindings/mtd/partition.yaml b/dts/bindings/mtd/partition.yaml index 2e193631be1b..13f05bd08948 100644 --- a/dts/bindings/mtd/partition.yaml +++ b/dts/bindings/mtd/partition.yaml @@ -1,6 +1,6 @@ --- title: Flash Partitions -id: fixed-partition +type: mtd version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "fixed-partitions" + generation: define partition\d+: type: string diff --git a/dts/bindings/mtd/soc-nv-flash.yaml b/dts/bindings/mtd/soc-nv-flash.yaml index edd60243abf6..38a9660e9488 100644 --- a/dts/bindings/mtd/soc-nv-flash.yaml +++ b/dts/bindings/mtd/soc-nv-flash.yaml @@ -1,6 +1,6 @@ --- title: Flash base node description -id: soc-nv-flash +type: mtd version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "soc-nv-flash" + generation: define label: type: string diff --git a/dts/bindings/pinctrl/atmel,sam0-pinmux.yaml b/dts/bindings/pinctrl/atmel,sam0-pinmux.yaml index 66afb6164f58..ce34487b20d7 100644 --- a/dts/bindings/pinctrl/atmel,sam0-pinmux.yaml +++ b/dts/bindings/pinctrl/atmel,sam0-pinmux.yaml @@ -1,6 +1,6 @@ --- title: Atmel SAM0 PINMUX -id: atmel,sam0-pinmux +type: pinmux version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "atmel,sam0-pinmux" + generation: define reg: type: int diff --git a/dts/bindings/pinctrl/nxp,kinetis-pinmux.yaml b/dts/bindings/pinctrl/nxp,kinetis-pinmux.yaml index b368eaf2dd9c..c0772fc2aa25 100644 --- a/dts/bindings/pinctrl/nxp,kinetis-pinmux.yaml +++ b/dts/bindings/pinctrl/nxp,kinetis-pinmux.yaml @@ -1,6 +1,6 @@ --- title: Kinetis Pinmux -id: nxp,kinetis-pinmux +type: pinmux version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "nxp,kinetis-pinmux" + generation: define reg: type: int diff --git a/dts/bindings/pinctrl/st,stm32-pinmux.yaml b/dts/bindings/pinctrl/st,stm32-pinmux.yaml index 72d6fe0d0f01..cd4ceabd3312 100644 --- a/dts/bindings/pinctrl/st,stm32-pinmux.yaml +++ b/dts/bindings/pinctrl/st,stm32-pinmux.yaml @@ -1,6 +1,6 @@ --- title: STM32 PINMUX -id: st,stm32-pinmux +type: pinmux version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "st,stm32-pinmux" + generation: define reg: type: int diff --git a/dts/bindings/pinctrl/ti,cc2650-pinmux.yaml b/dts/bindings/pinctrl/ti,cc2650-pinmux.yaml index 623bc97d7c19..9809fded75b5 100644 --- a/dts/bindings/pinctrl/ti,cc2650-pinmux.yaml +++ b/dts/bindings/pinctrl/ti,cc2650-pinmux.yaml @@ -1,6 +1,7 @@ --- # SPDX-License-Identifier: Apache-2.0 title: TI CC2650 Pinmux +type: pinmux version: 0.1 description: > @@ -12,6 +13,7 @@ properties: category: required description: compatible strings constraint: "ti,cc2650-pinmux" + generation: define reg: type: int diff --git a/dts/bindings/pwm/fsl,imx7d-pwm.yaml b/dts/bindings/pwm/fsl,imx7d-pwm.yaml index 6661771ce524..583d3e3d4edf 100644 --- a/dts/bindings/pwm/fsl,imx7d-pwm.yaml +++ b/dts/bindings/pwm/fsl,imx7d-pwm.yaml @@ -5,7 +5,6 @@ # --- title: i.MX7D PWM -id: fsl,imx7d-pwm version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "fsl,imx7d-pwm" reg: diff --git a/dts/bindings/pwm/nxp,kinetis-ftm.yaml b/dts/bindings/pwm/nxp,kinetis-ftm.yaml index 1b21157fd827..1c5253752023 100644 --- a/dts/bindings/pwm/nxp,kinetis-ftm.yaml +++ b/dts/bindings/pwm/nxp,kinetis-ftm.yaml @@ -5,7 +5,6 @@ # --- title: Kinetis FTM -id: nxp,kinetis-ftm version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-ftm" reg: diff --git a/dts/bindings/pwm/pwm.yaml b/dts/bindings/pwm/pwm.yaml index 91ab63137fc3..40b37b385cf8 100644 --- a/dts/bindings/pwm/pwm.yaml +++ b/dts/bindings/pwm/pwm.yaml @@ -5,13 +5,19 @@ # --- title: PWM Base Structure -id: pwm +type: pwm version: 0.1 description: > This binding gives the base structures for all PWM devices properties: + compatible: + type: string + category: required + description: compatible strings + generation: define + clocks: type: array category: required diff --git a/dts/bindings/pwm/sifive,pwm0.yaml b/dts/bindings/pwm/sifive,pwm0.yaml index aa42da305bfb..9cba4ed68ea0 100644 --- a/dts/bindings/pwm/sifive,pwm0.yaml +++ b/dts/bindings/pwm/sifive,pwm0.yaml @@ -5,7 +5,6 @@ # --- title: SiFive PWM -id: sifive,pwm0 version: 0.1 description: > diff --git a/dts/bindings/pwm/st,stm32-pwm.yaml b/dts/bindings/pwm/st,stm32-pwm.yaml index b9e9a62a2e89..4c8c058f7db2 100644 --- a/dts/bindings/pwm/st,stm32-pwm.yaml +++ b/dts/bindings/pwm/st,stm32-pwm.yaml @@ -1,6 +1,5 @@ --- title: STM32 PWM -id: st,stm32-pwm version: 0.1 description: > @@ -8,9 +7,6 @@ description: > properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-pwm" label: diff --git a/dts/bindings/rtc/intel,qmsi-rtc.yaml b/dts/bindings/rtc/intel,qmsi-rtc.yaml index 32b9eaa164bf..9e2ffc8b1c89 100644 --- a/dts/bindings/rtc/intel,qmsi-rtc.yaml +++ b/dts/bindings/rtc/intel,qmsi-rtc.yaml @@ -5,7 +5,6 @@ # --- title: Intel QMSI RTC -id: intel,qmsi-rtc version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "intel,qmsi-rtc" reg: diff --git a/dts/bindings/rtc/nxp,kinetis-rtc.yaml b/dts/bindings/rtc/nxp,kinetis-rtc.yaml index 6098f7f0de39..c19c18831ee6 100644 --- a/dts/bindings/rtc/nxp,kinetis-rtc.yaml +++ b/dts/bindings/rtc/nxp,kinetis-rtc.yaml @@ -5,7 +5,6 @@ # --- title: Kinetis RTC -id: nxp,kinetis-rtc version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-rtc" reg: diff --git a/dts/bindings/rtc/rtc.yaml b/dts/bindings/rtc/rtc.yaml index 36ff04bf20ff..f232df60bcd7 100644 --- a/dts/bindings/rtc/rtc.yaml +++ b/dts/bindings/rtc/rtc.yaml @@ -5,7 +5,7 @@ # --- title: RTC Base Structure -id: rtc +type: rtc version: 0.1 description: > @@ -13,6 +13,11 @@ description: > properties: + compatible: + type: string + category: required + description: compatible strings + generation: define clock-frequency: type: int category: optional diff --git a/dts/bindings/rtc/st,stm32-rtc.yaml b/dts/bindings/rtc/st,stm32-rtc.yaml index 81b6b7e5eb1b..49890a07538f 100644 --- a/dts/bindings/rtc/st,stm32-rtc.yaml +++ b/dts/bindings/rtc/st,stm32-rtc.yaml @@ -5,7 +5,6 @@ # --- title: STM32 RTC -id: st,stm32-rtc version: 0.1 description: > diff --git a/dts/bindings/sensor/adi,adt7420.yaml b/dts/bindings/sensor/adi,adt7420.yaml index f9702f1b6fff..368d2ec78bec 100644 --- a/dts/bindings/sensor/adi,adt7420.yaml +++ b/dts/bindings/sensor/adi,adt7420.yaml @@ -5,7 +5,7 @@ # --- title: ADT7420 16-Bit Digital I2C Temperature Sensor -id: adi,adt7420 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/ams,ccs811.yaml b/dts/bindings/sensor/ams,ccs811.yaml index 14a4fe87f259..2f70916c8858 100644 --- a/dts/bindings/sensor/ams,ccs811.yaml +++ b/dts/bindings/sensor/ams,ccs811.yaml @@ -5,7 +5,7 @@ # --- title: AMS (Austria Mikro Systeme) Digital Air Quality Sensor CCS811 -id: ams,ccs811 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/avago,apds9960.yaml b/dts/bindings/sensor/avago,apds9960.yaml index 953a74984778..d3ca9fee3ec4 100644 --- a/dts/bindings/sensor/avago,apds9960.yaml +++ b/dts/bindings/sensor/avago,apds9960.yaml @@ -5,7 +5,7 @@ # --- title: APDS9960 Digital Proximity, Ambient Light, RGB and Gesture Sensor -id: avago,apds9960 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/max,max30101.yaml b/dts/bindings/sensor/max,max30101.yaml index 244e1bc054ec..e89c89669706 100644 --- a/dts/bindings/sensor/max,max30101.yaml +++ b/dts/bindings/sensor/max,max30101.yaml @@ -5,7 +5,7 @@ # --- title: MAX30101 heart rate sensor -id: nxp,max30101 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/nxp,fxas21002.yaml b/dts/bindings/sensor/nxp,fxas21002.yaml index 715637566202..e92254d33b3d 100644 --- a/dts/bindings/sensor/nxp,fxas21002.yaml +++ b/dts/bindings/sensor/nxp,fxas21002.yaml @@ -5,7 +5,7 @@ # --- title: FXAS21002 3-axis gyroscope -id: nxp,fxas21002 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/nxp,fxos8700.yaml b/dts/bindings/sensor/nxp,fxos8700.yaml index d475bd27cc3d..7b3d13f9ca5a 100644 --- a/dts/bindings/sensor/nxp,fxos8700.yaml +++ b/dts/bindings/sensor/nxp,fxos8700.yaml @@ -5,7 +5,7 @@ # --- title: FXOS8700 6-axis accelerometer/magnetometer -id: nxp,fxos8700 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/nxp,mma8451q.yaml b/dts/bindings/sensor/nxp,mma8451q.yaml index fc91be430120..64bdb458ac9d 100644 --- a/dts/bindings/sensor/nxp,mma8451q.yaml +++ b/dts/bindings/sensor/nxp,mma8451q.yaml @@ -5,7 +5,7 @@ # --- title: MMA8451Q 3-axis Accelerometer -id: nxp,mma8451q +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,hts221.yaml b/dts/bindings/sensor/st,hts221.yaml index 1d930b73bfd7..777ff1f542af 100644 --- a/dts/bindings/sensor/st,hts221.yaml +++ b/dts/bindings/sensor/st,hts221.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors HTS221 -id: st,hts221 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,lis3mdl-magn.yaml b/dts/bindings/sensor/st,lis3mdl-magn.yaml index 066c29331901..2175e9618eb5 100644 --- a/dts/bindings/sensor/st,lis3mdl-magn.yaml +++ b/dts/bindings/sensor/st,lis3mdl-magn.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors LIS3MDL -id: st,lis3mdl-magn +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,lps22hb-press.yaml b/dts/bindings/sensor/st,lps22hb-press.yaml index 919d8ebb313b..d90a87de58e1 100644 --- a/dts/bindings/sensor/st,lps22hb-press.yaml +++ b/dts/bindings/sensor/st,lps22hb-press.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors LPS22HB -id: st,lps22hb-press +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,lps25hb-press.yaml b/dts/bindings/sensor/st,lps25hb-press.yaml index 74224a966f3e..90f696a3f3b0 100644 --- a/dts/bindings/sensor/st,lps25hb-press.yaml +++ b/dts/bindings/sensor/st,lps25hb-press.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors LPS25HB -id: st,lps25hb-press +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,lsm6ds0.yaml b/dts/bindings/sensor/st,lsm6ds0.yaml index b821f22f9ab3..0cf0c1340f52 100644 --- a/dts/bindings/sensor/st,lsm6ds0.yaml +++ b/dts/bindings/sensor/st,lsm6ds0.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors LSM6DS0 -id: st,lsm6ds0 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,lsm6dsl-spi.yaml b/dts/bindings/sensor/st,lsm6dsl-spi.yaml index e76322ddb4ab..bc33286c2d73 100644 --- a/dts/bindings/sensor/st,lsm6dsl-spi.yaml +++ b/dts/bindings/sensor/st,lsm6dsl-spi.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors LSM6DSL SPI -id: st,lsm6dsl-spi +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,lsm6dsl.yaml b/dts/bindings/sensor/st,lsm6dsl.yaml index 729c6eb59667..59b481cca2b7 100644 --- a/dts/bindings/sensor/st,lsm6dsl.yaml +++ b/dts/bindings/sensor/st,lsm6dsl.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors LSM6DSL -id: st,lsm6dsl +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/st,vl53l0x.yaml b/dts/bindings/sensor/st,vl53l0x.yaml index f38f80db2f93..d01a789928a3 100644 --- a/dts/bindings/sensor/st,vl53l0x.yaml +++ b/dts/bindings/sensor/st,vl53l0x.yaml @@ -5,7 +5,7 @@ # --- title: STMicroelectronics MEMS sensors VL53L0X -id: st,vl53l0x +type: sensor version: 0.1 description: > diff --git a/dts/bindings/sensor/ti,hdc1008.yaml b/dts/bindings/sensor/ti,hdc1008.yaml index d08869a8e1e3..7375b06cae6b 100644 --- a/dts/bindings/sensor/ti,hdc1008.yaml +++ b/dts/bindings/sensor/ti,hdc1008.yaml @@ -5,7 +5,7 @@ # --- title: HDC1008 Temperature and Humidity Sensor -id: ti,hdc1008 +type: sensor version: 0.1 description: > diff --git a/dts/bindings/serial/altera,jtag-uart.yaml b/dts/bindings/serial/altera,jtag-uart.yaml index 3aefbe5ebd11..103b8e54065c 100644 --- a/dts/bindings/serial/altera,jtag-uart.yaml +++ b/dts/bindings/serial/altera,jtag-uart.yaml @@ -1,6 +1,5 @@ --- title: Altera JTAG UART -id: altera,jtag-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "altera,jtag-uart" reg: diff --git a/dts/bindings/serial/arm,cmsdk-uart.yaml b/dts/bindings/serial/arm,cmsdk-uart.yaml index 3833699a038f..b96a28b039f2 100644 --- a/dts/bindings/serial/arm,cmsdk-uart.yaml +++ b/dts/bindings/serial/arm,cmsdk-uart.yaml @@ -1,6 +1,5 @@ --- title: ARM CMSDK UART -id: arm,cmsdk-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "arm,cmsdk-uart" reg: diff --git a/dts/bindings/serial/atmel,sam-uart.yaml b/dts/bindings/serial/atmel,sam-uart.yaml index 2a9b6a9e0a25..dbe1293d24e8 100644 --- a/dts/bindings/serial/atmel,sam-uart.yaml +++ b/dts/bindings/serial/atmel,sam-uart.yaml @@ -1,6 +1,5 @@ --- title: SAM Family UART -id: atmel,sam-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "atmel,sam-uart" reg: diff --git a/dts/bindings/serial/atmel,sam-usart.yaml b/dts/bindings/serial/atmel,sam-usart.yaml index f6ba47b8e79a..8b6b356d5444 100644 --- a/dts/bindings/serial/atmel,sam-usart.yaml +++ b/dts/bindings/serial/atmel,sam-usart.yaml @@ -1,6 +1,5 @@ --- title: Atmel SAM Family USART -id: atmel,sam-usart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "atmel,sam-usart" reg: diff --git a/dts/bindings/serial/atmel,sam0-uart.yaml b/dts/bindings/serial/atmel,sam0-uart.yaml index 43de0b32cd19..13b5c5e91d8c 100644 --- a/dts/bindings/serial/atmel,sam0-uart.yaml +++ b/dts/bindings/serial/atmel,sam0-uart.yaml @@ -1,6 +1,5 @@ --- title: Atmel SAM0 SERCOM UART driver -id: atmel,sam0-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "atmel,sam0-uart" reg: diff --git a/dts/bindings/serial/intel,qmsi-uart.yaml b/dts/bindings/serial/intel,qmsi-uart.yaml index 76cfdadbfce6..3f37f6b0ad8c 100644 --- a/dts/bindings/serial/intel,qmsi-uart.yaml +++ b/dts/bindings/serial/intel,qmsi-uart.yaml @@ -5,7 +5,6 @@ # --- title: Intel QMSI Uart -id: intel,qmsi-uart version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "intel,qmsi-uart" reg: diff --git a/dts/bindings/serial/nordic,nrf-uart.yaml b/dts/bindings/serial/nordic,nrf-uart.yaml index 4025b1651645..af7072f83141 100644 --- a/dts/bindings/serial/nordic,nrf-uart.yaml +++ b/dts/bindings/serial/nordic,nrf-uart.yaml @@ -1,6 +1,5 @@ --- title: Nordic UART -id: nordic,nrf-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nordic,nrf-uart" reg: diff --git a/dts/bindings/serial/nordic,nrf-uarte.yaml b/dts/bindings/serial/nordic,nrf-uarte.yaml index 9e18bfc6765a..3796a4dd8c41 100644 --- a/dts/bindings/serial/nordic,nrf-uarte.yaml +++ b/dts/bindings/serial/nordic,nrf-uarte.yaml @@ -1,6 +1,5 @@ --- title: Nordic UARTE -id: nordic,nrf-uarte version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nordic,nrf-uarte" reg: diff --git a/dts/bindings/serial/ns16550.yaml b/dts/bindings/serial/ns16550.yaml index 26da78123513..cce1bd331848 100644 --- a/dts/bindings/serial/ns16550.yaml +++ b/dts/bindings/serial/ns16550.yaml @@ -1,6 +1,5 @@ --- title: ns16550 -id: ns16550 version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "ns16550" reg: diff --git a/dts/bindings/serial/nxp,imx-uart.yaml b/dts/bindings/serial/nxp,imx-uart.yaml index 9e6bdd85a16f..a667bd43c17f 100644 --- a/dts/bindings/serial/nxp,imx-uart.yaml +++ b/dts/bindings/serial/nxp,imx-uart.yaml @@ -5,7 +5,6 @@ # --- title: iMX Uart -id: nxp,imx-uart version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,imx-uart" reg: diff --git a/dts/bindings/serial/nxp,kinetis-lpsci.yaml b/dts/bindings/serial/nxp,kinetis-lpsci.yaml index 32af1cf3bca9..3d0a2065e31c 100644 --- a/dts/bindings/serial/nxp,kinetis-lpsci.yaml +++ b/dts/bindings/serial/nxp,kinetis-lpsci.yaml @@ -1,6 +1,5 @@ --- title: Kinetis LPSCI UART -id: nxp,kinetis-lpsci version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-lpsci" reg: diff --git a/dts/bindings/serial/nxp,kinetis-lpuart.yaml b/dts/bindings/serial/nxp,kinetis-lpuart.yaml index 44da06b2ea2e..00fe7c0ff4e8 100644 --- a/dts/bindings/serial/nxp,kinetis-lpuart.yaml +++ b/dts/bindings/serial/nxp,kinetis-lpuart.yaml @@ -1,6 +1,5 @@ --- title: Kinetis LPUART -id: nxp,kinetis-lpuart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-lpuart" reg: diff --git a/dts/bindings/serial/nxp,kinetis-uart.yaml b/dts/bindings/serial/nxp,kinetis-uart.yaml index e264f37de01f..ac31c162f3e6 100644 --- a/dts/bindings/serial/nxp,kinetis-uart.yaml +++ b/dts/bindings/serial/nxp,kinetis-uart.yaml @@ -1,6 +1,5 @@ --- title: Kinetis UART -id: nxp,kinetis-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-uart" reg: diff --git a/dts/bindings/serial/nxp,lpc-usart.yaml b/dts/bindings/serial/nxp,lpc-usart.yaml index a5e14ed0c3af..dd3a792ce6af 100644 --- a/dts/bindings/serial/nxp,lpc-usart.yaml +++ b/dts/bindings/serial/nxp,lpc-usart.yaml @@ -5,7 +5,6 @@ # --- title: LPC USART -id: nxp,lpc-usart version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,lpc-usart" reg: diff --git a/dts/bindings/serial/riscv,qemu-uart.yaml b/dts/bindings/serial/riscv,qemu-uart.yaml index 01c98b931f39..bdf8d11b5bfc 100644 --- a/dts/bindings/serial/riscv,qemu-uart.yaml +++ b/dts/bindings/serial/riscv,qemu-uart.yaml @@ -1,6 +1,5 @@ --- title: RISCV QEMU UART -id: riscv,qemu-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "riscv,qemu-uart" reg: diff --git a/dts/bindings/serial/sifive,uart0.yaml b/dts/bindings/serial/sifive,uart0.yaml index 44cc22dac0ee..88caf4c521fc 100644 --- a/dts/bindings/serial/sifive,uart0.yaml +++ b/dts/bindings/serial/sifive,uart0.yaml @@ -5,7 +5,6 @@ # --- title: SIFIVE UART -id: sifive,uart0 version: 0.1 description: > diff --git a/dts/bindings/serial/silabs,efm32-uart.yaml b/dts/bindings/serial/silabs,efm32-uart.yaml index c23857476e11..901e26c73eaa 100644 --- a/dts/bindings/serial/silabs,efm32-uart.yaml +++ b/dts/bindings/serial/silabs,efm32-uart.yaml @@ -1,6 +1,5 @@ --- title: EFM32 UART -id: silabs,efm32-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "silabs,efm32-uart" reg: diff --git a/dts/bindings/serial/silabs,efm32-usart.yaml b/dts/bindings/serial/silabs,efm32-usart.yaml index 7da6bde7030a..40d58da913de 100644 --- a/dts/bindings/serial/silabs,efm32-usart.yaml +++ b/dts/bindings/serial/silabs,efm32-usart.yaml @@ -1,6 +1,5 @@ --- title: EFM32 USART -id: silabs,efm32-usart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "silabs,efm32-usart" reg: diff --git a/dts/bindings/serial/st,stm32-lpuart.yaml b/dts/bindings/serial/st,stm32-lpuart.yaml index 2e23737fdb54..93e072399e73 100644 --- a/dts/bindings/serial/st,stm32-lpuart.yaml +++ b/dts/bindings/serial/st,stm32-lpuart.yaml @@ -1,6 +1,5 @@ --- title: STM32 LPUART -id: st,stm32-lpuart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-lpuart" reg: diff --git a/dts/bindings/serial/st,stm32-uart.yaml b/dts/bindings/serial/st,stm32-uart.yaml index 5b5fae66d9dd..10965c376869 100644 --- a/dts/bindings/serial/st,stm32-uart.yaml +++ b/dts/bindings/serial/st,stm32-uart.yaml @@ -1,6 +1,5 @@ --- title: STM32 UART -id: st,stm32-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-uart" reg: diff --git a/dts/bindings/serial/st,stm32-usart.yaml b/dts/bindings/serial/st,stm32-usart.yaml index ee09aea9d7a2..44bee5ecc5c9 100644 --- a/dts/bindings/serial/st,stm32-usart.yaml +++ b/dts/bindings/serial/st,stm32-usart.yaml @@ -1,6 +1,5 @@ --- title: STM32 USART -id: st,stm32-usart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-usart" reg: diff --git a/dts/bindings/serial/ti,cc32xx-uart.yaml b/dts/bindings/serial/ti,cc32xx-uart.yaml index 06b75c93d84f..a97f04218996 100644 --- a/dts/bindings/serial/ti,cc32xx-uart.yaml +++ b/dts/bindings/serial/ti,cc32xx-uart.yaml @@ -1,6 +1,5 @@ --- title: TI CC32XX Uart -id: ti,cc32xx-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "ti,cc32xx-uart" reg: diff --git a/dts/bindings/serial/ti,msp432p4xx-uart.yaml b/dts/bindings/serial/ti,msp432p4xx-uart.yaml index 89be9677c3f8..949e775386b4 100644 --- a/dts/bindings/serial/ti,msp432p4xx-uart.yaml +++ b/dts/bindings/serial/ti,msp432p4xx-uart.yaml @@ -1,6 +1,5 @@ --- title: TI MSP432P4XX UART -id: ti,msp432p4xx-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "ti,msp432p4xx-uart" reg: diff --git a/dts/bindings/serial/ti,stellaris-uart.yaml b/dts/bindings/serial/ti,stellaris-uart.yaml index abb20a6f920c..42eaa833b87f 100644 --- a/dts/bindings/serial/ti,stellaris-uart.yaml +++ b/dts/bindings/serial/ti,stellaris-uart.yaml @@ -1,6 +1,5 @@ --- title: TI Stellaris UART -id: ti,stellaris-uart version: 0.1 description: > @@ -11,9 +10,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "ti,stellaris-uart" reg: diff --git a/dts/bindings/serial/uart-device.yaml b/dts/bindings/serial/uart-device.yaml index 68c18ca0fdb9..9c27ecb73870 100644 --- a/dts/bindings/serial/uart-device.yaml +++ b/dts/bindings/serial/uart-device.yaml @@ -5,7 +5,7 @@ # --- title: UART Device Base Structure -id: uart-device +type: uart-device version: 0.1 description: > @@ -19,6 +19,7 @@ properties: type: string category: required description: compatible strings + generation: define label: type: string category: required diff --git a/dts/bindings/serial/uart.yaml b/dts/bindings/serial/uart.yaml index 195f40636b7a..8f353d2e399b 100644 --- a/dts/bindings/serial/uart.yaml +++ b/dts/bindings/serial/uart.yaml @@ -1,6 +1,6 @@ --- title: Uart Base Structure -id: uart +type: uart version: 0.1 description: > @@ -10,6 +10,11 @@ child: bus: uart properties: + compatible: + type: string + category: required + description: compatible strings + generation: define clock-frequency: type: int category: optional diff --git a/dts/bindings/spi/atmel,sam0-spi.yaml b/dts/bindings/spi/atmel,sam0-spi.yaml index 3e21eb0ef46f..a8881bc49b86 100644 --- a/dts/bindings/spi/atmel,sam0-spi.yaml +++ b/dts/bindings/spi/atmel,sam0-spi.yaml @@ -5,7 +5,6 @@ # --- title: Atmel SAM0 SERCOM SPI driver -id: atmel,sam0-spi version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "atmel,sam0-spi" reg: diff --git a/dts/bindings/spi/nordic,nrf-spi.yaml b/dts/bindings/spi/nordic,nrf-spi.yaml index c1b564ab5fba..92d8fa78a279 100644 --- a/dts/bindings/spi/nordic,nrf-spi.yaml +++ b/dts/bindings/spi/nordic,nrf-spi.yaml @@ -5,7 +5,6 @@ # --- title: Nordic nRF Family SPI Master node -id: nordic,nrf-spi version: 0.1 description: > diff --git a/dts/bindings/spi/nxp,imx-flexspi.yaml b/dts/bindings/spi/nxp,imx-flexspi.yaml index db0d18bf1436..dfefda25144c 100644 --- a/dts/bindings/spi/nxp,imx-flexspi.yaml +++ b/dts/bindings/spi/nxp,imx-flexspi.yaml @@ -5,7 +5,6 @@ # --- title: NXP FlexSPI -id: nxp,imx-flexspi version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,imx-flexspi" reg: diff --git a/dts/bindings/spi/nxp,kinetis-dspi.yaml b/dts/bindings/spi/nxp,kinetis-dspi.yaml index 3f09560c5bbc..5bf114608971 100644 --- a/dts/bindings/spi/nxp,kinetis-dspi.yaml +++ b/dts/bindings/spi/nxp,kinetis-dspi.yaml @@ -5,7 +5,6 @@ # --- title: NXP DSPI -id: nxp,kinetis-dspi version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "nxp,kinetis-dspi" reg: diff --git a/dts/bindings/spi/sifive,spi0.yaml b/dts/bindings/spi/sifive,spi0.yaml index 30722c87454b..897f86f65531 100644 --- a/dts/bindings/spi/sifive,spi0.yaml +++ b/dts/bindings/spi/sifive,spi0.yaml @@ -5,7 +5,6 @@ # --- title: Sifive SPI driver -id: sifive,spi0 version: 0.1 description: > diff --git a/dts/bindings/spi/snps,designware-spi.yaml b/dts/bindings/spi/snps,designware-spi.yaml index c80f323e004d..a86e9cb66289 100644 --- a/dts/bindings/spi/snps,designware-spi.yaml +++ b/dts/bindings/spi/snps,designware-spi.yaml @@ -5,7 +5,6 @@ # --- title: Synopsys Designware SPI Controller -id: snps,designware-spi version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "snps,designware-spi" reg: diff --git a/dts/bindings/spi/spi-device.yaml b/dts/bindings/spi/spi-device.yaml index 74c15c1ea8a1..ce82e049c022 100644 --- a/dts/bindings/spi/spi-device.yaml +++ b/dts/bindings/spi/spi-device.yaml @@ -5,7 +5,7 @@ # --- title: SPI Device Base Structure -id: spi-device +type: spi-device version: 0.1 description: > @@ -19,6 +19,7 @@ properties: type: string category: required description: compatible strings + generation: define reg: type: array description: Chip select address of device diff --git a/dts/bindings/spi/spi.yaml b/dts/bindings/spi/spi.yaml index 92ac952669ea..656532100047 100644 --- a/dts/bindings/spi/spi.yaml +++ b/dts/bindings/spi/spi.yaml @@ -5,7 +5,7 @@ # --- title: SPI Base Structure -id: spi +type: spi version: 0.1 description: > @@ -15,6 +15,11 @@ child: bus: spi properties: + compatible: + type: string + category: required + description: compatible strings + generation: define "#address-cells": type: int category: required diff --git a/dts/bindings/spi/st,stm32-spi-fifo.yaml b/dts/bindings/spi/st,stm32-spi-fifo.yaml index ceb61c44b00f..aa9ae3042d89 100644 --- a/dts/bindings/spi/st,stm32-spi-fifo.yaml +++ b/dts/bindings/spi/st,stm32-spi-fifo.yaml @@ -5,7 +5,6 @@ # --- title: STM32 SPI FIFO -id: st,stm32-spi-fifo version: 0.1 description: > @@ -17,9 +16,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-spi-fifo" reg: diff --git a/dts/bindings/spi/st,stm32-spi.yaml b/dts/bindings/spi/st,stm32-spi.yaml index d09d8628d6c4..fa17741d192e 100644 --- a/dts/bindings/spi/st,stm32-spi.yaml +++ b/dts/bindings/spi/st,stm32-spi.yaml @@ -5,7 +5,6 @@ # --- title: STM32 SPI -id: st,stm32-spi version: 0.1 description: > @@ -16,9 +15,6 @@ inherits: properties: compatible: - type: string - category: required - description: compatible strings constraint: "st,stm32-spi" reg: diff --git a/dts/bindings/timer/arm,cmsdk-dtimer.yaml b/dts/bindings/timer/arm,cmsdk-dtimer.yaml index be52e78b5365..49ab9bdd9317 100644 --- a/dts/bindings/timer/arm,cmsdk-dtimer.yaml +++ b/dts/bindings/timer/arm,cmsdk-dtimer.yaml @@ -1,6 +1,6 @@ --- title: ARM CMSDK DUALTIMER -id: arm,cmsdk-dtimer +type: timer version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "arm,cmsdk-dtimer" + generation: define reg: type: array diff --git a/dts/bindings/timer/arm,cmsdk-timer.yaml b/dts/bindings/timer/arm,cmsdk-timer.yaml index 74af075dfbc7..c2361049db3d 100644 --- a/dts/bindings/timer/arm,cmsdk-timer.yaml +++ b/dts/bindings/timer/arm,cmsdk-timer.yaml @@ -1,6 +1,6 @@ --- title: ARM CMSDK TIMER -id: arm,cmsdk-timer +type: timer version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "arm,cmsdk-timer" + generation: define reg: type: array diff --git a/dts/bindings/timer/st,stm32-timers.yaml b/dts/bindings/timer/st,stm32-timers.yaml index 5d92337fd3de..7a12ed3db68b 100644 --- a/dts/bindings/timer/st,stm32-timers.yaml +++ b/dts/bindings/timer/st,stm32-timers.yaml @@ -1,6 +1,6 @@ --- title: STM32 TIMERS -id: st,stm32-timers +type: timer version: 0.1 description: > @@ -21,6 +21,7 @@ properties: category: required description: compatible strings constraint: "st,stm32-timers" + generation: define label: type: string diff --git a/dts/bindings/usb/atmel,sam0-usb.yaml b/dts/bindings/usb/atmel,sam0-usb.yaml index 09fb157b9e29..beac93ee23bf 100644 --- a/dts/bindings/usb/atmel,sam0-usb.yaml +++ b/dts/bindings/usb/atmel,sam0-usb.yaml @@ -1,6 +1,5 @@ --- title: Atmel SAM0 USB device -id: atmel,sam0-usb version: 0.1 description: > diff --git a/dts/bindings/usb/nordic,nrf-usbd.yaml b/dts/bindings/usb/nordic,nrf-usbd.yaml index 41b0ec4704d9..fe903070aa16 100644 --- a/dts/bindings/usb/nordic,nrf-usbd.yaml +++ b/dts/bindings/usb/nordic,nrf-usbd.yaml @@ -5,7 +5,6 @@ # --- title: Nordic nRF52 USBD -id: nordic,nrf-usbd version: 0.1 description: > diff --git a/dts/bindings/usb/nxp,kinetis-usbd.yaml b/dts/bindings/usb/nxp,kinetis-usbd.yaml index 761040a65c7f..fcfb78d445b5 100644 --- a/dts/bindings/usb/nxp,kinetis-usbd.yaml +++ b/dts/bindings/usb/nxp,kinetis-usbd.yaml @@ -5,7 +5,6 @@ # --- title: NXP Kinetis USBD -id: nxp,kinetis-usbd version: 0.1 description: > diff --git a/dts/bindings/usb/st,stm32-otgfs.yaml b/dts/bindings/usb/st,stm32-otgfs.yaml index 2da75eed9f58..70d79fc7dd8f 100644 --- a/dts/bindings/usb/st,stm32-otgfs.yaml +++ b/dts/bindings/usb/st,stm32-otgfs.yaml @@ -5,7 +5,6 @@ # --- title: STM32 OTGFS -id: st,stm32-otgfs version: 0.1 description: > diff --git a/dts/bindings/usb/st,stm32-otghs.yaml b/dts/bindings/usb/st,stm32-otghs.yaml index 31f4af9c4d5e..98c567753445 100644 --- a/dts/bindings/usb/st,stm32-otghs.yaml +++ b/dts/bindings/usb/st,stm32-otghs.yaml @@ -5,7 +5,6 @@ # --- title: STM32 OTGHS -id: st,stm32-otghs version: 0.1 description: > diff --git a/dts/bindings/usb/st,stm32-usb.yaml b/dts/bindings/usb/st,stm32-usb.yaml index 1d321693b5fc..cba616ce557a 100644 --- a/dts/bindings/usb/st,stm32-usb.yaml +++ b/dts/bindings/usb/st,stm32-usb.yaml @@ -5,7 +5,6 @@ # --- title: STM32 USB -id: st,stm32-usb version: 0.1 description: > diff --git a/dts/bindings/usb/usb-ep.yaml b/dts/bindings/usb/usb-ep.yaml index 12d7108fdda9..432e24a1f100 100644 --- a/dts/bindings/usb/usb-ep.yaml +++ b/dts/bindings/usb/usb-ep.yaml @@ -5,7 +5,7 @@ # --- title: USB Endpoints' properties -id: USB-EP +type: USB-EP version: 0.1 description: > diff --git a/dts/bindings/usb/usb.yaml b/dts/bindings/usb/usb.yaml index 158f3c46daa3..3f8e97dd86f9 100644 --- a/dts/bindings/usb/usb.yaml +++ b/dts/bindings/usb/usb.yaml @@ -5,7 +5,7 @@ # --- title: USB Base Structure -id: USB +type: USB version: 0.1 description: > @@ -16,6 +16,7 @@ properties: type: string category: required description: compatible strings + generation: define label: type: string diff --git a/dts/bindings/watchdog/arm,cmsdk-watchdog.yaml b/dts/bindings/watchdog/arm,cmsdk-watchdog.yaml index b98699a7d831..d1debac39247 100644 --- a/dts/bindings/watchdog/arm,cmsdk-watchdog.yaml +++ b/dts/bindings/watchdog/arm,cmsdk-watchdog.yaml @@ -1,6 +1,6 @@ --- title: ARM CMSDK WATCHDOG -id: arm,cmsdk-watchdog +type: watchdog version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "arm,cmsdk-watchdog" + generation: define reg: type: array diff --git a/dts/bindings/watchdog/atmel,sam0-watchdog.yaml b/dts/bindings/watchdog/atmel,sam0-watchdog.yaml index 308b61f93f4f..1eda6821cfec 100644 --- a/dts/bindings/watchdog/atmel,sam0-watchdog.yaml +++ b/dts/bindings/watchdog/atmel,sam0-watchdog.yaml @@ -1,6 +1,6 @@ --- title: Atmel SAM0 watchdog driver -id: atmel,sam0-watchdog +type: watchdog version: 0.1 description: > @@ -12,6 +12,7 @@ properties: category: required description: compatible strings constraint: "atmel,sam0-watchdog" + generation: define reg: type: int diff --git a/dts/bindings/watchdog/nordic,nrf-watchdog.yaml b/dts/bindings/watchdog/nordic,nrf-watchdog.yaml index ebfabe9946b4..8c9490f80db4 100644 --- a/dts/bindings/watchdog/nordic,nrf-watchdog.yaml +++ b/dts/bindings/watchdog/nordic,nrf-watchdog.yaml @@ -5,7 +5,7 @@ # --- title: Nordic Semiconductor NRF watchdog driver -id: nordic,nrf-watchdog +type: watchdog version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nordic,nrf-watchdog" + generation: define reg: type: int diff --git a/dts/bindings/watchdog/nxp,kinetis-wdog.yaml b/dts/bindings/watchdog/nxp,kinetis-wdog.yaml index 392fcf83169f..3cc39e9fab5f 100644 --- a/dts/bindings/watchdog/nxp,kinetis-wdog.yaml +++ b/dts/bindings/watchdog/nxp,kinetis-wdog.yaml @@ -5,7 +5,7 @@ # --- title: NXP Kinetis watchdog driver -id: nxp,kinetis-wdog +type: nxp,kinetis-wdog version: 0.1 description: > @@ -17,6 +17,7 @@ properties: category: required description: compatible strings constraint: "nxp,kinetis-wdog" + generation: define reg: type: int diff --git a/scripts/codegen/cmake.py b/scripts/codegen/cmake.py new file mode 100644 index 000000000000..eedc0be56c07 --- /dev/null +++ b/scripts/codegen/cmake.py @@ -0,0 +1,191 @@ +# Copyright (c) 2018 Open Source Foundries Limited. +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 +# +# CMakeCacheEntry and CMakeCache are taken from scripts/zephyr_run.py. +# + +import os +import sys +import re +from collections import OrderedDict +from pathlib import Path + + +class CMakeCacheEntry: + '''Represents a CMake cache entry. + This class understands the type system in a CMakeCache.txt, and + converts the following cache types to Python types: + Cache Type Python type + ---------- ------------------------------------------- + FILEPATH str + PATH str + STRING str OR list of str (if ';' is in the value) + BOOL bool + INTERNAL str OR list of str (if ';' is in the value) + ---------- ------------------------------------------- + ''' + + # Regular expression for a cache entry. + # + # CMake variable names can include escape characters, allowing a + # wider set of names than is easy to match with a regular + # expression. To be permissive here, use a non-greedy match up to + # the first colon (':'). This breaks if the variable name has a + # colon inside, but it's good enough. + CACHE_ENTRY = re.compile( + r'''(?P<name>.*?) # name + :(?P<type>FILEPATH|PATH|STRING|BOOL|INTERNAL) # type + =(?P<value>.*) # value + ''', re.X) + + @classmethod + def _to_bool(cls, val): + # Convert a CMake BOOL string into a Python bool. + # + # "True if the constant is 1, ON, YES, TRUE, Y, or a + # non-zero number. False if the constant is 0, OFF, NO, + # FALSE, N, IGNORE, NOTFOUND, the empty string, or ends in + # the suffix -NOTFOUND. Named boolean constants are + # case-insensitive. If the argument is not one of these + # constants, it is treated as a variable." + # + # https://cmake.org/cmake/help/v3.0/command/if.html + val = val.upper() + if val in ('ON', 'YES', 'TRUE', 'Y'): + return True + elif val in ('OFF', 'NO', 'FALSE', 'N', 'IGNORE', 'NOTFOUND', ''): + return False + elif val.endswith('-NOTFOUND'): + return False + else: + try: + v = int(val) + return v != 0 + except ValueError as exc: + raise ValueError('invalid bool {}'.format(val)) from exc + + @classmethod + def from_line(cls, line, line_no): + # Comments can only occur at the beginning of a line. + # (The value of an entry could contain a comment character). + if line.startswith('//') or line.startswith('#'): + return None + + # Whitespace-only lines do not contain cache entries. + if not line.strip(): + return None + + m = cls.CACHE_ENTRY.match(line) + if not m: + return None + + name, type_, value = (m.group(g) for g in ('name', 'type', 'value')) + if type_ == 'BOOL': + try: + value = cls._to_bool(value) + except ValueError as exc: + args = exc.args + ('on line {}: {}'.format(line_no, line),) + raise ValueError(args) from exc + elif type_ == 'STRING' or type_ == 'INTERNAL': + # If the value is a CMake list (i.e. is a string which + # contains a ';'), convert to a Python list. + if ';' in value: + value = value.split(';') + + return CMakeCacheEntry(name, value) + + def __init__(self, name, value): + self.name = name + self.value = value + + def __str__(self): + fmt = 'CMakeCacheEntry(name={}, value={})' + return fmt.format(self.name, self.value) + + +class CMakeCache: + '''Parses and represents a CMake cache file.''' + + def __init__(self, cache_file): + self.load(cache_file) + + def load(self, cache_file): + entries = [] + with open(str(cache_file), 'r') as cache: + for line_no, line in enumerate(cache): + entry = CMakeCacheEntry.from_line(line, line_no) + if entry: + entries.append(entry) + self._entries = OrderedDict((e.name, e) for e in entries) + + def get(self, name, default=None): + entry = self._entries.get(name) + if entry is not None: + return entry.value + else: + return default + + def get_list(self, name, default=None): + if default is None: + default = [] + entry = self._entries.get(name) + if entry is not None: + value = entry.value + if isinstance(value, list): + return value + elif isinstance(value, str): + return [value] + else: + msg = 'invalid value {} type {}' + raise RuntimeError(msg.format(value, type(value))) + else: + return default + + def __getitem__(self, name): + return self._entries[name].value + + def __setitem__(self, name, entry): + if not isinstance(entry, CMakeCacheEntry): + msg = 'improper type {} for value {}, expecting CMakeCacheEntry' + raise TypeError(msg.format(type(entry), entry)) + self._entries[name] = entry + + def __delitem__(self, name): + del self._entries[name] + + def __iter__(self): + return iter(self._entries.values()) + + +class CMakeMixin(object): + __slots__ = [] + + _cmake_cache = None + + def cmake_variable(self, variable_name, default="<unset>"): + variable_value = self.options.defines.get(variable_name, default) + if variable_value == "<unset>": + raise self._get_error_exception( + "CMake variable '{}' not defined.".format(variable_name), 1) + return variable_value + + def cmake_cache_variable(self, variable_name, default="<unset>"): + if self._cmake_cache is None: + cache_file = self.cmake_variable("CMAKE_BINARY_DIR") + cache_file = Path(cache_file).joinpath("CMakeCache.txt") + if not cache_file.is_file(): + raise self._get_error_exception( + "CMake cache file '{}' does not exist or is no file.". + format(cache_file), 1) + self._cmake_cache = CMakeCache(cache_file) + try: + return self._cmake_cache.get(variable_name) + except: + if default == "<unset>": + raise self._get_error_exception( + "CMake variable '{}' not defined in cache file.". + format(variable_name), 1) + return default + diff --git a/scripts/codegen/codegen.py b/scripts/codegen/codegen.py new file mode 100644 index 000000000000..296ae8101d66 --- /dev/null +++ b/scripts/codegen/codegen.py @@ -0,0 +1,630 @@ +# Copyright 2004-2016, Ned Batchelder. +# http://nedbatchelder.com/code/cog +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import sys +import os +import imp +import inspect +import re +from traceback import TracebackException + +from .whiteutils import * +from .filereader import NumberedFileReader +from .options import Options, OptionsMixin +from .generic import GenericMixin +from .guard import GuardMixin +from .config import ConfigMixin +from .cmake import CMakeMixin +from .zephyr import ZephyrMixin +from .edts import EDTSMixin +from .include import IncludeMixin +from .log import LogMixin +from .error import ErrorMixin, Error +from .output import OutputMixin +from .importmodule import ImportMixin +from .redirectable import Redirectable, RedirectableMixin + +class CodeGenerator(OptionsMixin, GenericMixin, ConfigMixin, + CMakeMixin, ZephyrMixin, EDTSMixin, GuardMixin, + IncludeMixin, LogMixin, ErrorMixin, OutputMixin, + ImportMixin, RedirectableMixin): + + code_start_marker = b'@code{.codegen}' + code_end_marker = b'@endcode{.codegen}' + code_insert_marker = b'@code{.codeins}@endcode' + + def __init__(self, processor, globals={}, + output_file=None, snippet_file = None): + self._stdout = sys.stdout + self._stderr = sys.stderr + self._outstring = '' + # code snippet markers and lines + self._start_marker = self.code_start_marker.decode('utf-8') + self._end_marker = self.code_end_marker.decode('utf-8') + self._insert_marker = self.code_insert_marker.decode('utf-8') + self.markers = [] + self.lines = [] + # The processor that is using this generator + self.processor = processor + self.options = processor.options + # All generators of a file usually work on the same global namespace + self.generator_globals = globals + self._output_file = output_file + # The file that contains the snippet + self._snippet_file = snippet_file + # The snippet this generator works on + self._snippet = None + # the snippet start offset in original file + self._snippet_offset = None + # the tab size in the snippet + self._snippet_tabsize = 8 + # the current evaluation start offset in the original file + # may be different to snippet offset during evaluation + self._eval_offset = None + # the previous output + self._previous = '' + + def line_is_start_marker(self, s): + return self._start_marker in s + + def line_is_end_marker(self, s): + return self._end_marker in s and not self.line_is_insert_marker(s) + + def line_is_insert_marker(self, s): + return self._insert_marker in s + + def parse_start_marker(self, l, snippet_offset): + self._snippet_offset = snippet_offset + self._eval_offset = snippet_offset + self.markers.append(l.expandtabs(self._snippet_tabsize)) + + def parse_end_marker(self, l): + self.markers.append(l.expandtabs(self._snippet_tabsize)) + + def parse_line(self, l, single_line_snippet=False): + l = l.expandtabs(self._snippet_tabsize).strip('\n') + if single_line_snippet: + # single line snippets contain the markers - remove them + beg = l.find(self._start_marker) + end = l.find(self._end_marker) + if beg > end: + self.lines.append(l) + self.error("Codegen code markers inverted", + frame_index = -2) + else: + l = l[beg+len(self._start_marker):end].strip() + self.lines.append(l) + + def _out(self, output='', dedent=False, trimblanklines=False): + if trimblanklines and ('\n' in output): + lines = output.split('\n') + if lines[0].strip() == '': + del lines[0] + if lines and lines[-1].strip() == '': + del lines[-1] + output = '\n'.join(lines)+'\n' + if dedent: + output = reindentBlock(output) + self._outstring += output + + ## + # @brief Re-indent a code block. + # + # Take a block of text as a string or list of lines. + # Remove any common prefix and whitespace indentation. + # Re-indent using new_indent + # + # @param lines + # @param common_prefix + # @param new_indent + # @return indented code block as a single string. + def _reindent_code(self, lines, common_prefix = '', new_indent=''): + if not isinstance(lines, list): + lines = lines.split('\n') + # remove common prefix + code_lines = [] # all code lines + code_no_white_lines = [] # code lines excluding white space lines + for line in lines: + line = line.expandtabs() + if common_prefix: + line = line.replace(common_prefix, '', 1) + code_lines.append(line) + if line and not line.isspace(): + code_no_white_lines.append(line) + # remove common white space and re-indent + out_lines = [] + common_white = os.path.commonprefix(code_no_white_lines) + common_white = re.search(r'\s*', common_white).group(0) + for line in code_lines: + if common_white: + line = line.replace(common_white, '', 1) + if line and new_indent: + line = new_indent + line + out_lines.append(line) + return '\n'.join(out_lines) + + ## + # @brief Extract the executable Python code from the generator. + # + def _get_code(self, fname, snippet_offset): + # If the markers and lines all have the same prefix + # (end-of-line comment chars, for example), + # then remove it from all the lines. + common_prefix = os.path.commonprefix(self.markers + self.lines) + if not common_prefix: + # there may be a prefix error + # just do some heuristics + if fname.endswith( + ('.h', '.hxx', '.c', '.cpp', '.cxx')): + # assume C/C++ comments + for line in (self.markers + self.lines): + if line.strip().startswith('*'): + common_prefix = '*' + break + elif line.strip().startswith('//'): + common_prefix = '//' + break + if common_prefix: + # there should be a common prefix -> error + lines = list() # lines with correct prefix + for lineno, line in enumerate(self.lines): + if not line.strip().startswith(common_prefix): + print("Codegen: Comment prefix may miss in codegen snippet (+{}) in '{}'.".format( + snippet_offset, fname)) + line_start = lineno - 5 + if line_start < 0: + line_start = 0 + line_end = lineno + 5 + if line_end > len(self.lines): + line_end = len(self.lines) + for i in range(line_start, line_end): + snippet_lineno = i + 2 + input_lineno = snippet_offset + snippet_lineno + print("#{} (+{}, line {}): {}".format( + input_lineno, snippet_offset, snippet_lineno, self.lines[i])) + else: + lines.append(line) + if len(lines) >= int(len(self.lines) / 2): + common_prefix = os.path.commonprefix(lines) + print("Codegen: Assuming comment prefix '{}' for codegen snippet (+{}) in '{}'.".format( + common_prefix, snippet_offset, fname)) + else: + common_prefix = '' + if common_prefix: + self.markers = [ line.replace(common_prefix, '', 1) for line in self.markers ] + code = self._reindent_code(self.lines, common_prefix) + return code + + # Make sure the "codegen" (alias cog) module has our state. + def _set_module_state(self): + restore_state = {} + module_states = self.processor.module_states + module = self.processor.cogmodule + # General module values + restore_state['inFile'] = getattr(module, 'inFile', None) + module.inFile = self._snippet_file + restore_state['outFile'] = getattr(module, 'outFile', None) + module.outFile = self._output_file + restore_state['firstLineNum'] = getattr(module, 'firstLineNum', None) + module.firstLineNum = self._snippet_offset + restore_state['previous'] = getattr(module, 'previous', None) + module.previous = self._previous + # CodeGenerator access + restore_state['options'] = getattr(module, 'options', None) + module.options = self.options + restore_state['Error'] = getattr(module, 'Error', None) + module.Error = self._get_error_exception + # Look for the Mixin classes + for base_cls in inspect.getmro(CodeGenerator): + if "Mixin" in base_cls.__name__: + for member_name, member_value in inspect.getmembers(base_cls): + if member_name.startswith('_'): + continue + if inspect.isroutine(member_value): + restore_state[member_name] = \ + getattr(module, member_name, None) + setattr(module, member_name, + getattr(self, member_name)) + module_states.append(restore_state) + + def _restore_module_state(self): + module_states = self.processor.module_states + module = self.processor.cogmodule + restore_state = module_states.pop() + # General module values + module.inFile = restore_state['inFile'] + module.outFile = restore_state['outFile'] + module.firstLineNum = restore_state['firstLineNum'] + module.previous = restore_state['previous'] + # CodeGenerator access + module.options = restore_state['options'] + module.Error = restore_state['Error'] + # Look for the Mixin classes + for base_cls in inspect.getmro(CodeGenerator): + if "Mixin" in base_cls.__name__: + for member_name, member_value in inspect.getmembers(base_cls): + if member_name.startswith('_'): + continue + if inspect.isroutine(member_value): + setattr(module, member_name, restore_state[member_name]) + + ## + # @brief snippet id to be used in logging and error reporting + # + # Accounts for extra lines added during evaluation + # + def _get_snippet_id(self): + return "+{}".format(self._eval_offset) + + ## + # @brief get snippet line number from evaluation line number + # + # Accounts for extra lines added during evaluation + # + # @param eval_lineno line number as reported from python code eval + def _get_snippet_lineno(self, eval_lineno): + return int(eval_lineno) + self._eval_offset - self._snippet_offset + + def _list_snippet(self): + if not self._snippet: + return None + listing = "" + for i, line in enumerate(self._snippet.splitlines()): + eval_lineno = i + 2 + input_lineno = self._eval_offset + eval_lineno + if i > 0: + listing += "\n" + listing += "#{} ({}, line {}): {}".format( + input_lineno, self._get_snippet_id(), eval_lineno, line) + return listing + + def _list_lines(self): + if len(self.lines) == 0: + return None + listing = "" + for i, line in enumerate(self.lines): + eval_lineno = i + 2 + input_lineno = self._eval_offset + eval_lineno + if i > 0: + listing += "\n" + listing += "#{} ({}, line {}): {}".format( + input_lineno, self._get_snippet_id(), eval_lineno, line) + return listing + + ## + # @brief evaluate + # + def evaluate(self): + self._snippet = self._get_code(self._snippet_file, self._snippet_offset) + if not self._snippet: + return '' + + # we add an extra line 'import codegen' + # to snippet so account for that + self._eval_offset = self._snippet_offset - 1 + + # In Python 2.2, the last line has to end in a newline. + eval_code = "import codegen\n" + self._snippet + "\n" + eval_fname = "{} {}".format(self._snippet_file, self._get_snippet_id()) + + try: + code = compile(eval_code, eval_fname, 'exec') + except: + exc_type, exc_value, exc_tb = sys.exc_info() + exc_traceback = TracebackException(exc_type, exc_value, exc_tb) + self.error( + "compile exception '{}' within snippet in {}".format( + exc_value, self._snippet_file), + frame_index = -2, + snippet_lineno = exc_traceback.lineno) + + # Make sure the "codegen" (alias cog) module has our state. + self._set_module_state() + + self._outstring = '' + try: + eval(code, self.generator_globals) + except: + exc_type, exc_value, exc_tb = sys.exc_info() + if exc_type is Error: + # Exception raise by CodeGen means + raise + # Not raised by Codegen means - add some info + print("Codegen: eval exception within codegen snippet ({}) in {}".format( + self._get_snippet_id(), self._snippet_file)) + for i, line in enumerate(self._snippet.splitlines()): + eval_lineno = i + 2 + input_lineno = self._eval_offset + eval_lineno + print("#{} ({}, line {}): {}".format(input_lineno, self._get_snippet_id(), eval_lineno, line)) + raise + finally: + self._restore_module_state() + + # We need to make sure that the last line in the output + # ends with a newline, or it will be joined to the + # end-output line, ruining cog's idempotency. + if self._outstring and self._outstring[-1] != '\n': + self._outstring += '\n' + + # end of evaluation - no extra offset anymore + self._eval_offset = self._snippet_offset + + # figure out the right whitespace prefix for the output + prefOut = whitePrefix(self.markers) + self._previous = reindentBlock(self._outstring, prefOut) + return self._previous + +## +# @brief The code generation processor +# +class CodeGen(Redirectable): + + def __init__(self): + Redirectable.__init__(self) + # Stack of module states + self.module_states = [] + self.options = Options() + # assure codegen module is installed + self._install_codegen_module() + + ## + # @brief Is this a trailing line after an end spec marker. + # + # @todo Make trailing end spec line detection dependent on + # type of text or file type. + # + # @param s line + # + def _is_end_spec_trailer(self, s): + return '*/' in s + + def _install_codegen_module(self): + """ Magic mumbo-jumbo so that imported Python modules + can say "import codegen" and get our state. + + Make us the module, and not our parent cog. + """ + self.cogmodule = imp.new_module('codegen') + self.cogmodule.path = [] + sys.modules['codegen'] = self.cogmodule + + def openOutputFile(self, fname): + """ Open an output file, taking all the details into account. + """ + opts = {} + mode = "w" + opts['encoding'] = self.options.sEncoding + if self.options.bNewlines: + opts['newline'] = "\n" + fdir = os.path.dirname(fname) + if os.path.dirname(fdir) and not os.path.exists(fdir): + os.makedirs(fdir) + return open(fname, mode, **opts) + + def openInputFile(self, fname): + """ Open an input file. """ + if fname == "-": + return sys.stdin + else: + opts = {} + opts['encoding'] = self.options.sEncoding + return open(fname, "r", **opts) + + ## + # @brief Process an input file object to an output file object. + # + # May be called recursively + # + # @param fIn input file object, or file name + # @param fOut output file object, or file name + # @param fname [optional] + # @param globals [optional] + # + def process_file(self, fIn, fOut, fname=None, globals=None): + + fInToClose = fOutToClose = None + # Convert filenames to files. + if isinstance(fIn, (str, bytes)): + # Open the input file. + sFileIn = fIn + fIn = fInToClose = self.openInputFile(fIn) + elif hasattr(fIn, 'name'): + sFileIn = fIn.name + else: + sFileIn = fname or '' + if isinstance(fOut, (str, bytes)): + # Open the output file. + sFileOut = fOut + fOut = fOutToClose = self.openOutputFile(fOut) + elif hasattr(fOut, 'name'): + sFileOut = fOut.name + else: + sFileOut = fname or '' + + try: + fIn = NumberedFileReader(fIn) + + bSawCog = False + + # The globals dict we will use for this file. + if globals is None: + globals = {} + # list of include files that are guarded against inclusion + globals['_guard_include'] = [] + + # If there are any global defines, put them in the globals. + globals.update(self.options.defines) + + # global flag for code generation + globals['_generate_code'] = True + + # loop over generator chunks + l = fIn.readline() + gen = None + while l and globals['_generate_code']: + + if gen is None: + # have a generator ready + # for marker check and error reporting + gen = CodeGenerator(self, globals, sFileOut, str(sFileIn)) + gen.setOutput(stdout=self._stdout) + + # Find the next spec begin + while l and not gen.line_is_start_marker(l): + if gen.line_is_end_marker(l): + gen._snippet_offset = fIn.linenumber() + gen.error("Unexpected '%s'" % gen._end_marker, + frame_index=-1, snippet_lineno=0) + if gen.line_is_insert_marker(l): + gen._snippet_offset = fIn.linenumber() + gen.error("Unexpected '%s'" % gen._insert_marker, + frame_index=-1, snippet_lineno=0) + fOut.write(l) + l = fIn.readline() + if not l: + break + if not self.options.bDeleteCode: + fOut.write(l) + + # l is the begin spec + firstLineNum = fIn.linenumber() + # Start parsing the inline code spec + # Assure a new generator is in use + gen = CodeGenerator(self, globals, sFileOut, str(sFileIn)) + gen.setOutput(stdout=self._stdout) + gen.parse_start_marker(l, firstLineNum) + + gen.log('s{}: process {} #{}'.format(len(self.module_states), sFileIn, firstLineNum)) + # If the spec begin is also a spec end, then process the single + # line of code inside. + if gen.line_is_end_marker(l): + gen.parse_line(l, True) + # next line + l = fIn.readline() + else: + # Deal with an ordinary code block. + l = fIn.readline() + + # Get all the lines in the spec + while l and not gen.line_is_end_marker(l): + gen.parse_line(l) + if gen.line_is_start_marker(l): + gen.error("Code followed by unexpected '%s'" % gen._start_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + if gen.line_is_insert_marker(l): + gen.error("Code followed by unexpected '%s'" % gen._insert_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + if not self.options.bDeleteCode: + fOut.write(l) + l = fIn.readline() + if not l: + gen.error("Codegen block begun but never ended.", + frame_index = -2, snippet_lineno = 0) + # write out end spec line + if not self.options.bDeleteCode: + fOut.write(l) + gen.parse_end_marker(l) + # next line - may be trailing end spec line + l = fIn.readline() + if self._is_end_spec_trailer(l) and not gen.line_is_insert_marker(l): + fOut.write(l) + l = fIn.readline() + + # Eat all the lines in the output section. + while l and not gen.line_is_insert_marker(l): + if gen.line_is_start_marker(l): + gen.error("Unexpected '%s'" % gen._start_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + if gen.line_is_end_marker(l): + gen.error("Unexpected '%s'" % gen._end_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + l = fIn.readline() + + if not l: + # We reached end of file before we found the end output line. + gen.error("Missing '%s' before end of file." % gen._insert_marker, + frame_index = -2, + snippet_lineno = fIn.linenumber() - firstLineNum) + + # Write the output of the spec to be the new output if we're + # supposed to generate code. + if not self.options.bNoGenerate: + sGen = gen.evaluate() + fOut.write(sGen) + if not globals['_generate_code']: + # generator code snippet stopped code generation + break + + bSawCog = True + + if not self.options.bDeleteCode: + fOut.write(l) + l = fIn.readline() + + if not bSawCog and self.options.bWarnEmpty: + self.warning("no codegen code found in %s" % sFileIn) + finally: + if fInToClose: + fInToClose.close() + if fOutToClose: + fOutToClose.close() + + def saveIncludePath(self): + self.savedInclude = self.options.includePath[:] + self.savedSysPath = sys.path[:] + + def restoreIncludePath(self): + self.options.includePath = self.savedInclude + self.cogmodule.path = self.options.includePath + sys.path = self.savedSysPath + + def addToIncludePath(self, includePath): + self.cogmodule.path.extend(includePath) + sys.path.extend(includePath) + + ## + # @brief process one file through CodeGen + # + # @param sFile file name + # + def _process_one_file(self, sFile): + """ Process one filename through cog. + """ + + self.saveIncludePath() + bNeedNewline = False + + try: + self.addToIncludePath(self.options.includePath) + # Since we know where the input file came from, + # push its directory onto the include path. + self.addToIncludePath([os.path.dirname(sFile)]) + + # How we process the file depends on where the output is going. + if self.options.sOutputName: + self.process_file(sFile, self.options.sOutputName, sFile) + else: + self.process_file(sFile, self.stdout, sFile) + finally: + self.restoreIncludePath() + + def callableMain(self, argv): + """ All of command-line codegen, but in a callable form. + This is used by main. + argv is the equivalent of sys.argv. + """ + argv = argv[1:] + + self.options.parse_args(argv) + + if self.options.input_file is None: + raise FileNotFoundError("No files to process") + + self._process_one_file(self.options.input_file) diff --git a/scripts/codegen/config.py b/scripts/codegen/config.py new file mode 100644 index 000000000000..02c45f7a68ca --- /dev/null +++ b/scripts/codegen/config.py @@ -0,0 +1,56 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys +import shlex +from pathlib import Path + +class ConfigMixin(object): + __slots__ = [] + + _autoconf = None + _autoconf_filename = None + + def _autoconf_assure(self): + if self._autoconf is None: + autoconf_file = self.cmake_variable("PROJECT_BINARY_DIR", None) + if autoconf_file is None: + raise self._get_error_exception( + "CMake variable PROJECT_BINARY_DIR not defined to codegen.", 2) + autoconf_file = Path(autoconf_file).joinpath('include/generated/autoconf.h') + if not autoconf_file.is_file(): + raise self._get_error_exception( + "Generated configuration {} not found/ no access.". + format(autoconf_file), 2) + autoconf = {} + with open(str(autoconf_file)) as autoconf_fd: + for line in autoconf_fd: + if not line.startswith('#'): + continue + if " " not in line: + continue + key, value = shlex.split(line)[1:] + autoconf[key] = value + self._autoconf = autoconf + self._autoconf_filename = str(autoconf_file) + + def config_property(self, property_name, default="<unset>"): + self._autoconf_assure() + property_value = self._autoconf.get(property_name, default) + if property_value == "<unset>": + raise self._get_error_exception( + "Config property '{}' not defined.".format(property_name), 1) + return property_value + + ## + # @brief Get all config properties. + # + # The property names are the ones autoconf.conf. + # + # @return A dictionary of config properties. + # + def config_properties(self): + self._autoconf_assure() + return self._autoconf diff --git a/scripts/codegen/edts.py b/scripts/codegen/edts.py new file mode 100644 index 000000000000..a89b4205b413 --- /dev/null +++ b/scripts/codegen/edts.py @@ -0,0 +1,31 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path +from dts.edtsdatabase import EDTSDatabase + +class EDTSMixin(object): + __slots__ = [] + + _edts = None + + def _edts_assure(self): + if self._edts is None: + edts_file = self.cmake_variable("GENERATED_DTS_BOARD_EDTS") + edts_file = Path(edts_file) + if not edts_file.is_file(): + raise self._get_error_exception( + "Generated extended device tree database file '{}' not found/ no access.". + format(edts_file), 2) + self._edts = EDTSDatabase() + self._edts.load(str(edts_file)) + + ## + # @brief Get the extended device tree database. + # + # @return Extended device tree database. + # + def edts(self): + self._edts_assure() + return self._edts diff --git a/scripts/codegen/error.py b/scripts/codegen/error.py new file mode 100644 index 000000000000..56cf4ddb2a6b --- /dev/null +++ b/scripts/codegen/error.py @@ -0,0 +1,68 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import inspect +from pathlib import Path + +class Error(Exception): + pass + +class ErrorMixin(object): + __slots__ = [] + + ## + # @brief Get code generation error exception + # + # @note only for 'raise codegen.Error(msg)' in snippet + # + # @param msg exception message + # @param frame_index [optional] call frame index + # @param snippet_lineno [optional] line number within snippet + # @return code generation exception object + # + def _get_error_exception(self, msg, frame_index = 0, + snippet_lineno = 0): + if frame_index >= 0: + # There are frames to get data from + frame_index += 1 + frame = inspect.currentframe() + try: + while frame_index > 0: + frame = frame.f_back + frame_index -= 1 + (filename, snippet_lineno, function, code_context, index) = \ + inspect.getframeinfo(frame) + except: + pass + finally: + del frame + input_lineno = self._snippet_offset + self._get_snippet_lineno(snippet_lineno) + error_msg = "{} #{} ({}, line {}): {}".format( + Path(self._snippet_file).name, + input_lineno, self._get_snippet_id(), + snippet_lineno, msg) + listing = self._list_snippet() + if listing: + error_msg = listing + '\n' + error_msg + else: + listing = self._list_lines() + if listing: + error_msg= listing + '\n' + error_msg + return Error(error_msg) + + ## + # @brief Raise Error exception. + # + # Extra information is added that maps the python snippet + # line seen by the Python interpreter to the line of the file + # that inlines the python snippet. + # + # @param msg [optional] exception message + # @param frame_index [optional] call frame index + # @param snippet_lineno [optional] line number within snippet + # + def error(self, msg = 'Error raised by codegen generator.', + frame_index = 0, snippet_lineno = 0): + frame_index += 1 + raise self._get_error_exception(msg, frame_index, snippet_lineno) diff --git a/scripts/codegen/filereader.py b/scripts/codegen/filereader.py new file mode 100644 index 000000000000..c567a5ca24df --- /dev/null +++ b/scripts/codegen/filereader.py @@ -0,0 +1,20 @@ +# Copyright 2004-2016, Ned Batchelder. +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +class NumberedFileReader: + """ A decorator for files that counts the readline()'s called. + """ + def __init__(self, f): + self.f = f + self.n = 0 + + def readline(self): + l = self.f.readline() + if l: + self.n += 1 + return l + + def linenumber(self): + return self.n diff --git a/scripts/codegen/generic.py b/scripts/codegen/generic.py new file mode 100644 index 000000000000..07e89bcaeed5 --- /dev/null +++ b/scripts/codegen/generic.py @@ -0,0 +1,51 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path + +class GenericMixin(object): + __slots__ = [] + + @staticmethod + def path_walk(top, topdown = False, followlinks = False): + """ + See Python docs for os.walk, exact same behavior but it yields Path() + instances instead + + Form: http://ominian.com/2016/03/29/os-walk-for-pathlib-path/ + """ + names = list(top.iterdir()) + + dirs = (node for node in names if node.is_dir() is True) + nondirs = (node for node in names if node.is_dir() is False) + + if topdown: + yield top, dirs, nondirs + + for name in dirs: + if followlinks or name.is_symlink() is False: + for x in path_walk(name, topdown, followlinks): + yield x + + if topdown is not True: + yield top, dirs, nondirs + + # + # @param marker Marker as b'my-marker' + # + @staticmethod + def template_files(top, marker, suffix='.c'): + sources = [] + for path, directory_names, file_names in CodeGen.path_walk(top): + sources.extend([x for x in file_names if x.suffix == suffix]) + + templates = [] + for source_file in sources: + if os.stat(source_file).st_size == 0: + continue + with open(source_file, 'rb', 0) as source_file_fd: + s = mmap.mmap(source_file_fd.fileno(), 0, access=mmap.ACCESS_READ) + if s.find(marker) != -1: + templates.append(source_file) + return templates diff --git a/scripts/codegen/guard.py b/scripts/codegen/guard.py new file mode 100644 index 000000000000..0cf8a11a22eb --- /dev/null +++ b/scripts/codegen/guard.py @@ -0,0 +1,16 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +class GuardMixin(object): + __slots__ = [] + + + def outl_guard_config(self, property_name): + is_config = self.config_property(property_name, 0) + self.outl("#if {} // Guard({}) {}".format( + is_config, is_config, property_name)) + + def outl_unguard_config(self, property_name): + is_config = self.config_property(property_name, 0) + self.outl("#endif // Guard({}) {}".format(is_config, property_name)) diff --git a/scripts/codegen/importmodule.py b/scripts/codegen/importmodule.py new file mode 100644 index 000000000000..3f4e632059d9 --- /dev/null +++ b/scripts/codegen/importmodule.py @@ -0,0 +1,37 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import sys +import os +import importlib +from pathlib import Path + +class ImportMixin(object): + __slots__ = [] + + ## + # @brief Import a CodeGen module. + # + # Import a module from the codegen/modules package. + # + # @param name Module to import. Specified without any path. + # + def import_module(self, name): + try: + module_file = self.zephyr_path().joinpath( + "scripts/codegen/modules/{}.py".format(name)).resolve() + except FileNotFoundError: + # Python 3.4/3.5 will throw this exception + # Python >= 3.6 will not throw this exception + module_file = self.zephyr_path().joinpath( + "scripts/codegen/modules/{}.py".format(name)) + if not module_file.is_file(): + raise self._get_error_exception( + "Module file '{}' of module '{}' does not exist or is no file.". + format(module_file, name), 1) + sys.path.append(os.path.dirname(str(module_file))) + module = importlib.import_module(name) + sys.path.pop() + self.generator_globals[name] = module + diff --git a/scripts/codegen/include.py b/scripts/codegen/include.py new file mode 100644 index 000000000000..54ea51d48eba --- /dev/null +++ b/scripts/codegen/include.py @@ -0,0 +1,67 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path +import io + +from .error import Error + +class IncludeMixin(object): + __slots__ = [] + + def out_include(self, include_file): + try: + input_file = Path(include_file).resolve() + except FileNotFoundError: + # Python 3.4/3.5 will throw this exception + # Python >= 3.6 will not throw this exception + input_file = Path(include_file) + if not input_file.is_file(): + # don't resolve upfront + input_file = Path(include_file) + # try to find the file in the templates directory + expanded_file_path = self.zephyr_path().joinpath( + "scripts/codegen/templates") + if 'templates' in input_file.parts: + templates_seen = False + else: + # assume the path starts after templates + templates_seen = True + # append the remaining part behind templates + for part in input_file.parts: + if templates_seen: + expanded_file_path = expanded_file_path.joinpath(part) + elif part is 'templates': + templates_seen = True + if expanded_file_path.is_file(): + input_file = expanded_file_path + if not input_file.is_file(): + raise self._get_error_exception( + "Include file '{}' does not exist or is no file.". + format(input_file), 1) + if str(input_file) in self.generator_globals['_guard_include']: + self.log('------- include guarded {} - multiple inclusion of include file.'. + format(str(input_file))) + else: + output_fd = io.StringIO() + # delete inline code in included files + delete_code = self.processor.options.bDeleteCode + self.processor.options.bDeleteCode = True + self.log('------- include start {}'.format(input_file)) + self.processor.process_file(str(input_file), output_fd, + globals=self.generator_globals) + self.log(output_fd.getvalue()) + self.log('------- include end {}'.format(input_file)) + self.processor.options.bDeleteCode = delete_code + self.out(output_fd.getvalue()) + + def guard_include(self): + if self._snippet_file in self.generator_globals['_guard_include']: + # This should never happen + raise self._get_error_exception( + "Multiple inclusion of guarded include file '{}'.". + format(self._snippet_file), 1) + self.log('------- include guard {}'.format(self._snippet_file)) + self.generator_globals['_guard_include'].append(self._snippet_file) + diff --git a/scripts/codegen/log.py b/scripts/codegen/log.py new file mode 100644 index 000000000000..7ee81bad6ac6 --- /dev/null +++ b/scripts/codegen/log.py @@ -0,0 +1,41 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path + +class LogMixin(object): + __slots__ = [] + + _log_fd = None + + def log(self, message, message_type=None, end="\n", logonly=True): + if self._log_fd is None: + if self.options.log_file is not None: + log_file = Path(self.options.log_file) + if not log_file.is_file(): + # log file will be created + # add preamble + preamble = "My preamble\n{}".format(message) + self._log_fd = open(str(log_file), 'a') + if message_type is None: + message_type = '' + else: + message_type = message_type+': ' + if self._log_fd is not None: + for line in message.splitlines(): + self._log_fd.write("{}{}{}".format(message_type, line, end)) + if not logonly: + print(message_type+message, file=self._stderr, end=end) + + def msg(self, s): + self.log(s, message_type='message', logonly=False) + + def warning(self, s): + self.log(s, message_type='warning', logonly=False) + + def prout(self, s, end="\n"): + self.log(s, message_type=None, end=end, logonly=False) + + def prerr(self, s, end="\n"): + self.log(s, message_type='error', end=end, logonly=False) diff --git a/scripts/codegen/modules/__init__.py b/scripts/codegen/modules/__init__.py new file mode 100644 index 000000000000..270dcebaa5f4 --- /dev/null +++ b/scripts/codegen/modules/__init__.py @@ -0,0 +1 @@ +from .modules import * diff --git a/scripts/codegen/modules/devicedeclare.py b/scripts/codegen/modules/devicedeclare.py new file mode 100644 index 000000000000..35563f02ff49 --- /dev/null +++ b/scripts/codegen/modules/devicedeclare.py @@ -0,0 +1,389 @@ +# Copyright (c) 2018 Linaro Limited +# Copyright (c) 2018 Bobby Noelte +# +# SPDX-License-Identifier: Apache-2.0 + +import pprint +import re +import codegen + +from string import Template + +_device_and_api_init_tmpl = \ + 'DEVICE_AND_API_INIT( \\\n' + \ + '\t${device-name}, \\\n' + \ + '\t"${driver-name}", \\\n' + \ + '\t${device-init}, \\\n' + \ + '\t&${device-data}, \\\n' + \ + '\t&${device-config-info}, \\\n' + \ + '\t${device-level}, \\\n' + \ + '\t${device-prio}, \\\n' + \ + '\t&${device-api});' + +## +# Aliases for EDTS property paths. +_property_path_aliases = [ + ('reg/0/address/0', 'reg/address'), + ('reg/0/size/0', 'reg/size'), +] + +## +# @brief Get device name +# +# Device name is generated from +# - device compatible +# - bus master address if the device is connected to a bus master +# - device address +# - parent device address if the device does not have a device address +def _device_name(device_id): + device_name = codegen.edts().device_property(device_id, 'compatible/0', None) + if device_name is None: + codegen.error("No compatible property for device id '{}'." + .format(device_id)) + + bus_master_device_id = codegen.edts().device_property(device_id, 'bus/master', None) + if bus_master_device_id is not None: + reg = codegen.edts().device_property(bus_master_device_id, 'reg') + try: + # use always the first key to get first address inserted into dict + # because reg_index may be number or name + # reg/<reg_index>/address/<address_index> : address + for reg_index in reg: + for address_index in reg[reg_index]['address']: + bus = reg[reg_index]['address'][address_index] + device_name += '_' + hex(bus)[2:].zfill(8) + break + break + except: + # this device is missing the register directive + codegen.error("No bus master register address property for device id '{}'." + .format(bus_master_device_id)) + + reg = codegen.edts().device_property(device_id, 'reg', None) + if reg is None: + # no reg property - take the reg property of the parent device + parent_device_id = codegen.edts().device_property( + device_id, 'parent-device', None) + if parent_device_id: + reg = codegen.edts().device_property(parent_device_id, 'reg', None) + device_address = None + if reg is not None: + try: + # use always the first key to get first address inserted into dict + # because reg_index may be number or name + # reg/<reg_index>/address/<address_index> : address + for reg_index in reg: + for address_index in reg[reg_index]['address']: + address = reg[reg_index]['address'][address_index] + device_address = hex(address)[2:].zfill(8) + break + break + except: + # this device is missing the register directive + pass + if device_address is None: + # use label instead of address + device_address = codegen.edts().device_property(device_id, 'label', + '<unknown>') + # Warn about missing reg property + codegen.log("No register address property for device id '{}'." + .format(device_id), "warning", "\n") + device_name += '_' + device_address + + device_name = device_name.replace("-", "_"). \ + replace(",", "_"). \ + replace(";", "_"). \ + replace("@", "_"). \ + replace("#", "_"). \ + replace("&", "_"). \ + replace("/", "_"). \ + lower() + return device_name + +class _DeviceLocalTemplate(Template): + # pattern is ${<property_path>} + # never starts with / + # extend default pattern by '-' '/' ',' + idpattern = r'[_a-z][_a-z0-9\-/,]*' + + +class _DeviceGlobalTemplate(Template): + # pattern is ${<device-id>:<property_path>} + # device ID is the same as node address + # always starts with / + # extend default pattern by '-', '@', '/', ':' + idpattern = r'/[_a-z0-9\-/,@:]*' + +## +# @brief Substitude values in device template +# +def _device_template_substitute(template, device_id, preset={}): + # substitute device local placeholders ${<property_path>}, config, ... + mapping = {} + # add preset mapping + mapping.update(preset) + # add device properties from device tree + mapping.update(codegen.edts().device_properties_flattened(device_id)) + # add specific device declaration vars/ constants + mapping['device-name'] = mapping.get('device-name', + _device_name(device_id)) + mapping['driver-name'] = mapping.get('driver-name', + codegen.edts().device_property(device_id, 'label').strip('"')) + mapping['device-data'] = mapping.get('device-data', + "{}_data".format(mapping['device-name']).lower()) + mapping['device-config-info'] = mapping.get('device-config-info', + "{}_config".format(mapping['device-name']).lower()) + mapping['device-config-irq'] = mapping.get('device-config-irq', + "{}_config_irq".format(mapping['device-name']).lower()) + substituted = _DeviceLocalTemplate(template).safe_substitute(mapping) + + # substitute device global placeholders ${<device-id>:<property_path>} + # + # we need a second substitude to allow for device indirections + # ${${<property_path for device id>}:<property_path>} + mapping = {} + for device_id in codegen.edts()['devices']: + path_prefix = device_id + ':' + mapping.update(codegen.edts().device_properties_flattened(device_id, + path_prefix)) + # add specific device declaration vars/ constants + try: + mapping[path_prefix + 'device-name'] = _device_name(device_id) + mapping[path_prefix + 'driver-name'] = \ + codegen.edts().device_property(device_id, 'label').strip('"') + except: + # will be obvious if any of this is needed, just skip here + pass + + # add aliases to mapping + aliases_mapping = {} + for property_path, property_value in mapping.items(): + for alias_property_path, alias in _property_path_aliases: + if property_path.endswith(alias_property_path): + property_path = property_path[:-len(alias_property_path)] \ + + alias + aliases_mapping[property_path] = property_value + mapping.update(aliases_mapping) + + substituted = _DeviceGlobalTemplate(substituted).safe_substitute(mapping) + + return substituted + + +# +# @return True if device is declared, False otherwise +def device_declare_single(device_config, + driver_name, + device_init, + device_level, + device_prio, + device_api, + device_info, + device_defaults = {}): + device_configured = codegen.config_property(device_config, '<not-set>') + if device_configured == '<not-set>' or device_configured[-1] == '0': + # Not configured - do not generate + # + # The generation decision must be taken by codegen here + # (vs. #define CONFIG_xxx) to cope with the following situation: + # + # If config is not set the device may also be not activated in the + # device tree. No device tree info is available in this case. + # An attempt to generate code without the DTS info + # will lead to an exception for a valid situation. + codegen.outl("/* !!! '{}' not configured !!! */".format(driver_name)) + return False + + device_id = codegen.edts().device_id_by_label(driver_name) + if device_id is None: + # this should not happen + raise codegen.Error("Did not find driver name '{}'.".format(driver_name)) + + # Presets for mapping this device data to template + preset = device_defaults + preset['device-init'] = device_init + preset['device-level'] = device_level + preset['device-prio'] = device_prio + preset['device-api'] = device_api + preset['device-config'] = device_config + preset['driver-name'] = driver_name.strip('"') + + # + # device info + if device_info: + device_info = _device_template_substitute(device_info, device_id, + preset) + codegen.outl(device_info) + # + # device init + codegen.outl(_device_template_substitute(_device_and_api_init_tmpl, + device_id, preset)) + return True + +## +# @param device_configs +# A list of configuration variables for device instantiation. +# (e.g. ['CONFIG_SPI_0', 'CONFIG_SPI_1']) +# @param driver_names +# A list of driver names for device instantiation. The list shall be ordered +# as the list of device configs. +# (e.g. ['SPI_0', 'SPI_1']) +# @param device_inits +# A list of device initialisation functions or a one single function. The +# list shall be ordered as the list of device configs. +# (e.g. 'spi_stm32_init') +# @param device_levels +# A list of driver initialisation levels or one single level definition. The +# list shall be ordered as the list of device configs. +# (e.g. 'PRE_KERNEL_1') +# @param device_prios +# A list of driver initialisation priorities or one single priority +# definition. The list shall be ordered as the list of device configs. +# (e.g. 32) +# @param device_api +# Identifier of the device api. +# (e.g. 'spi_stm32_driver_api') +# @param device_info +# Device info template for device driver config, data and interrupt +# initialisation. +# @param device_defaults +# Device default property values. `device_defaults` is a dictionary of +# property path : property value. +# +def device_declare_multi(device_configs, + driver_names, + device_inits, + device_levels, + device_prios, + device_api, + device_info, + device_defaults = {}): + devices_declared = [] + for i, device_config in enumerate(device_configs): + driver_name = driver_names[i] + if isinstance(device_inits, str): + device_init = device_inits + else: + try: + device_init = device_inits[i] + except: + device_init = device_inits + if isinstance(device_levels, str): + device_level = device_levels + else: + try: + device_level = device_levels[i] + except: + device_level = device_levels + if isinstance(device_prios, str): + device_prio = device_prios + else: + try: + device_prio = device_prios[i] + except: + device_prio = device_prios + + device_declared = device_declare_single(device_config, + driver_name, + device_init, + device_level, + device_prio, + device_api, + device_info, + device_defaults) + devices_declared.append(str(device_declared)) + + if 'True' not in devices_declared: + err = "No active device found for {} = {} and {}.".format( + ', '.join(device_configs), ', '.join(devices_declared), + ', '.join(driver_names)) + codegen.log(err) + raise codegen.Error(err) + + +def _device_generate_struct(type_of_struct, _struct): + if _struct is None and type_of_struct == 'config': + return 'static const int ${device-config-info}[] = {};\n' + elif _struct is None and type_of_struct == 'data': + return 'static int ${device-data}[] = {};\n' + + struct = "" + # convert _struct into a list. Struct might have only one element + if type(_struct) is str: + _struct = [_struct] + else: + _struct = list(_struct) + + if type_of_struct == 'config': + struct += 'static const struct {} ${{device-config-info}} = {{\n'.format(_struct[0]) + elif type_of_struct == 'data': + struct += 'static struct {} ${{device-data}} = {{\n'.format(_struct[0]) + else: + msg("Not expected") + + if len(_struct) > 1: + struct += _struct[1] + + struct += '};\n\n' + return struct + + +def _device_generate_irq_bootstrap(irq_names, irq_flag, irq_func): + irq_bootstrap_info = \ + '#ifdef {}\n'.format(irq_flag) + \ + 'DEVICE_DECLARE(${device-name});\n' + \ + 'static void ${device-config-irq}(struct device *dev)\n' + \ + '{\n' + for irq_name in irq_names: + irq_num = '${{interrupts/{}/irq}}'.format(irq_name) + irq_prio = '${{interrupts/{}/priority}}'.format(irq_name) + irq_bootstrap_info += \ + '\tIRQ_CONNECT({},\n'.format(irq_num) + \ + '\t\t{},\n'.format(irq_prio) + if len(irq_names) == 1 and irq_name == '0': + # Only one irq and no name associated. Keep it simple name + irq_bootstrap_info += '\t\t{},\n'.format(irq_func) + else: + irq_bootstrap_info += '\t\t{}_{},\n'.format(irq_func, irq_name) + irq_bootstrap_info += \ + '\t\tDEVICE_GET(${device-name}),\n' + \ + '\t\t0);\n' + \ + '\tirq_enable({});\n\n'.format(irq_num) + irq_bootstrap_info += \ + '}\n' + \ + '#endif /* {} */\n\n'.format(irq_flag) + return irq_bootstrap_info + + +def device_declare(compatibles, init_prio_flag, kernel_level, irq_func, + init_func, api, data_struct, config_struct): + + config_struct = _device_generate_struct('config', config_struct) + data_struct = _device_generate_struct('data', data_struct) + if api is None: + api = "(*(const int *)0)" + + for device_id in codegen.edts().device_ids_by_compatible(compatibles): + driver_name = codegen.edts().device_property(device_id, 'label') + device_config = "CONFIG_{}".format(driver_name.strip('"')) + interrupts = codegen.edts().device_property( + device_id, 'interrupts', None) + if interrupts is not None: + irq_names = list(interrupts.keys()) + else: + irq_names = None + + device_info = "" + if irq_func is not None: + device_info += _device_generate_irq_bootstrap( + irq_names, irq_func['irq_flag'], irq_func['irq_func']) + device_info += config_struct + device_info += data_struct + + device_declare_single(device_config, + driver_name, + init_func, + kernel_level, + init_prio_flag, + api, + device_info) diff --git a/scripts/codegen/options.py b/scripts/codegen/options.py new file mode 100644 index 000000000000..312509353852 --- /dev/null +++ b/scripts/codegen/options.py @@ -0,0 +1,139 @@ +# Copyright 2004-2016, Ned Batchelder. +# http://nedbatchelder.com/code/cog +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import os +import argparse + +class Options(object): + + @staticmethod + def is_valid_directory(parser, arg): + if not os.path.isdir(arg): + parser.error('The directory {} does not exist!'.format(arg)) + else: + # File directory so return the directory + return arg + + @staticmethod + def is_valid_file(parser, arg): + if not os.path.isfile(arg): + parser.error('The file {} does not exist!'.format(arg)) + else: + # File exists so return the file + return arg + + def __init__(self): + # Defaults for argument values. + self.args = [] + self.includePath = [] + self.defines = {} + self.bNoGenerate = False + self.sOutputName = None + self.bWarnEmpty = False + self.bDeleteCode = False + self.bNewlines = False + self.sEncoding = "utf-8" + self.verbosity = 2 + + self._parser = argparse.ArgumentParser( + description='Generate code with inlined Python code.') + self._parser.add_argument('-d', '--delete-code', + dest='bDeleteCode', action='store_true', + help='Delete the generator code from the output file.') + self._parser.add_argument('-D', '--define', nargs=1, metavar='DEFINE', + dest='defines', action='append', + help='Define a global string available to your generator code.') + self._parser.add_argument('-e', '--warn-empty', + dest='bWarnEmpty', action='store_true', + help='Warn if a file has no generator code in it.') + self._parser.add_argument('-U', '--unix-newlines', + dest='bNewlines', action='store_true', + help='Write the output with Unix newlines (only LF line-endings).') + self._parser.add_argument('-I', '--include', nargs=1, metavar='DIR', + dest='includePath', action='append', + type=lambda x: self.is_valid_directory(self._parser, x), + help='Add DIR to the list of directories for data files and modules.') + self._parser.add_argument('-n', '--encoding', nargs=1, + dest='sEncoding', action='store', metavar='ENCODING', + type=lambda x: self.is_valid_file(self._parser, x), + help='Use ENCODING when reading and writing files.') + self._parser.add_argument('-i', '--input', nargs=1, metavar='FILE', + dest='input_file', action='store', + type=lambda x: self.is_valid_file(self._parser, x), + help='Get the input from FILE.') + self._parser.add_argument('-o', '--output', nargs=1, metavar='FILE', + dest='sOutputName', action='store', + help='Write the output to FILE.') + self._parser.add_argument('-l', '--log', nargs=1, metavar='FILE', + dest='log_file', action='store', + help='Log to FILE.') + + def __str__(self): + sb = [] + for key in self.__dict__: + sb.append("{key}='{value}'".format(key=key, value=self.__dict__[key])) + return ', '.join(sb) + + def __repr__(self): + return self.__str__() + + + def __eq__(self, other): + """ Comparison operator for tests to use. + """ + return self.__dict__ == other.__dict__ + + def clone(self): + """ Make a clone of these options, for further refinement. + """ + return copy.deepcopy(self) + + def parse_args(self, argv): + args = self._parser.parse_args(argv) + # set options + self.bDeleteCode = args.bDeleteCode + self.bWarnEmpty = args.bWarnEmpty + self.bNewlines = args.bNewlines + if args.includePath is None: + self.includePath = [] + else: + self.includePath = args.includePath + self.sEncoding = args.sEncoding + if args.input_file is None: + self.input_file = None + else: + self.input_file = args.input_file[0] + if args.sOutputName is None: + self.sOutputName = None + else: + self.sOutputName = args.sOutputName[0] + if args.log_file is None: + self.log_file = None + else: + self.log_file = args.log_file[0] + self.defines = {} + if args.defines is not None: + for define in args.defines: + d = define[0].split('=') + if len(d) > 1: + value = d[1] + else: + value = None + self.defines[d[0]] = value + + def addToIncludePath(self, dirs): + """ Add directories to the include path. + """ + dirs = dirs.split(os.pathsep) + self.includePath.extend(dirs) + + + +class OptionsMixin(object): + __slots__ = [] + + def option(self, option_name): + return getattr(self.options, option_name) diff --git a/scripts/codegen/output.py b/scripts/codegen/output.py new file mode 100644 index 000000000000..647002b3ed53 --- /dev/null +++ b/scripts/codegen/output.py @@ -0,0 +1,19 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + + +class OutputMixin(object): + __slots__ = [] + + def msg(self, s): + self.prout("Message: "+s) + + def out(self, sOut='', dedent=False, trimblanklines=False): + self._out(sOut, dedent, trimblanklines) + + def outl(self, sOut='', **kw): + """ The cog.outl function. + """ + self._out(sOut, **kw) + self._out('\n') diff --git a/scripts/codegen/redirectable.py b/scripts/codegen/redirectable.py new file mode 100644 index 000000000000..3cdc49b25e5f --- /dev/null +++ b/scripts/codegen/redirectable.py @@ -0,0 +1,31 @@ +# Copyright 2004-2016, Ned Batchelder. +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import sys + +class RedirectableMixin(object): + __slots__ = [] + + def setOutput(self, stdout=None, stderr=None): + """ Assign new files for standard out and/or standard error. + """ + if stdout: + self._stdout = stdout + if stderr: + self._stderr = stderr + + def prout(self, s, end="\n"): + print(s, file=self._stdout, end=end) + + def prerr(self, s, end="\n"): + print(s, file=self._stderr, end=end) + + +class Redirectable(RedirectableMixin): + """ An object with its own stdout and stderr files. + """ + def __init__(self): + self._stdout = sys.stdout + self._stderr = sys.stderr diff --git a/scripts/codegen/whiteutils.py b/scripts/codegen/whiteutils.py new file mode 100644 index 000000000000..2a128e4ab88f --- /dev/null +++ b/scripts/codegen/whiteutils.py @@ -0,0 +1,72 @@ +# Copyright 2004-2016, Ned Batchelder. +# http://nedbatchelder.com/code/cog +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: MIT + +import re + +def b(s): + return s.encode("latin-1") + +def whitePrefix(strings): + """ Determine the whitespace prefix common to all non-blank lines + in the argument list. + """ + # Remove all blank lines from the list + strings = [s for s in strings if s.strip() != ''] + + if not strings: return '' + + # Find initial whitespace chunk in the first line. + # This is the best prefix we can hope for. + pat = r'\s*' + if isinstance(strings[0], (bytes, )): + pat = pat.encode("utf8") + prefix = re.match(pat, strings[0]).group(0) + + # Loop over the other strings, keeping only as much of + # the prefix as matches each string. + for s in strings: + for i in range(len(prefix)): + if prefix[i] != s[i]: + prefix = prefix[:i] + break + return prefix + +def reindentBlock(lines, newIndent=''): + """ Take a block of text as a string or list of lines. + Remove any common whitespace indentation. + Re-indent using newIndent, and return it as a single string. + """ + sep, nothing = '\n', '' + if isinstance(lines, (bytes, )): + sep, nothing = b('\n'), b('') + if isinstance(lines, (str, bytes)): + lines = lines.split(sep) + oldIndent = whitePrefix(lines) + outLines = [] + for l in lines: + if oldIndent: + l = l.replace(oldIndent, nothing, 1) + if l and newIndent: + l = newIndent + l + outLines.append(l) + return sep.join(outLines) + +def commonPrefix(strings): + """ Find the longest string that is a prefix of all the strings. + """ + if not strings: + return '' + prefix = strings[0] + for s in strings: + if len(s) < len(prefix): + prefix = prefix[:len(s)] + if not prefix: + return '' + for i in range(len(prefix)): + if prefix[i] != s[i]: + prefix = prefix[:i] + break + return prefix diff --git a/scripts/codegen/zephyr.py b/scripts/codegen/zephyr.py new file mode 100644 index 000000000000..3366b2643ba8 --- /dev/null +++ b/scripts/codegen/zephyr.py @@ -0,0 +1,12 @@ +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +from pathlib import Path + +class ZephyrMixin(object): + __slots__ = [] + + @staticmethod + def zephyr_path(): + return Path(__file__).resolve().parents[2] diff --git a/scripts/dts/edtsdatabase.py b/scripts/dts/edtsdatabase.py new file mode 100644 index 000000000000..7c09494db346 --- /dev/null +++ b/scripts/dts/edtsdatabase.py @@ -0,0 +1,244 @@ +# +# Copyright (c) 2018 Bobby Noelte +# +# SPDX-License-Identifier: Apache-2.0 +# + +from collections.abc import Mapping +import json + +## +# @brief ETDS Database consumer +# +# Methods for ETDS database usage. +# +class EDTSConsumerMixin(object): + __slots__ = [] + + + ## + # @brief Get all supported device types + # + # @param none + # @return list of supported device types + def get_device_types(self): + return list(self._edts['device-types']) + + ## + # @brief Get all activated compatible devices. + # + # @param compatible + # @return dict of compatible devices + def _generate_device_dict(self, compatibles): + devices = dict() + if not isinstance(compatibles, list): + compatibles = [compatibles, ] + for compatible in compatibles: + for device_id in self._edts['compatibles'].get(compatible, []): + devices[device_id] = self._edts['devices'][device_id] + return devices + + ## + # @brief Get all activated compatible devices. + # + # @param compatibles compatible(s) + # @return list of devices that are compatible + def get_devices_by_compatible(self, compatibles): + return list(_generate_device_dict(compatibles).values()) + + ## + # @brief Get device ids of all activated compatible devices. + # + # @param compatibles compatible(s) + # @return list of device ids of activated devices that are compatible + def get_device_ids_by_compatible(self, compatibles): + return list(_generate_device_dict(compatibles).keys()) + + ## + # @brief Get device id of activated device with given label. + # + # @return device id + def get_device_id_by_label(self, label): + for device_id, device in self._edts['devices'].items(): + if label == device.get('label', None): + return device_id + return None + + ## + # @brief Get device tree property value for the device of the given device id. + # + # @param device_id + # @param property_path Path of the property to access + # (e.g. 'reg/0', 'interrupts/prio', 'device_id', ...) + # @return property value + # + def get_device_property(self, device_id, property_path, default="<unset>"): + property_value = self._edts['devices'].get(device_id, None) + property_path_elems = property_path.strip("'").split('/') + for elem_index, key in enumerate(property_path_elems): + if isinstance(property_value, dict): + property_value = property_value.get(key, None) + elif isinstance(property_value, list): + if int(key) < len(property_value): + property_value = property_value[int(key)] + else: + property_value = None + else: + property_value = None + if property_value is None: + if default == "<unset>": + default = "Device tree property {} not available in {}" \ + .format(property_path, device_id) + return default + return property_value + + def _device_properties_flattened(self, properties, path, flattened, path_prefix): + if isinstance(properties, dict): + for prop_name in properties: + super_path = "{}/{}".format(path, prop_name).strip('/') + self._device_properties_flattened(properties[prop_name], + super_path, flattened, + path_prefix) + elif isinstance(properties, list): + for i, prop in enumerate(properties): + super_path = "{}/{}".format(path, i).strip('/') + self._device_properties_flattened(prop, super_path, flattened, + path_prefix) + else: + flattened[path_prefix + path] = properties + + ## + # @brief Get the device tree properties for the device of the given device id. + # + # @param device_id + # @param path_prefix + # @return dictionary of proerty_path and property_value + def device_properties_flattened(self, device_id, path_prefix = ""): + flattened = dict() + self._device_properties_flattened(self._edts['devices'][device_id], + '', flattened, path_prefix) + return flattened + + def load(self, file_path): + with open(file_path, "r") as load_file: + self._edts = json.load(load_file) + +## +# @brief ETDS Database provider +# +# Methods for ETDS database creation. +# +class EDTSProviderMixin(object): + __slots__ = [] + + def _update_device_compatible(self, device_id, compatible): + if compatible not in self._edts['compatibles']: + self._edts['compatibles'][compatible] = list() + if device_id not in self._edts['compatibles'][compatible]: + self._edts['compatibles'][compatible].append(device_id) + self._edts['compatibles'][compatible].sort() + + def _update_device_type(self, device_id, device_type): + if device_type not in self._edts['device-types']: + self._edts['device-types'][device_type] = list() + if device_id not in self._edts['device-types'][device_type]: + self._edts['device-types'][device_type].append(device_id) + self._edts['device-types'][device_type].sort() + + def insert_device_type(self, compatible, device_type): + if device_type not in self._edts['device-types']: + self._edts['device-types'][device_type] = list() + if compatible not in self._edts['device-types'][device_type]: + self._edts['device-types'][device_type].append(compatible) + self._edts['device-types'][device_type].sort() + + + ## + # @brief Insert property value for the device of the given device id. + # + # @param device_id + # @param property_path Path of the property to access + # (e.g. 'reg/0', 'interrupts/prio', 'label', ...) + # @param property_value value + # + def insert_device_property(self, device_id, property_path, property_value): + # special properties + if property_path.startswith('compatible'): + self._update_device_compatible(device_id, property_value) + + # normal property management + if device_id not in self._edts['devices']: + self._edts['devices'][device_id] = dict() + self._edts['devices'][device_id]['device-id'] = device_id + if property_path == 'device-id': + # already set + return + keys = property_path.strip("'").split('/') + property_access_point = self._edts['devices'][device_id] + for i in range(0, len(keys)): + if i < len(keys) - 1: + # there are remaining keys + if keys[i] not in property_access_point: + property_access_point[keys[i]] = dict() + property_access_point = property_access_point[keys[i]] + else: + # we have to set the property value + if keys[i] in property_access_point and \ + property_access_point[keys[i]] != property_value: + # Property is already set and we're overwiting with a new + # different value. Tigger an error + raise Exception("Overwriting edts cell {} with different value\n \ + Initial value: {} \n \ + New value: {}".format(property_access_point, + property_access_point[keys[i]], + property_value + )) + property_access_point[keys[i]] = property_value + + + def save(self, file_path): + with open(file_path, "w") as save_file: + json.dump(self._edts, save_file, indent = 4) + +## +# @brief Extended DTS database +# +# Database schema: +# +# _edts dict( +# 'devices': dict(device-id : device-struct), +# 'compatibles': dict(compatible : sorted list(device-id)), +# 'device-types': dict(device-type : sorted list(compatible)), +# ... +# ) +# +# device-struct dict( +# 'device-id' : device-id, +# 'compatible' : list(compatible) or compatible, +# 'label' : label, +# property-name : property-value ... +# ) +# +# Database types: +# +# device-id: opaque id for a device (do not use for other purposes), +# compatible: any of ['st,stm32-spi-fifo', ...] - 'compatibe' from <binding>.yaml +# label: any of ['UART_0', 'SPI_11', ...] - label directive from DTS +# +class EDTSDatabase(EDTSConsumerMixin, EDTSProviderMixin, Mapping): + + def __init__(self, *args, **kw): + self._edts = dict(*args, **kw) + # setup basic database schema + for edts_key in ('devices', 'compatibles', 'device-types'): + if not edts_key in self._edts: + self._edts[edts_key] = dict() + + def __getitem__(self, key): + return self._edts[key] + + def __iter__(self): + return iter(self._edts) + + def __len__(self): + return len(self._edts) diff --git a/scripts/dts/extract/clocks.py b/scripts/dts/extract/clocks.py index caa15adf1f72..105bfad1f57e 100644 --- a/scripts/dts/extract/clocks.py +++ b/scripts/dts/extract/clocks.py @@ -5,6 +5,7 @@ # from extract.globals import * +from extract.edts import * from extract.directive import DTDirective ## @@ -12,15 +13,53 @@ # # Handles: # - clocks -# directives. +# +# Generates in EDTS: +# +# Clock consumer +# -------------- +# - clocks/<index>/<cell-name> : <cell-value> +# (cell-name from cell-names of provider) # class DTClocks(DTDirective): def __init__(self): pass - def _extract_consumer(self, node_address, yaml, clocks, names, def_label): + ## + # @brief Insert clock cells into EDTS + # + # @param clock_consumer + # @param yaml + # @param clock_provider + # @param clock_cells + # @param property_path_templ "xxx/yyy/{}" + # + def _edts_insert_clock_cells(self, clock_consumer_node_address, yaml, + clock_provider_node_address, clock_cells, + property_path_templ): + if len(clock_cells) == 0: + return + clock_consumer_device_id = edts_device_id(clock_consumer_node_address) + clock_provider_device_id = edts_device_id(clock_provider_node_address) + clock_provider = reduced[clock_provider_node_address] + clock_provider_compat = get_compat(clock_provider_node_address) + clock_provider_bindings = yaml[clock_provider_compat] + clock_nr_cells = int(clock_provider['props'].get('#clock-cells', 0)) + clock_cells_names = clock_provider_bindings.get( + '#cells', ['ID', 'CELL1', "CELL2", "CELL3"]) + for i, cell in enumerate(clock_cells): + if i >= len(clock_cells_names): + clock_cell_name = 'CELL{}'.format(i).lower() + else: + clock_cell_name = clock_cells_names[i].lower() + edts_insert_device_property(clock_consumer_device_id, + property_path_templ.format(clock_cell_name), cell) + + def _extract_consumer(self, node_address, yaml, clocks, def_label): + + clock_consumer_device_id = edts_device_id(node_address) clock_consumer = reduced[node_address] clock_consumer_compat = get_compat(node_address) clock_consumer_bindings = yaml[clock_consumer_compat] @@ -28,7 +67,7 @@ def _extract_consumer(self, node_address, yaml, clocks, names, def_label): clock_index = 0 clock_cell_index = 0 - nr_clock_cells = 0 + clock_nr_cells = 0 clock_provider_node_address = '' clock_provider = {} for cell in clocks: @@ -42,27 +81,37 @@ def _extract_consumer(self, node_address, yaml, clocks, names, def_label): str(clock_provider))) clock_provider_node_address = phandles[cell] clock_provider = reduced[clock_provider_node_address] - clock_provider_compat = get_compat(clock_provider_node_address) - clock_provider_bindings = yaml[clock_provider_compat] - clock_provider_label = self.get_node_label_string( \ - clock_provider_node_address) - nr_clock_cells = int(clock_provider['props'].get( - '#clock-cells', 0)) - clock_cells_string = clock_provider_bindings.get( - 'cell_string', 'CLOCK') - clock_cells_names = clock_provider_bindings.get( - '#cells', ['ID', 'CELL1', "CELL2", "CELL3"]) + clock_nr_cells = int(clock_provider['props'].get('#clock-cells', 0)) clock_cells = [] else: clock_cells.append(cell) clock_cell_index += 1 - if clock_cell_index > nr_clock_cells: - # clock consumer device - clocks info - ##################################### + if clock_cell_index > clock_nr_cells: + + # generate EDTS + edts_insert_device_property(clock_consumer_device_id, + 'clocks/{}/provider'.format(clock_index), + clock_provider_node_address) + self._edts_insert_clock_cells(node_address, yaml, + clock_provider_node_address, + clock_cells, + "clocks/{}/{{}}".format(clock_index)) + + # generate defines prop_def = {} prop_alias = {} + # legacy definitions for backwards compatibility + # @todo remove legacy definitions + # Legacy clocks definitions by extract_cells + clock_provider_compat = get_compat(clock_provider_node_address) + clock_provider_bindings = yaml[clock_provider_compat] + clock_cells_string = clock_provider_bindings.get( + 'cell_string', 'CLOCK') + clock_cells_names = clock_provider_bindings.get( + '#cells', ['ID', 'CELL1', "CELL2", "CELL3"]) + for i, cell in enumerate(clock_cells): if i >= len(clock_cells_names): clock_cell_name = 'CELL{}'.format(i) @@ -93,25 +142,17 @@ def _extract_consumer(self, node_address, yaml, clocks, names, def_label): clock_cell_name, index]) prop_alias[clock_alias_label] = clock_label # alias - if i < nr_clock_cells: + if i < clock_nr_cells: # clocks info for first clock clock_alias_label = self.get_label_string([ clock_consumer_label, clock_cells_string, clock_cell_name]) prop_alias[clock_alias_label] = clock_label - # Legacy clocks definitions by extract_controller + # ----- legacy clocks definitions clock_provider_label_str = clock_provider['props'].get('label', None) if clock_provider_label_str is not None: - try: - generation = clock_consumer_bindings['properties'][ - 'clocks']['generation'] - except: - generation = '' - if 'use-prop-name' in generation: - clock_cell_name = 'CLOCKS_CONTROLLER' - else: - clock_cell_name = 'CLOCK_CONTROLLER' + clock_cell_name = 'CLOCK_CONTROLLER' if clock_index == 0 and \ len(clocks) == (len(clock_cells) + 1): index = '' @@ -128,6 +169,7 @@ def _extract_consumer(self, node_address, yaml, clocks, names, def_label): prop_alias[clock_alias_label] = clock_label insert_defs(node_address, prop_def, prop_alias) + # ------ legacy end clock_cell_index = 0 clock_index += 1 @@ -138,10 +180,9 @@ def _extract_consumer(self, node_address, yaml, clocks, names, def_label): # @param node_address Address of node owning the clockxxx definition. # @param yaml YAML definition for the owning node. # @param prop clockxxx property name - # @param names (unused) # @param def_label Define label string of node owning the directive. # - def extract(self, node_address, yaml, prop, names, def_label): + def extract(self, node_address, yaml, prop, def_label): properties = reduced[node_address]['props'][prop] @@ -153,7 +194,7 @@ def extract(self, node_address, yaml, prop, names, def_label): if prop == 'clocks': # indicator for clock consumers - self._extract_consumer(node_address, yaml, prop_list, names, def_label) + self._extract_consumer(node_address, yaml, prop_list, def_label) else: raise Exception( "DTClocks.extract called with unexpected directive ({})." diff --git a/scripts/dts/extract/compatible.py b/scripts/dts/extract/compatible.py new file mode 100644 index 000000000000..a6cf7f01c92b --- /dev/null +++ b/scripts/dts/extract/compatible.py @@ -0,0 +1,49 @@ +# +# Copyright (c) 2018 Bobby Noelte +# +# SPDX-License-Identifier: Apache-2.0 +# + +from extract.globals import * +from extract.edts import * +from extract.directive import DTDirective + +## +# @brief Manage compatible directives. +# +# Handles: +# - compatible +# +# Generates in EDTS: +# - compatible/<index> : compatible +class DTCompatible(DTDirective): + + def __init__(self): + pass + + ## + # @brief Extract compatible + # + # @param node_address Address of node owning the + # compatible definition. + # @param yaml YAML definition for the owning node. + # @param prop compatible property name + # @param def_label Define label string of node owning the + # compatible definition. + # + def extract(self, node_address, yaml, prop, def_label): + + # compatible definition + compatible = reduced[node_address]['props'][prop] + if not isinstance(compatible, list): + compatible = [compatible, ] + + # generate EDTS + device_id = edts_device_id(node_address) + for i, comp in enumerate(compatible): + edts_insert_device_property(device_id, 'compatible/{}'.format(i), + comp) + +## +# @brief Management information for compatible. +compatible = DTCompatible() diff --git a/scripts/dts/extract/default.py b/scripts/dts/extract/default.py index f66c0dd496a4..ad0cea99cc3e 100644 --- a/scripts/dts/extract/default.py +++ b/scripts/dts/extract/default.py @@ -5,6 +5,7 @@ # from extract.globals import * +from extract.edts import * from extract.directive import DTDirective ## @@ -18,17 +19,20 @@ def __init__(self): ## # @brief Extract directives in a default way # - # @param node_address Address of node owning the clockxxx definition. + # @param node_address Address of node owning the directive definition. # @param yaml YAML definition for the owning node. # @param prop property name - # @param names (unused) # @param def_label Define label string of node owning the directive. # - def extract(self, node_address, yaml, prop, names, def_label): - prop_def = {} - prop_alias = {} + def extract(self, node_address, yaml, prop, def_label): prop_values = reduced[node_address]['props'][prop] + # generate EDTS + edts_insert_device_property(node_address, prop, prop_values) + + # generate defines + prop_def = {} + prop_alias = {} if isinstance(prop_values, list): for i, prop_value in enumerate(prop_values): prop_name = convert_string_to_label(prop) diff --git a/scripts/dts/extract/directive.py b/scripts/dts/extract/directive.py index b4496a1c419e..ad8291f436bb 100644 --- a/scripts/dts/extract/directive.py +++ b/scripts/dts/extract/directive.py @@ -57,8 +57,7 @@ def __init__(): # @param node_address Address of node issueuing the directive. # @param yaml YAML definition for the node. # @param prop Directive property name - # @param names Names assigned to directive. # @param def_label Define label string of node owning the directive. # - def extract(self, node_address, yaml, prop, names, def_label): + def extract(self, node_address, yaml, prop, def_label): pass diff --git a/scripts/dts/extract/edts.py b/scripts/dts/extract/edts.py new file mode 100644 index 000000000000..6c9d3cc1dec5 --- /dev/null +++ b/scripts/dts/extract/edts.py @@ -0,0 +1,47 @@ +# +# Copyright (c) 2018 Bobby Noelte +# +# SPDX-License-Identifier: Apache-2.0 +# + +from .globals import * +import edtsdatabase + +edts = edtsdatabase.EDTSDatabase() + +## +# @brief Get EDTS device id associated to node address. +# +# @return ETDS device id +def edts_device_id(node_address): + return node_address + +## +# @brief Insert device property into EDTS +# +def edts_insert_device_property(node_address, property_path, property_value): + device_id = edts_device_id(node_address) + edts.insert_device_property(device_id, property_path, property_value) + +def edts_insert_device_type(compatible, device_type): + edts.insert_device_type(compatible, device_type) + +## +# @brief Insert device parent-device property into EDTS +# +def edts_insert_device_parent_device_property(node_address): + # Check for a parent device this device is subordinated + parent_device_id = None + parent_node_address = '' + for comp in node_address.split('/')[1:-1]: + parent_node_address += '/' + comp + compatibles = reduced[parent_node_address]['props'] \ + .get('compatible', None) + if compatibles: + # there is a parent device, + # only use the ones that have a minimum control on the child + if 'simple-bus' not in compatibles: + parent_device_id = edts_device_id(parent_node_address) + if parent_device_id: + edts_insert_device_property(edts_device_id(node_address), + 'parent-device', parent_device_id) diff --git a/scripts/dts/extract/flash.py b/scripts/dts/extract/flash.py index 312e79842ec3..4e2ed88ad583 100644 --- a/scripts/dts/extract/flash.py +++ b/scripts/dts/extract/flash.py @@ -19,7 +19,7 @@ def __init__(self): # Node of the flash self._flash_node = None - def _extract_partition(self, node_address, yaml, prop, names, def_label): + def _extract_partition(self, node_address, yaml, prop, def_label): prop_def = {} prop_alias = {} node = reduced[node_address] @@ -53,7 +53,7 @@ def _extract_partition(self, node_address, yaml, prop, names, def_label): insert_defs(node_address, prop_def, prop_alias) - def _extract_flash(self, node_address, yaml, prop, names, def_label): + def _extract_flash(self, node_address, yaml, prop, def_label): load_defs = {} if node_address == 'dummy-flash': @@ -72,14 +72,14 @@ def _extract_flash(self, node_address, yaml, prop, names, def_label): flash_props = ["label", "write-block-size", "erase-block-size"] for prop in flash_props: if prop in self._flash_node['props']: - default.extract(node_address, None, prop, None, def_label) + default.extract(node_address, None, prop, def_label) insert_defs(node_address, load_defs, {}) #for address in reduced: # if address.startswith(node_address) and 'partition@' in address: # self._extract_partition(address, yaml, 'partition', None, def_label) - def _extract_code_partition(self, node_address, yaml, prop, names, def_label): + def _extract_code_partition(self, node_address, yaml, prop, def_label): load_defs = {} if node_address == 'dummy-flash': @@ -113,21 +113,20 @@ def _extract_code_partition(self, node_address, yaml, prop, names, def_label): # flash definition. # @param yaml YAML definition for the owning node. # @param prop compatible property name - # @param names (unused) # @param def_label Define label string of node owning the # compatible definition. # - def extract(self, node_address, yaml, prop, names, def_label): + def extract(self, node_address, yaml, prop, def_label): if prop == 'zephyr,flash': # indicator for flash - self._extract_flash(node_address, yaml, prop, names, def_label) + self._extract_flash(node_address, yaml, prop, def_label) elif prop == 'zephyr,code-partition': # indicator for code_partition - self._extract_code_partition(node_address, yaml, prop, names, def_label) + self._extract_code_partition(node_address, yaml, prop, def_label) elif prop == 'reg': # indicator for partition - self._extract_partition(node_address, yaml, prop, names, def_label) + self._extract_partition(node_address, yaml, prop, def_label) else: raise Exception( "DTFlash.extract called with unexpected directive ({})." diff --git a/scripts/dts/extract/globals.py b/scripts/dts/extract/globals.py index cf59ebcacbad..ad89647c87e7 100644 --- a/scripts/dts/extract/globals.py +++ b/scripts/dts/extract/globals.py @@ -5,6 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 # +import sys from collections import defaultdict # globals @@ -13,7 +14,6 @@ chosen = {} reduced = {} defs = {} -structs = {} regs_config = { 'zephyr,flash' : 'CONFIG_FLASH', diff --git a/scripts/dts/extract/gpios.py b/scripts/dts/extract/gpios.py new file mode 100644 index 000000000000..aa530f5340ee --- /dev/null +++ b/scripts/dts/extract/gpios.py @@ -0,0 +1,207 @@ +# +# Copyright (c) 2018 Linaro Limited +# +# SPDX-License-Identifier: Apache-2.0 +# + +import pprint + +from extract.globals import * +from extract.directive import DTDirective +from extract.edts import * + +## +# @brief Manage gpio-x directive. +# insert <gpio-prop-name>-_controller +# insert gpio cells based on gpio-controller definitions +# +class DTGpios(DTDirective): + + def __init__(self): + pass + + ## + # @brief Extract gpio information. + # + # @param node_address Address of node owning the pinctrl definition. + # @param yaml YAML definition for the owning node. + # @param prop gpio key + # @param def_label Define label string of client node owning the gpio + # definition. + # + def _extract_controller(self, node_address, yaml, prop, prop_values, def_label, index): + + prop_def = {} + prop_alias = {} + + # get controller node (referenced via phandle) + cell_parent = phandles[prop_values[0]] + + for k in reduced[cell_parent]['props'].keys(): + if k[0] == '#' and '-cells' in k: + num_cells = reduced[cell_parent]['props'].get(k) + + try: + l_cell = reduced[cell_parent]['props'].get('label') + except KeyError: + l_cell = None + + if l_cell is not None: + + l_base = def_label.split('/') + + # Check is defined should be indexed (_0, _1) + if index == 0 and len(prop_values) < (num_cells + 2): + # 0 or 1 element in prop_values + # ( ie len < num_cells + phandle + 1 ) + l_idx = [] + else: + l_idx = [str(index)] + + # Check node generation requirements + try: + generation = yaml[get_compat(node_address)]['properties'][prop][ + 'generation'] + except: + generation = '' + + if 'use-prop-name' in generation: + l_cellname = convert_string_to_label(prop + '_' + 'controller') + else: + l_cellname = convert_string_to_label('gpio' + '_' + + 'controller') + + edts_insert_device_property(edts_device_id(node_address), + '{}/{}/controller'.format(prop, index), + cell_parent) + + label = l_base + [l_cellname] + l_idx + + prop_def['_'.join(label)] = "\"" + l_cell + "\"" + + #generate defs also if node is referenced as an alias in dts + if node_address in aliases: + for i in aliases[node_address]: + alias_label = \ + convert_string_to_label(i) + alias = [alias_label] + label[1:] + prop_alias['_'.join(alias)] = '_'.join(label) + + insert_defs(node_address, prop_def, prop_alias) + + # prop off phandle + num_cells to get to next list item + prop_values = prop_values[num_cells+1:] + + # recurse if we have anything left + if len(prop_values): + self._extract_controller(node_address, yaml, prop, prop_values, + def_label, index + 1) + + + def _extract_cells(self, node_address, yaml, prop, prop_values, def_label, index): + + cell_parent = phandles[prop_values.pop(0)] + + try: + cell_yaml = yaml[get_compat(cell_parent)] + except: + raise Exception( + "Could not find yaml description for " + + reduced[cell_parent]['name']) + + + # Get number of cells per element of current property + for k in reduced[cell_parent]['props'].keys(): + if k[0] == '#' and '-cells' in k: + num_cells = reduced[cell_parent]['props'].get(k) + + l_cell = [convert_string_to_label(str(prop))] + + + # Check node generation requirements + try: + generation = yaml[get_compat(node_address)]['properties'][prop][ + 'generation'] + except: + generation = '' + + if 'use-prop-name' in generation: + l_cell = [convert_string_to_label(str(prop))] + else: + l_cell = [convert_string_to_label('gpio')] + + l_base = def_label.split('/') + # Check if #define should be indexed (_0, _1, ...) + if index == 0 and len(prop_values) < (num_cells + 2): + # Less than 2 elements in prop_values + # (ie len < num_cells + phandle + 1) + # Indexing is not needed + l_idx = [] + else: + l_idx = [str(index)] + + prop_def = {} + prop_alias = {} + + # Generate label for each field of the property element + for i in range(num_cells): + cell_name = cell_yaml['#cells'][i] + l_cellname = [str(cell_name).upper()] + if l_cell == l_cellname: + label = l_base + l_cell + l_idx + else: + label = l_base + l_cell + l_cellname + l_idx + # label_name = l_base + name + l_cellname + label_name = l_base + l_cellname + cell_value = prop_values.pop(0) + prop_def['_'.join(label)] = cell_value + # if len(name): + # prop_alias['_'.join(label_name)] = '_'.join(label) + + # generate defs for node aliases + if node_address in aliases: + for i in aliases[node_address]: + alias_label = convert_string_to_label(i) + alias = [alias_label] + label[1:] + prop_alias['_'.join(alias)] = '_'.join(label) + + edts_insert_device_property(edts_device_id(node_address), + '{}/{}/{}'.format(prop, index, cell_name), cell_value) + + insert_defs(node_address, prop_def, prop_alias) + + # recurse if we have anything left + if len(prop_values): + extract_cells(node_address, yaml, prop, prop_values, def_label, + index + 1) + + + ## + # @brief Extract gpio related directives + # + # @param node_address Address of node owning the gpio definition. + # @param yaml YAML definition for the owning node. + # @param prop gpio property name + # @param def_label Define label string of node owning the directive. + # + def extract(self, node_address, yaml, prop, def_label): + + try: + prop_values = list(reduced[node_address]['props'].get(prop)) + except: + prop_values = reduced[node_address]['props'].get(prop) + + if 'gpio' in prop: + # indicator for clock consumers + self._extract_controller(node_address, yaml, prop, prop_values, + def_label, 0) + self._extract_cells(node_address, yaml, prop, prop_values, + def_label, 0) + else: + raise Exception( + "DTGpios.extract called with unexpected directive ({})." + .format(prop)) + +## +# @brief Management information for gpio +gpios = DTGpios() diff --git a/scripts/dts/extract/heuristics.py b/scripts/dts/extract/heuristics.py new file mode 100644 index 000000000000..208678d5b2a9 --- /dev/null +++ b/scripts/dts/extract/heuristics.py @@ -0,0 +1,87 @@ +# +# Copyright (c) 2018 Bobby Noelte +# +# SPDX-License-Identifier: Apache-2.0 +# + +from extract.globals import * +from extract.edts import * +from extract.directive import DTDirective +from extract.default import default + +## +# @brief Generate device tree information based on heuristics. +# +# Generates in EDTS: +# - bus/master : device id of bus master for a bus device +# - parent-device : device id of parent device +class DTHeuristics(DTDirective): + + def __init__(self): + pass + + ## + # @brief Generate device tree information based on heuristics. + # + # Device tree properties may have to be deduced by heuristics + # as the property definitions are not always consistent across + # different node types. + # + # @param node_address Address of node owning the + # compatible definition. + # @param yaml YAML definition for the owning node. + # @param prop compatible property name + # @param def_label Define label string of node owning the + # compatible definition. + # + def extract(self, node_address, yaml, prop, def_label): + compatible = reduced[node_address]['props']['compatible'] + if not isinstance(compatible, list): + compatible = [compatible] + + # Check for <device>-device that is connected to a bus + for compat in compatible: + + # get device type list + try: + device_types = yaml[compat]['type'] + except KeyError: + raise Exception("Device Node: {} has no 'type'".format(node_address)) + + if not isinstance(device_types, list): + device_types = [device_types, ] + + # inject device type in database + for j, device_type in enumerate(device_types): + edts_insert_device_type(compat, device_type) + edts_insert_device_property(node_address, 'device-type/{}'.format(j), + device_type) + + # Perform device type specific treatment + if not device_type.endswith('-device'): + continue + + bus_master_device_type = device_type.replace('-device', '') + + # get parent + parent_node_address = '' + for comp in node_address.split('/')[1:-1]: + parent_node_address += '/' + comp + + # get parent yaml + parent_yaml = yaml[reduced[parent_node_address] \ + ['props']['compatible']] + + if bus_master_device_type not in parent_yaml['type']: + continue + + # generate EDTS + edts_insert_device_property(node_address, 'bus/master', + parent_node_address) + + # Check for a parent device this device is subordinated + edts_insert_device_parent_device_property(node_address) + +## +# @brief Management information for heuristics. +heuristics = DTHeuristics() diff --git a/scripts/dts/extract/interrupts.py b/scripts/dts/extract/interrupts.py index a6e2cebc1dd6..0ef9558ef63d 100644 --- a/scripts/dts/extract/interrupts.py +++ b/scripts/dts/extract/interrupts.py @@ -6,6 +6,7 @@ from extract.globals import * from extract.directive import DTDirective +from extract.edts import * ## # @brief Manage interrupts directives. @@ -47,7 +48,38 @@ def extract(self, node_address, yaml, prop, names, def_label): props = [node['props'].get(prop)] irq_parent = self._find_parent_irq_node(node_address) - + irq_nr_cells = reduced[irq_parent]['props']['#interrupt-cells'] + irq_cell_yaml = yaml[get_compat(irq_parent)] + irq_cell_names = irq_cell_yaml.get('#cells', []) + irq_names = node['props'].get('interrupt-names', []) + if not isinstance(irq_names, list): + irq_names = [irq_names, ] + + # generate EDTS + device_id = edts_device_id(node_address) + irq_index = 0 + irq_cell_index = 0 + for cell in props: + if len(irq_names) > irq_index: + irq_name = irq_names[irq_index] + else: + irq_name = str(irq_index) + if len(irq_cell_names) > irq_cell_index: + irq_cell_name = irq_cell_names[irq_cell_index] + else: + irq_cell_name = str(irq_cell_index) + edts_insert_device_property(device_id, + 'interrupts/{}/parent'.format(irq_name), + edts_device_id(irq_parent)) + edts_insert_device_property(device_id, + 'interrupts/{}/{}'.format(irq_name, irq_cell_name), + cell) + irq_cell_index += 1 + if irq_cell_index >= irq_nr_cells: + irq_cell_index = 0 + irq_index += 1 + + # generate defines l_base = def_label.split('/') index = 0 @@ -67,11 +99,10 @@ def extract(self, node_address, yaml, prop, names, def_label): except: name = [] - cell_yaml = yaml[get_compat(irq_parent)] l_cell_prefix = ['IRQ'] - for i in range(reduced[irq_parent]['props']['#interrupt-cells']): - l_cell_name = [cell_yaml['#cells'][i].upper()] + for i in range(irq_nr_cells): + l_cell_name = [irq_cell_names[i].upper()] if l_cell_name == l_cell_prefix: l_cell_name = [] diff --git a/scripts/dts/extract/pinctrl.py b/scripts/dts/extract/pinctrl.py index 7ca63dccd8e5..f79a80677eee 100644 --- a/scripts/dts/extract/pinctrl.py +++ b/scripts/dts/extract/pinctrl.py @@ -21,11 +21,10 @@ def __init__(self): # @param node_address Address of node owning the pinctrl definition. # @param yaml YAML definition for the owning node. # @param prop pinctrl-x key - # @param names Names assigned to pinctrl state pinctrl-<index>. # @param def_label Define label string of client node owning the pinctrl # definition. # - def extract(self, node_address, yaml, prop, names, def_label): + def extract(self, node_address, yaml, prop, def_label): pinconf = reduced[node_address]['props'][prop] diff --git a/scripts/dts/extract/reg.py b/scripts/dts/extract/reg.py index aeec78ab2d64..dde65c73706b 100644 --- a/scripts/dts/extract/reg.py +++ b/scripts/dts/extract/reg.py @@ -6,6 +6,7 @@ from extract.globals import * from extract.directive import DTDirective +from extract.edts import * ## # @brief Manage reg directive. @@ -22,28 +23,52 @@ def __init__(self): # reg definition. # @param yaml YAML definition for the owning node. # @param prop reg property name - # @param names (unused) # @param def_label Define label string of node owning the # compatible definition. # - def extract(self, node_address, yaml, prop, names, def_label): + def extract(self, node_address, yaml, prop, def_label): node = reduced[node_address] node_compat = get_compat(node_address) reg = reduced[node_address]['props']['reg'] - if type(reg) is not list: reg = [ reg ] - props = list(reg) + if type(reg) is not list: reg = [ reg, ] + reg_names = node['props'].get('reg-names', []) - address_cells = reduced['/']['props'].get('#address-cells') - size_cells = reduced['/']['props'].get('#size-cells') + nr_address_cells = reduced['/']['props'].get('#address-cells') + nr_size_cells = reduced['/']['props'].get('#size-cells') address = '' for comp in node_address.split('/')[1:-1]: address += '/' + comp - address_cells = reduced[address]['props'].get( - '#address-cells', address_cells) - size_cells = reduced[address]['props'].get('#size-cells', size_cells) - + nr_address_cells = reduced[address]['props'].get( + '#address-cells', nr_address_cells) + nr_size_cells = reduced[address]['props'].get('#size-cells', nr_size_cells) + + # generate EDTS + device_id = edts_device_id(node_address) + reg_index = 0 + reg_cell_index = 0 + reg_nr_cells = nr_address_cells + nr_size_cells + for cell in reg: + if len(reg_names) > reg_index: + reg_name = reg_names[reg_index] + else: + reg_name = str(reg_index) + if reg_cell_index < nr_address_cells: + edts_insert_device_property(device_id, + 'reg/{}/address/{}'.format(reg_name, reg_cell_index), + cell) + else: + size_cell_index = reg_cell_index - nr_address_cells + edts_insert_device_property(device_id, + 'reg/{}/size/{}'.format(reg_name, size_cell_index), + cell) + reg_cell_index += 1 + if reg_cell_index >= reg_nr_cells: + reg_cell_index = 0 + reg_index += 1 + + # generate defines post_label = "BASE_ADDRESS" if yaml[node_compat].get('use-property-label', False): label = node['props'].get('label', None) @@ -55,6 +80,7 @@ def extract(self, node_address, yaml, prop, names, def_label): l_addr = [convert_string_to_label(post_label)] l_size = ["SIZE"] + props = list(reg) while props: prop_def = {} prop_alias = {} @@ -72,21 +98,21 @@ def extract(self, node_address, yaml, prop, names, def_label): except: name = [] - for x in range(address_cells): + for x in range(nr_address_cells): addr += props.pop(0) << (32 * x) - for x in range(size_cells): + for x in range(nr_size_cells): size += props.pop(0) << (32 * x) l_addr_fqn = '_'.join(l_base + l_addr + l_idx) l_size_fqn = '_'.join(l_base + l_size + l_idx) - if address_cells: + if nr_address_cells: prop_def[l_addr_fqn] = hex(addr) - if size_cells: + if nr_size_cells: prop_def[l_size_fqn] = int(size) if len(name): - if address_cells: + if nr_address_cells: prop_alias['_'.join(l_base + name + l_addr)] = l_addr_fqn - if size_cells: + if nr_size_cells: prop_alias['_'.join(l_base + name + l_size)] = l_size_fqn # generate defs for node aliases diff --git a/scripts/dts/extract_dts_includes.py b/scripts/dts/extract_dts_includes.py index 429352867080..e5d3cad36e3a 100755 --- a/scripts/dts/extract_dts_includes.py +++ b/scripts/dts/extract_dts_includes.py @@ -19,12 +19,16 @@ from devicetree import parse_file from extract.globals import * +from extract.edts import edts from extract.clocks import clocks +from extract.gpios import gpios +from extract.compatible import compatible from extract.interrupts import interrupts from extract.reg import reg from extract.flash import flash from extract.pinctrl import pinctrl +from extract.heuristics import heuristics from extract.default import default class Bindings(yaml.Loader): @@ -197,144 +201,6 @@ def extract_reg_prop(node_address, names, def_label, div, post_label): index += 1 -def extract_controller(node_address, yaml, prop, prop_values, index, def_label, generic): - - prop_def = {} - prop_alias = {} - - # get controller node (referenced via phandle) - cell_parent = phandles[prop_values[0]] - - for k in reduced[cell_parent]['props'].keys(): - if k[0] == '#' and '-cells' in k: - num_cells = reduced[cell_parent]['props'].get(k) - - # get controller node (referenced via phandle) - cell_parent = phandles[prop_values[0]] - - try: - l_cell = reduced[cell_parent]['props'].get('label') - except KeyError: - l_cell = None - - if l_cell is not None: - - l_base = def_label.split('/') - - # Check is defined should be indexed (_0, _1) - if index == 0 and len(prop_values) < (num_cells + 2): - # 0 or 1 element in prop_values - # ( ie len < num_cells + phandle + 1 ) - l_idx = [] - else: - l_idx = [str(index)] - - # Check node generation requirements - try: - generation = yaml[get_compat(node_address)]['properties'][prop][ - 'generation'] - except: - generation = '' - - if 'use-prop-name' in generation: - l_cellname = convert_string_to_label(prop + '_' + 'controller') - else: - l_cellname = convert_string_to_label(generic + '_' + 'controller') - - label = l_base + [l_cellname] + l_idx - - prop_def['_'.join(label)] = "\"" + l_cell + "\"" - - #generate defs also if node is referenced as an alias in dts - if node_address in aliases: - for i in aliases[node_address]: - alias_label = \ - convert_string_to_label(i) - alias = [alias_label] + label[1:] - prop_alias['_'.join(alias)] = '_'.join(label) - - insert_defs(node_address, prop_def, prop_alias) - - # prop off phandle + num_cells to get to next list item - prop_values = prop_values[num_cells+1:] - - # recurse if we have anything left - if len(prop_values): - extract_controller(node_address, yaml, prop, prop_values, index + 1, - def_label, generic) - - -def extract_cells(node_address, yaml, prop, prop_values, names, index, - def_label, generic): - - cell_parent = phandles[prop_values.pop(0)] - - try: - cell_yaml = yaml[get_compat(cell_parent)] - except: - raise Exception( - "Could not find yaml description for " + - reduced[cell_parent]['name']) - - try: - name = names.pop(0).upper() - except: - name = [] - - # Get number of cells per element of current property - for k in reduced[cell_parent]['props'].keys(): - if k[0] == '#' and '-cells' in k: - num_cells = reduced[cell_parent]['props'].get(k) - try: - generation = yaml[get_compat(node_address)]['properties'][prop][ - 'generation'] - except: - generation = '' - - if 'use-prop-name' in generation: - l_cell = [convert_string_to_label(str(prop))] - else: - l_cell = [convert_string_to_label(str(generic))] - - l_base = def_label.split('/') - # Check if #define should be indexed (_0, _1, ...) - if index == 0 and len(prop_values) < (num_cells + 2): - # Less than 2 elements in prop_values (ie len < num_cells + phandle + 1) - # Indexing is not needed - l_idx = [] - else: - l_idx = [str(index)] - - prop_def = {} - prop_alias = {} - - # Generate label for each field of the property element - for i in range(num_cells): - l_cellname = [str(cell_yaml['#cells'][i]).upper()] - if l_cell == l_cellname: - label = l_base + l_cell + l_idx - else: - label = l_base + l_cell + l_cellname + l_idx - label_name = l_base + name + l_cellname - prop_def['_'.join(label)] = prop_values.pop(0) - if len(name): - prop_alias['_'.join(label_name)] = '_'.join(label) - - # generate defs for node aliases - if node_address in aliases: - for i in aliases[node_address]: - alias_label = convert_string_to_label(i) - alias = [alias_label] + label[1:] - prop_alias['_'.join(alias)] = '_'.join(label) - - insert_defs(node_address, prop_def, prop_alias) - - # recurse if we have anything left - if len(prop_values): - extract_cells(node_address, yaml, prop, prop_values, names, - index + 1, def_label, generic) - - def extract_single(node_address, yaml, prop, key, def_label): prop_def = {} @@ -438,27 +304,24 @@ def extract_property(node_compat, yaml, node_address, prop, prop_val, names, if prop == 'reg': if 'partition@' in node_address: # reg in partition is covered by flash handling - flash.extract(node_address, yaml, prop, names, def_label) + flash.extract(node_address, yaml, prop, def_label) else: - reg.extract(node_address, yaml, prop, names, def_label) + reg.extract(node_address, yaml, prop, def_label) elif prop == 'interrupts' or prop == 'interrupts-extended': interrupts.extract(node_address, yaml, prop, names, def_label) + elif prop == 'compatible': + compatible.extract(node_address, yaml, prop, def_label) + # do extra property definition based on heuristics + # do it here as the compatible property is mandatory + heuristics.extract(node_address, yaml, prop, def_label) elif 'pinctrl-' in prop: - pinctrl.extract(node_address, yaml, prop, names, def_label) + pinctrl.extract(node_address, yaml, prop, def_label) elif 'clocks' in prop: - clocks.extract(node_address, yaml, prop, names, def_label) + clocks.extract(node_address, yaml, prop, def_label) elif 'gpios' in prop: - try: - prop_values = list(reduced[node_address]['props'].get(prop)) - except: - prop_values = reduced[node_address]['props'].get(prop) - - extract_controller(node_address, yaml, prop, prop_values, 0, - def_label, 'gpio') - extract_cells(node_address, yaml, prop, prop_values, - names, 0, def_label, 'gpio') + gpios.extract(node_address, yaml, prop, def_label) else: - default.extract(node_address, yaml, prop, names, def_label) + default.extract(node_address, yaml, prop, def_label) def extract_node_include_info(reduced, root_node_address, sub_node_address, @@ -543,7 +406,6 @@ def yaml_traverse_inherited(node): """ Recursive overload procedure inside ``node`` ``inherits`` section is searched for and used as node base when found. Base values are then overloaded by node values - Additionally, 'id' key of 'inherited' dict is converted to 'node_type' and some consistency checks are done. :param node: :return: node @@ -555,15 +417,12 @@ def yaml_traverse_inherited(node): # If 'title' is missing, make fault finding more easy. # Give a hint what node we are looking at. print("extract_dts_includes.py: node without 'title' -", node) - for prop in ('title', 'id', 'version', 'description'): + for prop in ('title', 'version', 'description'): if prop not in node: node[prop] = "<unknown {}>".format(prop) print("extract_dts_includes.py: '{}' property missing".format(prop), "in '{}' binding. Using '{}'.".format(node['title'], node[prop])) - if 'node_type' not in node: - node['node_type'] = [node['id'],] - if 'inherits' in node: if isinstance(node['inherits'], list): inherits_list = node['inherits'] @@ -573,21 +432,20 @@ def yaml_traverse_inherited(node): for inherits in inherits_list: if 'inherits' in inherits: inherits = yaml_traverse_inherited(inherits) - if 'node_type' in inherits: - node['node_type'].extend(inherits['node_type']) - else: - if 'id' not in inherits: - inherits['id'] = "<unknown id>" - title = inherits.get('title', "<unknown title>") - print("extract_dts_includes.py: 'id' property missing in", - "'{}' binding. Using '{}'.".format(title, - inherits['id'])) - node['node_type'].append(inherits['id']) - # id, node_type, title, description, version of inherited node + if 'type' in inherits: + if 'type' not in node: + node['type'] = [] + if not isinstance(node['type'], list): + node['type'] = [node['type'],] + if isinstance(inherits['type'], list): + node['type'].extend(inherits['type']) + else: + node['type'].append(inherits['type']) + + # type, title, description, version of inherited node # are overwritten by intention. Remove to prevent dct_merge to # complain about duplicates. - inherits.pop('id') - inherits.pop('node_type', None) + inherits.pop('type', None) inherits.pop('title', None) inherits.pop('version', None) inherits.pop('description', None) @@ -754,10 +612,9 @@ def generate_node_definitions(yaml_list): extract_string_prop(chosen[k], None, "label", v) node_address = chosen.get('zephyr,flash', 'dummy-flash') - flash.extract(node_address, yaml_list, 'zephyr,flash', None, 'FLASH') + flash.extract(node_address, yaml_list, 'zephyr,flash', 'FLASH') node_address = chosen.get('zephyr,code-partition', node_address) - flash.extract(node_address, yaml_list, 'zephyr,code-partition', None, - 'FLASH') + flash.extract(node_address, yaml_list, 'zephyr,code-partition', 'FLASH') return defs @@ -769,6 +626,8 @@ def parse_arguments(): parser.add_argument("-d", "--dts", nargs=1, required=True, help="DTS file") parser.add_argument("-y", "--yaml", nargs='+', required=True, help="YAML file directories, we allow multiple") + parser.add_argument("-e", "--edts", nargs=1, required=True, + help="Generate EDTS database file for the build system") parser.add_argument("-f", "--fixup", nargs='+', help="Fixup file(s), we allow multiple") parser.add_argument("-i", "--include", nargs=1, required=True, @@ -797,6 +656,7 @@ def main(): generate_keyvalue_file(args.keyvalue[0]) generate_include_file(args.include[0], args.fixup) + edts.save(args.edts[0]) if __name__ == '__main__': diff --git a/scripts/gen_code.py b/scripts/gen_code.py new file mode 100755 index 000000000000..36719134ef74 --- /dev/null +++ b/scripts/gen_code.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2018 Bobby Noelte. +# +# SPDX-License-Identifier: Apache-2.0 + +import sys + +from codegen.codegen import CodeGen + +if __name__ == '__main__': + ret = CodeGen().callableMain(sys.argv) + sys.exit(ret)