Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project(utils)
option(ENABLE_WERROR "Treat compiler warnings as errors" OFF)

# List of subsidiary CMakeLists
add_subdirectory(dtapply)
add_subdirectory(dtmerge)
add_subdirectory(eeptools)
add_subdirectory(kdtc)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# utils
A collection of scripts and simple applications

* [dtapply](dtapply/) - A script that reads a Raspberry Pi `config.txt` and uses `dtmerge`
to apply all its `dtparam` and `dtoverlay` directives to a base `.dtb` file.
* [dtmerge](dtmerge/) - A tool for applying compiled DT overlays (`*.dtbo`) to base Device
Tree files (`*.dtb`). Also includes the `dtoverlay` and `dtparam` utilities.
* [eeptools](eeptools/) - Tools for creating and managing EEPROMs for HAT+ and HAT board.
Expand Down
7 changes: 7 additions & 0 deletions dtapply/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.10...3.27)

include(GNUInstallDirs)

project(dtapply)

install(PROGRAMS dtapply DESTINATION ${CMAKE_INSTALL_BINDIR})
184 changes: 184 additions & 0 deletions dtapply/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# dtapply and examples

`dtapply` reads a Raspberry Pi `config.txt` file and uses `dtmerge` to apply
all of its `dtparam` and `dtoverlay` directives to a base `.dtb` file,
producing a merged `.dtb` without requiring a running Pi. This could be used
to speed up the booting process.

## Usage

```
usage: dtapply [-h] [-o OUTPUT] [--overlays-dir OVERLAYS_DIR]
[--dtmerge DTMERGE] [--model MODEL] [-d] [-n]
dtb config

positional arguments:
dtb Base DTB file (e.g. bcm2711-rpi-4-b.dtb)
config Raspberry Pi config.txt file

options:
-h, --help show this help message and exit
-o OUTPUT, --output OUTPUT
Output DTB file (default: output.dtb)
--overlays-dir OVERLAYS_DIR
Directory containing .dtbo overlay files (default:
auto-detect /boot/firmware/overlays or /boot/overlays)
--dtmerge DTMERGE Path to the dtmerge binary (default: dtmerge)
--model MODEL Override Pi model identifier for section filtering
(e.g. pi4, cm4, pi5)
-d, --debug Pass -d to dtmerge and print extra information
-n, --dry-run Parse and print directives but do not run dtmerge
```

## Example files

| File | Demonstrates |
|---|---|
| `config-basic.txt` | Common `dtparam` and `dtoverlay` lines with no section filtering |
| `config-sections.txt` | Conditional `[section]` headers to target specific Pi models |
| `config-overlay-context.txt` | Multi-line overlay parameters and mixed global/overlay params |

---

## config-basic.txt — Basic usage

```
dtapply bcm2711-rpi-4-b.dtb config-basic.txt -o merged.dtb
```

The simplest case: every directive falls under the implicit `[all]` section
and is applied unconditionally. `dtapply` calls `dtmerge` once per
`dtparam` block and once per `dtoverlay`, chaining the output of each step
into the next.

```
dtparam=audio=on
dtparam=i2c_arm=on
dtparam=spi=on
dtoverlay=vc4-kms-v3d
dtoverlay=w1-gpio,gpiopin=4
```

Produces five `dtmerge` calls in sequence:

```
dtmerge base.dtb step1.dtb - audio=on
dtmerge step1.dtb step2.dtb - i2c_arm=on
dtmerge step2.dtb step3.dtb - spi=on
dtmerge step3.dtb step4.dtb vc4-kms-v3d.dtbo
dtmerge step4.dtb merged.dtb w1-gpio.dtbo gpiopin=4
```

---

## config-sections.txt — Conditional section filters

`config.txt` uses `[section]` headers to gate directives to specific
hardware. `dtapply` infers the Pi model from the DTB filename:

| DTB prefix | Model identifier(s) |
|---|---|
| `bcm2708-rpi-zero-w` | `pi0w` |
| `bcm2708-rpi-b-plus` | `pi1` |
| `bcm2709-rpi-2-b` | `pi0w` |
| `bcm2710-rpi-zero-2-w` | `pi02` |
| `bcm2710-rpi-3-b` | `pi3` |
| `bcm2710-rpi-cm0` | `cm0` |
| `bcm2711-rpi-4-b` | `pi4` |
| `bcm2711-rpi-400` | `pi400` |
Comment thread
timg236 marked this conversation as resolved.
| `bcm2711-rpi-cm4` | `cm4` |
| `bcm2712-rpi-5-b` | `pi5` |
| `bcm2712-rpi-cm5` | `cm5` |
| `bcm2712-rpi-500` | `pi500` |
| … | … |
(not an exhaustive list)

A directive is included if and only if its enclosing section matches the
inferred model, or is `[all]`. Lines before the first `[section]` header
are treated as `[all]`. `[none]` suppresses everything inside it.

```
dtapply bcm2711-rpi-4-b.dtb config-sections.txt -o merged-pi4.dtb
dtapply bcm2712-rpi-5-b.dtb config-sections.txt -o merged-pi5.dtb
```

For `bcm2711-rpi-4-b.dtb` (`pi4` model), only the `[all]` and `[pi4]`
sections are active — the `[pi5]` and `[cm4]` directives are skipped.

If the model cannot be reliably inferred from the filename, use `--model`:

```
dtapply mystery-board.dtb config-sections.txt --model pi4 -o merged.dtb
```

Use `--dry-run` (`-n`) to inspect which directives would be applied without
actually running `dtmerge`:

```
dtapply bcm2712-rpi-5-b.dtb config-sections.txt -n
```

```
Detected model: pi5
Found 3 action(s) to apply:
dtparam=audio=on
dtparam=i2c_arm=on
dtoverlay=vc4-kms-v3d-pi5
dtparam=spi=on
```

---

## config-overlay-context.txt — Overlay context and multi-line parameters

### Parameters split across lines

A `dtoverlay` line sets the *current overlay context*. All subsequent
`dtparam` lines are treated as additional parameters for that overlay until
the context changes. This lets you spread a long parameter list across
multiple lines:

```
dtoverlay=i2c-gpio
dtparam=i2c_gpio_sda=2
dtparam=i2c_gpio_scl=3
dtparam=i2c_gpio_delay_us=2
dtparam=bus=3
```

All five lines are collapsed into a single `dtmerge` call:

```
dtmerge current.dtb next.dtb i2c-gpio.dtbo \
i2c_gpio_sda=2 i2c_gpio_scl=3 i2c_gpio_delay_us=2 bus=3
```

### Global parameters inside an overlay block

Each parameter is resolved against the current overlay's `__overrides__`
node first, falling back to the base device tree's `__overrides__` if it
is not found there. This means base-DT parameters can appear inside an
overlay block without causing an error:

```
dtoverlay=uart0,txd0_pin=14,rxd0_pin=15
dtparam=i2c_arm_baudrate=400000
```

Here `i2c_arm_baudrate` is a base-DT parameter, not a `uart0` parameter.
`dtmerge` detects this automatically and applies it to the base DT. The
result is the same as if the `dtparam` line had appeared outside the
overlay block.

### Resetting the overlay context

A bare `dtoverlay=` (nothing after the `=`) or `dtoverlay=none` ends the
current overlay context. Any `dtparam` lines that follow are then
applied to the base DT only, with no overlay lookup:

```
dtoverlay=gpio-fan,gpiopin=14
dtoverlay= # end gpio-fan context

dtparam=audio=on # base-DT parameter, no overlay involved
```
Loading
Loading