pax_global_header00006660000000000000000000000064152057254550014524gustar00rootroot0000000000000052 comment=8f48565e5cfedc74d3f7512f1e0188e9d85dc1de device-tree-compiler-1.8.1/000077500000000000000000000000001520572545500155375ustar00rootroot00000000000000device-tree-compiler-1.8.1/.cirrus.yml000066400000000000000000000022141520572545500176460ustar00rootroot00000000000000# FreeBSD build with multiple versions freebsd_versions_task: name: FreeBSD $FREEBSD_VERSION make build freebsd_instance: image_family: $FREEBSD_IMAGE matrix: - env: FREEBSD_VERSION: "13.5" FREEBSD_IMAGE: freebsd-13-5 - env: FREEBSD_VERSION: "14.3" FREEBSD_IMAGE: freebsd-14-3 install_script: - pkg install -y git gmake flex bison python3 py312-setuptools swig libyaml pkgconf build_script: - gmake check_script: - gmake check # FreeBSD meson builds with multiple versions freebsd_meson_versions_task: name: FreeBSD $FREEBSD_VERSION meson build freebsd_instance: image_family: $FREEBSD_IMAGE matrix: - env: FREEBSD_VERSION: "13.5" FREEBSD_IMAGE: freebsd-13-5 - env: FREEBSD_VERSION: "14.3" FREEBSD_IMAGE: freebsd-14-3 install_script: - pkg install -y git meson ninja flex bison python3 py312-setuptools swig libyaml pkgconf setup_script: - meson setup -D python=enabled -D yaml=enabled build build_script: - meson compile -C build test_script: - if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi device-tree-compiler-1.8.1/.clang-format000066400000000000000000000073101520572545500201130ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0 # # clang-format configuration file. Intended for clang-format >= 11. # # For more information, see: # # Documentation/dev-tools/clang-format.rst # https://clang.llvm.org/docs/ClangFormat.html # https://clang.llvm.org/docs/ClangFormatStyleOptions.html # --- AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: true AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 Cpp11BracedListStyle: false DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: false # Taken from: # git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' \ # | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ # | LC_ALL=C sort -u ForEachMacros: - 'fdt_for_each_property_offset' - 'fdt_for_each_subnode' - 'for_each_child' - 'for_each_child_withdel' - 'for_each_label' - 'for_each_label_withdel' - 'for_each_marker' - 'for_each_marker_of_type' - 'for_each_property' - 'for_each_property_withdel' IncludeBlocks: Preserve IncludeCategories: - Regex: '.*' Priority: 1 IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false IndentGotoLabels: false IndentPPDirectives: None IndentWidth: 8 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true # Taken from git's rules PenaltyBreakAssignment: 10 PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakComment: 10 PenaltyBreakFirstLessLess: 0 PenaltyBreakString: 10 PenaltyExcessCharacter: 100 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right ReflowComments: false SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatementsExceptForEachMacros SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp03 TabWidth: 8 UseTab: Always ... device-tree-compiler-1.8.1/.editorconfig000066400000000000000000000011161520572545500202130ustar00rootroot00000000000000# EditorConfig is a file format and collection of text editor plugins # for maintaining consistent coding styles between different editors # and IDEs. Most popular editors support this either natively or via # plugin. # # Check https://editorconfig.org for details. root = true [*] end_of_line = lf insert_final_newline = true charset = utf-8 indent_style = space [Makefile*] indent_style = tab indent_size = 8 file_type_emacs = makefile [*.[ch]] indent_style = tab indent_size = 8 [*.py] indent_size = 4 [meson.build] indent_style = space indent_size = 2 [*.lds] indent_style = tab device-tree-compiler-1.8.1/.github/000077500000000000000000000000001520572545500170775ustar00rootroot00000000000000device-tree-compiler-1.8.1/.github/workflows/000077500000000000000000000000001520572545500211345ustar00rootroot00000000000000device-tree-compiler-1.8.1/.github/workflows/build.yml000066400000000000000000000061001520572545500227530ustar00rootroot00000000000000--- name: Build test 'on': push: branches: - main - ci pull_request: branches: - main # ensure that the workflow is only triggered once per PR, subsequent pushes to the PR will cancel # and restart the workflow. See https://docs.github.com/en/actions/using-jobs/using-concurrency concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: build-make: runs-on: ubuntu-latest strategy: fail-fast: false matrix: os: [ "alpine", "archlinux", "fedora", "ubuntu" ] container: image: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v4 - name: Install Dependencies run: | ./scripts/install-deps.sh - name: Build run: | make - name: Run check run: | make check build-meson: runs-on: ubuntu-latest strategy: fail-fast: false matrix: os: [ "alpine", "archlinux", "fedora", "ubuntu" ] container: image: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v4 - name: Install Dependencies run: | ./scripts/install-deps.sh - name: Setup run: meson setup -D python=enabled -D yaml=enabled build - name: Build run: meson compile -C build - name: Run check run: if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi build-macos: runs-on: macos-latest strategy: fail-fast: false matrix: build: [ "make", "meson" ] steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install Dependencies run: | brew install libyaml swig meson ninja pkg-config - name: Build (Make) if: matrix.build == 'make' run: | make - name: Setup (Meson) if: matrix.build == 'meson' run: meson setup -D python=enabled -D yaml=enabled -D tests=false build - name: Build (Meson) if: matrix.build == 'meson' run: meson compile -C build build-windows: runs-on: windows-latest strategy: fail-fast: false matrix: include: - { sys: mingw32, swig: false } - { sys: mingw64, swig: true } - { sys: ucrt64, swig: true } - { sys: clang64, swig: true } name: ${{ matrix.sys }} defaults: run: shell: msys2 {0} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup MSYS2 uses: msys2/setup-msys2@v2 with: msystem: ${{matrix.sys}} update: true install: >- git flex bison pacboy: >- toolchain:p meson:p ninja:p libyaml:p ${{ matrix.swig && 'swig:p python-setuptools-scm:p' || '' }} - name: '🚧 Build' run: | meson setup -Dtools=true -Dtests=false build meson compile -C build device-tree-compiler-1.8.1/.gitignore000066400000000000000000000003461520572545500175320ustar00rootroot00000000000000*.o *.d *.a *.patch *.so *.so.* *~ *.bak *.tab.[ch] lex.yy.c *.lex.c .*.swp /dtc /fdtdump /convert-dtsv0 /version_gen.h /fdtget /fdtput /fdtoverlay /patches /.pc # cscope files cscope.* ncscope.* .eggs/ build/ dist/ *.egg-info/ device-tree-compiler-1.8.1/.gitlab-ci.yml000066400000000000000000000025321520572545500201750ustar00rootroot00000000000000stages: - build variables: GIT_DEPTH: 1 workflow: rules: - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main" - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "ci" - if: $CI_PIPELINE_SOURCE == "merge_request_event" # Linux builds with make .build-make-template: &build-make-template stage: build before_script: - ./scripts/install-deps.sh script: - make - make check interruptible: true build-make-alpine: <<: *build-make-template image: alpine:latest build-make-archlinux: <<: *build-make-template image: archlinux:latest build-make-fedora: <<: *build-make-template image: fedora:latest build-make-ubuntu: <<: *build-make-template image: ubuntu:latest # Linux builds with meson .build-meson-template: &build-meson-template stage: build before_script: - ./scripts/install-deps.sh script: - meson setup -D python=enabled -D yaml=enabled build - meson compile -C build - if ! meson test -C build; then cat build/meson-logs/testlog.txt; false; fi interruptible: true build-meson-alpine: <<: *build-meson-template image: alpine:latest build-meson-archlinux: <<: *build-meson-template image: archlinux:latest build-meson-fedora: <<: *build-meson-template image: fedora:latest build-meson-ubuntu: <<: *build-meson-template image: ubuntu:latest device-tree-compiler-1.8.1/AGENTS.md000066400000000000000000000126441520572545500170510ustar00rootroot00000000000000# AGENTS.md This file provides guidance to AI coding assistants when working with code in this repository. ## Build and Test The build system is Meson (the legacy Makefile still works but is deprecated). ```sh # Configure and build meson setup build meson compile -C build # Run all tests meson test -C build # Run a specific test suite (libfdt, dtc, fdtget, fdtput, fdtdump, fdtoverlay, pylibfdt, utilfdt, dtbs_equal) meson test -C build dtc meson test -C build libfdt # Legacy make (deprecated, still functional) make make check # all tests make checkm # tests under valgrind ``` Optional build dependencies: libyaml (>= 0.2.3) for YAML output, valgrind for memory checking, swig + python3-dev for pylibfdt. ## Architecture The repo contains three main components: ### dtc (Device Tree Compiler) Compiles device tree source (.dts) to binary (.dtb) and vice versa. The pipeline is: parse source → live tree → flatten to blob (or reverse). - **Parsing**: `dtc-lexer.l` (flex) + `dtc-parser.y` (bison) produce a live tree from .dts source. `flattree.c` reads .dtb blobs. `fstree.c` reads /proc/device-tree style filesystem trees. `yamltree.c` writes YAML output. - **Live tree** (`livetree.c`, `dtc.h`): In-memory representation as `struct node` / `struct property` trees with labels, phandles, and source position tracking. The `struct data` type carries property values with type markers and cross-reference markers. - **Checks** (`checks.c`): ~50 semantic checks registered via `WARNING()`, `ERROR()`, and `CHECK()` macros into a `check_table[]`. Each check declares prerequisite checks, forming a DAG. Checks validate DT conventions (node naming, property types, interrupt structures, etc.). Use `-W`/`-E` flags to promote/demote. - **Output**: `flattree.c` writes .dtb blobs and assembler output. `treesource.c` writes .dts source. ### libfdt (Flat Device Tree library) C library for reading/writing .dtb blobs in-place, dual-licensed GPL-2.0-or-later OR BSD-2-Clause. Used in bootloaders, kernels, and hypervisors where the full compiler isn't available. - `fdt_ro.c` — read-only access (property lookup, node traversal) - `fdt_rw.c` — read-write modification of existing blobs - `fdt_sw.c` — sequential-write creation of new blobs - `fdt_wip.c` — "write in place" operations (in-place modification) - `fdt_overlay.c` — device tree overlay application - `fdt_check.c` — blob validation (`fdt_check_full`) - `fdt_addresses.c` — address/size cell helpers - `version.lds` — exported symbol list; new public functions must be added here libfdt is designed to be embeddable: `Makefile.libfdt` can be included by external build systems. The `FDT_ASSUME_MASK` controls safety vs. performance tradeoffs (see `libfdt_internal.h`). ### pylibfdt SWIG-generated Python bindings for libfdt (`pylibfdt/libfdt.i`). Functions not supportable by SWIG should be behind `#ifndef SWIG` in `libfdt.h`. ## Tests Tests live in `tests/`. The test runner is `tests/run_tests.sh` which defines test groups: `libfdt_tests`, `dtc_tests`, `fdtget_tests`, `fdtput_tests`, `fdtoverlay_tests`, `pylibfdt_tests`, etc. Individual C test programs link against libfdt and use helpers from `tests/testutils.c`. Binary test trees are built from assembler macros in `tests/trees.S` via `tests/dumptrees.c` — if you modify `tests/test_tree1.dts`, you must also update `tests/trees.S`. ## AI Contribution Policy See the "AI Coding Assistants" section in CONTRIBUTING.md. Key rules: - **Do not** add `Signed-off-by` tags — only humans can certify the DCO - Use `Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]` for attribution in commit messages - The human submitter is responsible for reviewing all AI-generated code and ensuring license compliance ## Tagging a New Release Releases use the `vMAJOR.MINOR.PATCH` tag format (e.g., `v1.7.2`). An AI agent can prepare the release; the human maintainer reviews, adds `Signed-off-by`, and signs the tag. 1. **Update `VERSION.txt` and commit** — run the prepare script: ```sh scripts/prepare-release X.Y.Z ``` This updates `VERSION.txt` and creates the version bump commit (without `Signed-off-by`, per the AI contribution policy). 2. **Draft the tag message** — write it to a temporary file (e.g., `tag-message.txt`) for the maintainer to review. The format is: ``` DTC X.Y.Z Changes since vPREV include: * Component - Change description - ... ``` Group changes by component (dtc, libfdt, pylibfdt, fdtget, fdtoverlay, Build, General, etc.) with a bullet per notable change. Generate the changelog from `git log vPREV..HEAD`. 3. **Human review** — the maintainer reviews the commit and tag message, then runs the finalize script which amends the commit to add `Signed-off-by`, creates the signed annotated tag, pushes the release commit and tag to origin, and optionally uploads to kernel.org via kup: ```sh scripts/finalize-release tag-message.txt ``` Agents must **never** run `scripts/finalize-release` or `scripts/kup-dtc`. These perform signing, push, and upload operations that only a human maintainer may execute. ## Coding Conventions - License: GPL-2.0-or-later for dtc tools; (GPL-2.0-or-later OR BSD-2-Clause) for libfdt - SPDX identifiers on every file - C style follows kernel conventions: tabs for indentation, `lower_case` names - Compiler warnings are errors (`-Werror`) - libfdt functions return negative `FDT_ERR_*` codes on failure (never errno) device-tree-compiler-1.8.1/BSD-2-Clause000066400000000000000000000031511520572545500174430ustar00rootroot00000000000000Valid-License-Identifier: BSD-2-Clause SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html Usage-Guide: To use the BSD 2-clause "Simplified" License put the following SPDX tag/value pair into a comment according to the placement guidelines in the licensing rules documentation: SPDX-License-Identifier: BSD-2-Clause License-Text: Copyright (c) . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. device-tree-compiler-1.8.1/CLAUDE.md000066400000000000000000000006721520572545500170230ustar00rootroot00000000000000# CLAUDE.md Read and follow AGENTS.md — it has build instructions, architecture notes, coding conventions, and the AI contribution policy for this project. ## Claude Code Specifics When writing `Assisted-by` commit trailers, use `Claude` as the agent name and the model's short ID as the version. For example: ``` Assisted-by: Claude:claude-opus-4-6 ``` Do not use `claude-code`, `Claude Code`, or other variations as the agent name. device-tree-compiler-1.8.1/CONTRIBUTING.md000066400000000000000000000115001520572545500177650ustar00rootroot00000000000000# Contributing to dtc or libfdt There are two ways to submit changes for dtc or libfdt: * Post patches directly to the [devicetree-compiler](mailto:devicetree-compiler@vger.kernel.org) mailing list. * Submit pull requests via [Github](https://github.com/dgibson/dtc/pulls) ## Adding a new function to libfdt.h The shared library uses `libfdt/version.lds` to list the exported functions, so add your new function there. Check that your function works with pylibfdt. If it cannot be supported, put the declaration in `libfdt.h` behind `#ifndef SWIG` so that swig ignores it. ## Tests Test files are kept in the `tests/` directory. Use `make check` to build and run all tests. If you want to adjust a test file, be aware that `tree_tree1.dts` is compiled and checked against a binary tree from assembler macros in `trees.S`. So if you change that file you must change `tree.S` also. ## Developer's Certificate of Origin Like many other projects, dtc and libfdt have adopted the "Developer's Certificate of Origin" (Signed-off-by) process created by the Linux kernel community to improve tracking of who did what. Here's how it works (this is a very slight modification of the description from `Documentation/process/submitting-patches.rst` in the kernel tree): The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below: Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. then you just add a line saying:: Signed-off-by: Random J Developer using your real name (sorry, no pseudonyms or anonymous contributions.) This will be done for you automatically if you use `git commit -s`. Reverts should also include "Signed-off-by". `git revert -s` does that for you. Any further SoBs (Signed-off-by:'s) following the author's SoB are from people handling and transporting the patch, but were not involved in its development. SoB chains should reflect the **real** route a patch took as it was propagated to the maintainers, with the first SoB entry signalling primary authorship of a single author. ## AI Coding Assistants AI tools helping with dtc/libfdt development must follow the standard contribution process described in this document. ### Licensing and Legal Requirements All contributions must comply with the project's licensing requirements: * All code must be compatible with GPL-2.0-or-later * All libfdt code must also be compatible with BSD-2-Clause * Use appropriate SPDX license identifiers ### Signed-off-by and Developer Certificate of Origin AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the Developer Certificate of Origin (DCO). The human submitter is responsible for: * Reviewing all AI-generated code * Ensuring compliance with licensing requirements * Adding their own Signed-off-by tag to certify the DCO * Taking full responsibility for the contribution ### Attribution When AI tools contribute to development, proper attribution helps track the evolving role of AI in the development process. Contributions should include an `Assisted-by` tag in the following format: ``` Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2] ``` Where: * `AGENT_NAME` is the name of the AI tool or framework * `MODEL_VERSION` is the specific model version used * `[TOOL1] [TOOL2]` are optional specialized analysis tools used (e.g., coccinelle, sparse, smatch, clang-tidy) Basic development tools (git, gcc, make, editors) should not be listed. Example: ``` Assisted-by: Claude:claude-3-opus coccinelle sparse ``` device-tree-compiler-1.8.1/Documentation/000077500000000000000000000000001520572545500203505ustar00rootroot00000000000000device-tree-compiler-1.8.1/Documentation/dt-object-internal.txt000066400000000000000000000211761520572545500246050ustar00rootroot00000000000000Device Tree Dynamic Object format internals ------------------------------------------- The Device Tree for most platforms is a static representation of the hardware capabilities. This is insufficient for platforms that need to dynamically insert Device Tree fragments into the live tree. This document explains the Device Tree object format and modifications made to the Device Tree compiler, which make it possible. 1. Simplified Problem Definition -------------------------------- Assume we have a platform which boots using following simplified Device Tree. ---- foo.dts ----------------------------------------------------------------- /* FOO platform */ / { compatible = "corp,foo"; /* shared resources */ res: res { }; /* On chip peripherals */ ocp: ocp { /* peripherals that are always instantiated */ peripheral1 { ... }; }; }; ---- foo.dts ----------------------------------------------------------------- We have a number of peripherals that after probing (using some undefined method) should result in different Device Tree configuration. We cannot boot with this static tree because due to the configuration of the foo platform there exist multiple conflicting peripherals DT fragments. So for the bar peripheral we would have this: ---- foo+bar.dts ------------------------------------------------------------- /* FOO platform + bar peripheral */ / { compatible = "corp,foo"; /* shared resources */ res: res { }; /* On chip peripherals */ ocp: ocp { /* peripherals that are always instantiated */ peripheral1 { ... }; /* bar peripheral */ bar { compatible = "corp,bar"; ... /* various properties and child nodes */ }; }; }; ---- foo+bar.dts ------------------------------------------------------------- While for the baz peripheral we would have this: ---- foo+baz.dts ------------------------------------------------------------- /* FOO platform + baz peripheral */ / { compatible = "corp,foo"; /* shared resources */ res: res { /* baz resources */ baz_res: res_baz { ... }; }; /* On chip peripherals */ ocp: ocp { /* peripherals that are always instantiated */ peripheral1 { ... }; /* baz peripheral */ baz { compatible = "corp,baz"; /* reference to another point in the tree */ ref-to-res = <&baz_res>; ... /* various properties and child nodes */ }; }; }; ---- foo+baz.dts ------------------------------------------------------------- We note that the baz case is more complicated, since the baz peripheral needs to reference another node in the DT tree. 2. Device Tree Object Format Requirements ----------------------------------------- Since the Device Tree is used for booting a number of very different hardware platforms it is imperative that we tread very carefully. 2.a) No changes to the Device Tree binary format for the base tree. We cannot modify the tree format at all and all the information we require should be encoded using Device Tree itself. We can add nodes that can be safely ignored by both bootloaders and the kernel. The plugin dtbs are optionally tagged with a different magic number in the header but otherwise they're simple blobs. 2.b) Changes to the DTS source format should be absolutely minimal, and should only be needed for the DT fragment definitions, and not the base boot DT. 2.c) An explicit option should be used to instruct DTC to generate the required information needed for object resolution. Platforms that don't use the dynamic object format can safely ignore it. 2.d) Finally, DT syntax changes should be kept to a minimum. It should be possible to express everything using the existing DT syntax. 3. Implementation ----------------- The basic unit of addressing in Device Tree is the phandle. Turns out it's relatively simple to extend the way phandles are generated and referenced so that it's possible to dynamically convert symbolic references (labels) to phandle values. This is a valid assumption as long as the author uses reference syntax and does not assign phandle values manually (which might be a problem with decompiled source files). We can roughly divide the operation into two steps. 3.a) Compilation of the base board DTS file using the '-@' option generates a valid DT blob with an added __symbols__ node at the root node, containing a list of all nodes that are marked with a label. Using the foo.dts file above the following node will be generated; $ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts $ fdtdump foo.dtb ... / { ... res { ... phandle = <0x00000001>; ... }; ocp { ... phandle = <0x00000002>; ... }; __symbols__ { res="/res"; ocp="/ocp"; }; }; Notice that all the nodes that had a label have been recorded, and that phandles have been generated for them. This blob can be used to boot the board normally, the __symbols__ node will be safely ignored both by the bootloader and the kernel (the only loss will be a few bytes of memory and disk space). We generate a __symbols__ node to record nodes that had labels in the base tree (or subsequent loaded overlays) so that they can be matched up with references made to them in Device Tree objects. 3.b) The Device Tree fragments must be compiled with the same option but they must also have a tag (/plugin/) that allows undefined references to nodes that are not present at compilation time to be recorded so that the runtime loader can fix them. So the bar peripheral's DTS format would be of the form: /dts-v1/; /plugin/; /* allow undefined references and record them */ / { .... /* various properties for loader use; i.e. part id etc. */ fragment@0 { target = <&ocp>; __overlay__ { /* bar peripheral */ bar { compatible = "corp,bar"; ... /* various properties and child nodes */ } }; }; }; Note that there's a target property that specifies the location where the contents of the overlay node will be placed, and it references the node in the foo.dts file. $ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts $ fdtdump bar.dtbo ... / { ... /* properties */ fragment@0 { target = <0xffffffff>; __overlay__ { bar { compatible = "corp,bar"; ... /* various properties and child nodes */ } }; }; __fixups__ { ocp = "/fragment@0:target:0"; }; }; No __symbols__ node has been generated (no label in bar.dts). Note that the target's ocp label is undefined, so the phandle value is filled with the illegal value '0xffffffff', while a __fixups__ node has been generated, which marks the location in the tree where the label lookup should store the runtime phandle value of the ocp node. The format of the __fixups__ node entry is