From: Daniel Golle <daniel@makrotopia.org>
To: "Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Nathan Chancellor" <nathan@kernel.org>,
"Nicolas Schier" <nsc@kernel.org>,
"Saravana Kannan" <saravanak@kernel.org>,
"Daniel Golle" <daniel@makrotopia.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Masahiro Yamada" <masahiroy@kernel.org>,
"Thomas Weißschuh" <linux@weissschuh.net>,
"Tamir Duberstein" <tamird@kernel.org>,
"Steven Rostedt" <rostedt@goodmis.org>,
"Aleksander Jan Bajkowski" <olek2@wp.pl>,
"Guenter Roeck" <linux@roeck-us.net>,
"Test User" <test@example.com>,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kbuild@vger.kernel.org
Subject: [PATCH v3 0/3] dt-bindings: automated coding style check for DTS examples
Date: Mon, 11 May 2026 00:58:15 +0100 [thread overview]
Message-ID: <cover.1778454442.git.daniel@makrotopia.org> (raw)
Documentation/devicetree/bindings/dts-coding-style.rst documents
the style expected of DT examples and source files, but nothing
existing actually enforces it. dtc tolerates arbitrary whitespace,
yamllint only sees the YAML envelope and not the DTS content
inside literal block scalars, and so reviewers spend cycles
flagging issues that tooling could catch.
Add scripts/dtc/dt-check-style, a Python tool that checks DTS
coding style on YAML binding examples and on .dts/.dtsi/.dtso
source files. Rules live in a small declarative registry; each
rule is tagged 'relaxed' (default) or 'strict' (opt-in for new
submissions). Promoting a rule from strict to relaxed is a
one-line edit once the tree catches up.
Relaxed mode covers trailing whitespace, tab characters in YAML
examples, mixed tab+space indents, and the per-input-type indent
character (1 tab for .dts/.dtsi/.dtso). It is zero-violation on
the current tree and runs as part of dt_binding_check_one, so no
new warnings appear in `make dt_binding_check`.
Strict mode adds indent unit and depth consistency; blank-line
policy (no consecutive blanks or blanks at body edges; required
blank line before each child node and before "status"); property
ordering by canonical bucket (compatible, reg/reg-names, ranges,
standard, vendor, status) with declarative within-bucket pairing
rules (<x>-names follows <x>, pinctrl-names follows the last
pinctrl-N) and natural-sort fallback; sibling node ordering by
unit address or natural-sort name; line length (80 columns);
continuation alignment of multi-line property values under the
first '<' or '"' after the '='; lowercase hex literals and unit
addresses; single-spaced values inside <...>; closing-brace
placement; and unused-label detection (skipped for .dtsi/.dtso
since labels there are exported to includers/applies-to).
Together these constrain a DT structure to a single canonical
rendering modulo the author's choice of when to wrap properties
for readability. Comments are intentionally out of scope. Strict
mode is opt-in, intended for use by checkpatch.pl in a follow-up
series.
The tool reads file paths from @argfile and parallelises across
CPUs via -j N. With no -j given it picks up $PARALLELISM (set by
scripts/jobserver-exec from the GNU make jobserver) and falls
back to os.cpu_count() otherwise. Running as one Python
invocation amortises the ruamel.yaml import across the whole
tree -- ~2s on a 32-CPU host vs ~28s sequential. ruamel.yaml is
the only non-stdlib dependency, already required by dtschema.
A selftest under scripts/dtc/dt-style-selftest/ pairs good/ and
bad/ fixtures with expected output so rule behaviour can be
exercised independently of the full tree via the
dt_style_selftest top-level make target.
---
v1: https://lore.kernel.org/all/cover.1776700167.git.daniel@makrotopia.org/
v2: https://lore.kernel.org/all/cover.1777471439.git.daniel@makrotopia.org/
Changes since v2:
- route findings to stderr so a quiet dt_binding_check produces
no output (Rob)
- switch the Makefile recipe from mktemp to Kbuild's
$(tmp-target) so build output stays inside the build folder
(Nathan)
- collapse the recipe's exit-handling tail into the familiar
"&& touch $@ || true" pattern, matching cmd_chk_bindings;
keeps future warnings non-fatal (Rob, Nathan)
- explain in patch 2/3 why the recipe uses an explicit
$(PYTHON3) prefix where the neighbouring recipes call their
scripts directly (Rob)
- append a trailing newline to every expected/*.txt selftest
fixture (Rob)
- restore the trailing whitespace inside yaml-trailing-ws.yaml
that had been silently stripped during re-application, so the
selftest actually exercises the trailing-whitespace rule
Changes since v1:
- rules declared in a registry tagged relaxed/strict; default
relaxed mode is zero-violation on the current tree
- tool now also accepts .dts/.dtsi/.dtso files directly (with a
tab-indent variant); unused-labels skipped for .dtsi/.dtso
where labels are exported to includers/applies-to
- renamed dt-check-example-style -> dt-check-style
- added -j N with $PARALLELISM (jobserver) awareness
- dropped node-name [a-z0-9-] check (Rob: better as a meta-schema)
- property-order rebuilt around buckets + declarative pairing
rules plus natural-sort fallback
- added child-name-order, required-blank-lines, hex-case,
unit-address-format, value-whitespace, node-close-alone,
line-length and continuation-alignment to strict mode
- new selftest patch (Krzysztof: "would be happy to see at
least a few test cases for it")
Default relaxed mode is zero-violation on the current tree once
the small prep-cleanup series [1] has landed.
Strict-mode violation counts on a current tree (5506 YAML
bindings, 6530 in-tree .dts/.dtsi/.dtso under arch/):
rule yaml dts
property-order 14457 240804
indent-consistent 2435 294778
continuation-alignment 2462 187914
unused-labels 3611 11628
required-blank-lines 1862 47351
line-length 102 25999
child-name-order 664 16409
mixed-indent-chars 0 13275
indent-unit-strict 1493 --
child-address-order 69 4075
blank-lines 91 1963
value-whitespace 87 983
node-close-alone 40 783
hex-case 78 666
indent-unit 181 --
indent-unit-dts -- 202
unit-address-format 5 39
trailing-whitespace 0 10
(YAML and DTS columns reflect the rules that apply to each input
type; e.g. indent-unit-strict is YAML-only since .dts files use
tabs, indent-unit-dts is the equivalent DTS-only check.
unused-labels is skipped for .dtsi/.dtso since labels there are
exported to includers/applies-to.)
The script was written with generous help from Claude Opus 4.7,
since my Python is even worse than my DTS coding style.
[1] https://lore.kernel.org/all/cover.1777434096.git.daniel@makrotopia.org/
Daniel Golle (3):
dt-bindings: add DTS style checker
dt-bindings: wire style checker into dt_binding_check
dt-bindings: add self-test fixtures for style checker
Documentation/devicetree/bindings/Makefile | 19 +-
Makefile | 6 +
scripts/dtc/dt-check-style | 1063 +++++++++++++++++
.../dtc/dt-style-selftest/bad/dts-spaces.dts | 13 +
.../bad/yaml-child-addr-order.yaml | 41 +
.../bad/yaml-child-name-order.yaml | 37 +
.../bad/yaml-cont-align.yaml | 30 +
.../dt-style-selftest/bad/yaml-hex-case.yaml | 29 +
.../bad/yaml-indent-strict.yaml | 29 +
.../bad/yaml-line-length.yaml | 29 +
.../bad/yaml-mixed-indent.yaml | 29 +
.../bad/yaml-node-close.yaml | 31 +
.../bad/yaml-prop-order.yaml | 29 +
.../bad/yaml-prop-pairing.yaml | 33 +
.../bad/yaml-required-blank.yaml | 33 +
.../dtc/dt-style-selftest/bad/yaml-tab.yaml | 29 +
.../bad/yaml-trailing-ws.yaml | 29 +
.../dt-style-selftest/bad/yaml-unit-addr.yaml | 29 +
.../bad/yaml-unused-label.yaml | 29 +
.../dt-style-selftest/bad/yaml-value-ws.yaml | 29 +
.../expected/dts-spaces.dts.txt | 2 +
.../expected/yaml-child-addr-order.yaml.txt | 2 +
.../expected/yaml-child-name-order.yaml.txt | 2 +
.../expected/yaml-cont-align.yaml.txt | 2 +
.../expected/yaml-hex-case.yaml.txt | 2 +
.../expected/yaml-indent-strict.yaml.txt | 2 +
.../expected/yaml-line-length.yaml.txt | 2 +
.../expected/yaml-mixed-indent.yaml.txt | 3 +
.../expected/yaml-node-close.yaml.txt | 2 +
.../expected/yaml-prop-order.yaml.txt | 2 +
.../expected/yaml-prop-pairing.yaml.txt | 3 +
.../expected/yaml-required-blank.yaml.txt | 3 +
.../expected/yaml-tab.yaml.txt | 2 +
.../expected/yaml-trailing-ws.yaml.txt | 2 +
.../expected/yaml-unit-addr.yaml.txt | 2 +
.../expected/yaml-unused-label.yaml.txt | 2 +
.../expected/yaml-value-ws.yaml.txt | 2 +
.../dtc/dt-style-selftest/good/dts-tab.dts | 30 +
.../dt-style-selftest/good/yaml-4space.yaml | 41 +
scripts/dtc/dt-style-selftest/run.sh | 67 ++
40 files changed, 1769 insertions(+), 2 deletions(-)
create mode 100755 scripts/dtc/dt-check-style
create mode 100644 scripts/dtc/dt-style-selftest/bad/dts-spaces.dts
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-child-addr-order.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-child-name-order.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-cont-align.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-hex-case.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-indent-strict.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-line-length.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-mixed-indent.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-node-close.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-prop-order.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-prop-pairing.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-required-blank.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-tab.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-trailing-ws.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-unit-addr.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-unused-label.yaml
create mode 100644 scripts/dtc/dt-style-selftest/bad/yaml-value-ws.yaml
create mode 100644 scripts/dtc/dt-style-selftest/expected/dts-spaces.dts.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-child-addr-order.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-child-name-order.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-cont-align.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-hex-case.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-indent-strict.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-line-length.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-mixed-indent.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-node-close.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-prop-order.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-prop-pairing.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-required-blank.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-tab.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-trailing-ws.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-unit-addr.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-unused-label.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/expected/yaml-value-ws.yaml.txt
create mode 100644 scripts/dtc/dt-style-selftest/good/dts-tab.dts
create mode 100644 scripts/dtc/dt-style-selftest/good/yaml-4space.yaml
create mode 100755 scripts/dtc/dt-style-selftest/run.sh
--
2.54.0
next reply other threads:[~2026-05-10 23:58 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-10 23:58 Daniel Golle [this message]
2026-05-10 23:58 ` [PATCH v3 1/3] dt-bindings: add DTS style checker Daniel Golle
2026-05-10 23:58 ` [PATCH v3 2/3] dt-bindings: wire style checker into dt_binding_check Daniel Golle
2026-05-10 23:59 ` [PATCH v3 3/3] dt-bindings: add self-test fixtures for style checker Daniel Golle
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cover.1778454442.git.daniel@makrotopia.org \
--to=daniel@makrotopia.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=linux@weissschuh.net \
--cc=masahiroy@kernel.org \
--cc=nathan@kernel.org \
--cc=nsc@kernel.org \
--cc=ojeda@kernel.org \
--cc=olek2@wp.pl \
--cc=robh@kernel.org \
--cc=rostedt@goodmis.org \
--cc=saravanak@kernel.org \
--cc=tamird@kernel.org \
--cc=test@example.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox