Module 9 · Lab 6
Device tree and pin multiplexing
A PC's buses announce what is plugged into them. Most peripherals on an Arm system-on-chip cannot, so the board ships a description of its hardware, and the header's pins can each be switched between several jobs.
Key ideas
- The device tree is a tree of nodes, one per device. Each says what the device is (
compatible), where its registers are (reg), and which interrupts, clocks and regulators it uses.statusturns it on or off. - Pin multiplexing: one pad of the system-on-chip can be a GPIO, or an I2C, SPI, UART or PWM signal. A function-select register picks which, and the kernel's pin-control driver writes it from the device tree's pin-control nodes. Only one function owns a pad at a time, so enabling a bus on two pins takes them away from GPIO.
ldto conflictschecks whether two overlays claim the same pin;gpioinfoshows whether a line is already held by a bus, a driver or a program. - An overlay is a patch to the board's device tree, applied live to the running kernel or merged so the bootloader loads it at boot, that enables a bus on header pins or adds a part on it, without rebuilding the kernel or the base tree.
- When an overlay adds a part with an in-kernel driver, the kernel probes it and the part appears in
/sysand/devwith no code written.
Pin multiplexing
lgpio pinmux 7J1 <pin> lists the functions a pin's pad can carry on your board; gpioinfo shows what holds the pin now.Device tree or ACPI
A PC learns its hardware differently. Its firmware hands the operating system ACPI tables, and those tables can contain small programs the OS runs to switch devices on and off. Arm boards like the course boards use a device tree: a plain description, with no code in it. The same Linux kernel understands both, and 64-bit Arm servers often use ACPI. What decides it is what the firmware provides.
| Device tree | ACPI | |
|---|---|---|
| What it is | Data only: nodes and properties, compiled from .dts source into a binary .dtb | Tables from the firmware, including AML bytecode that the OS interprets to run firmware-defined methods |
| Who writes it | Board and kernel developers, in the open with the kernel | The firmware vendor, built into the firmware |
| How the OS gets it | The bootloader passes it in memory; through UEFI it arrives as a configuration table | The firmware publishes the tables; the OS finds them through UEFI |
| Power and device control | The kernel's drivers do it, using the clocks, regulators and resets the tree names | Often firmware methods the OS calls, so the firmware keeps control |
| Adding a part on a header | An overlay patches the tree | An extra table, or a firmware update |
| Where you meet it | Most Arm and embedded boards, including both course boards | x86 PCs and laptops, and many Arm servers |
On the course boards, U-Boot hands Linux a device tree through UEFI (module 7); there are no ACPI tables to read. The kernel log says which it found in its first lines.
The wiring tool
libretech-wiring-tool is Libre Computer's catalogue of ready-made overlays for each board's 40-pin header, and the commands that use them. Each board has its own set: one overlay per bus or part, a pin map of the header, and slot names that mean the same header pins on every board, so the same command works on Das Frite and on Solitude:
| Slot | Header pins | Overlay on both course boards |
|---|---|---|
H40P_I2C_1 | 27 (SDA), 28 (SCL) | I2C bus |
H40P_I2C_1_SSD1306_128x64 | 27, 28 | The I2C bus with the SSD1306 128 × 64 OLED bound to the kernel's driver |
H40P_SPI_0_1CS | 19 (MOSI), 21 (MISO), 23 (SCLK), 24 (CS0) | SPI bus with one chip select |
H40P_SPI_0_1CS_DEV | 19, 21, 23, 24 | The same bus with a spidev device for user-space access |
Das Frite's console uses header pins 3 and 5, which other boards use for I2C; that is why the course uses the slot on pins 27 and 28 on both boards.
Overlays with ldto
ldto is the wiring tool's overlay command. Run the changing ones with sudo.
| Command | What it does |
|---|---|
ldto list | Every overlay for this board, with its slot name and a one-line summary |
ldto info H40P_I2C_1 | The pins an overlay claims, what it needs first and what needs it |
ldto conflicts A B | Whether two overlays want the same pin or bus |
ldto enable --dry-run A | The plan: which overlays would be applied, in which order, on which pins |
ldto enable A / ldto disable A | Apply to the running kernel now, or take it off; gone at the next boot |
ldto merge A | Make it permanent: merge it into the device tree the bootloader loads from the EFI system partition |
ldto status | What is applied now, what is merged, and what the next boot will use |
ldto reset | Remove the merged tree, so the next boot uses the firmware's own |
lgpio pinmux 7J1 27 | The companion GPIO tool: a header pin's pad and every function it can carry (7J1 is the 40-pin header) |
ldto applies its catalogue's overlays through the kernel's configfs overlay interface, and you can use the same interface for an overlay you wrote: compile it with dtc -@ -I dts -O dtb -o my.dtbo my.dts, then sudo mkdir /sys/kernel/config/device-tree/overlays/my, write the file into it with sudo sh -c 'cat my.dtbo > /sys/kernel/config/device-tree/overlays/my/dtbo', and check that status in that directory reads applied. sudo rmdir of the directory takes it off again.
Where the running tree comes from
Which tree Linux boots with is decided in this order, and knowing it explains most surprises:
| Source | When it applies | Kept across a reboot? |
|---|---|---|
| The tree built into the bootloader, plus overlays the firmware applies from SPI flash | When nothing overrides it | Yes |
A tree on the EFI system partition, written by ldto merge | Whenever that file is present; it replaces the built-in tree | Yes, until ldto reset or until a kernel update overwrites the file (re-merge then; ldto status says so) |
Overlays applied live with ldto enable | On top of whichever tree booted | No |
Try an overlay live first; merge it only once it works, so a bad overlay cannot stop the board from booting.
On the bench
In short, what you do in lab 6, where the steps are given in full:
- Read the live tree under
/proc/device-tree, decompile it withdtc, and find the first kernel log lines that say it booted from a device tree. - Run
lgpio pinmux 7J1 27(7J1 is the wiring tool's name for the 40-pin header) and compare it with the same pin in the GPIO pinout: every function its pad can carry, and the register write that selects each. - With
ldto listandldto info H40P_I2C_1, find the I2C overlay and the pins it claims; apply it withsudo ldto enable H40P_I2C_1and check that a new/dev/i2c-*appears. - Write your own overlay that binds the kernel's DS3231 real-time clock driver on that bus and apply it live through the kernel's configfs overlay interface. Check that a second
/dev/rtcappears, then remove your overlay and take the bus off withsudo ldto disable H40P_I2C_1.
Resources
| Resource | Use in this module |
|---|---|
| GPIO pinout: Das Frite · Solitude | Every header pin's functions, libgpiod line, pad and mux register |
| libretech-wiring-tool | Ready-made overlays for the 40-pin header, and the tool that applies them |
| ldto documentation | Every ldto command, and the header slot table |
| GPIO pin header maps and wiring tool | How to use the wiring tool |
| Kernel devicetree documentation | The format and its bindings |
| Kernel ACPI documentation | How Linux uses ACPI, for comparison |