Skip to content

device tree

Frank Bauernöppel edited this page Dec 9, 2018 · 20 revisions

The device tree describes the hardware at chip and board level. This is needed for so called platform devices which cannot be detected automatically by software. Examples are:

  • a LED attached to a GPIO
  • a servo motor controlled via PWM
  • a SPI or I2C device
  • on chip devices like interrupt controllers, timers, power controller, memory, ...

This is in contrast to plug-and-play devices attached to USB or PCIe busses and discoverable by software protocols.

For RasPi, the device tree is in file bcm2710-rpi-3-b.dtb on the boot partition in binary form and is loaded by the boot loader and passed on to the Linux kernel.

On a running RasPi, the device tree can be dumped (if feature enabled in kernel config). For brevity, all files were omitted in the following listing:

root@raspberrypi3:~# tree -d /proc/device-tree
/proc/device-tree
|-- __overrides__
|-- __symbols__
|-- aliases
|-- axi
|   |-- dma
|   |-- usb
|   |   `-- hub
|   |       `-- ethernet
|   `-- vc_mem
|-- chosen
|-- clocks
|   |-- clock@3
|   `-- clock@4
|-- cpus
|   |-- cpu@0
|   |-- cpu@1
|   |-- cpu@2
|   `-- cpu@3
|-- fixedregulator_3v3
|-- fixedregulator_5v0
|-- leds
|   |-- act
|   `-- pwr
|-- memory
|-- soc
|   |-- arm-pmu
|   |-- audio
|   |-- aux@0x7e215000
|   |-- cprman@7e101000
|   |-- dma@7e007000
|   |-- dpi@7e208000
|   |-- dsi@7e209000
|   |-- dsi@7e700000
|   |-- expgpio
|   |-- fb
|   |-- firmware
|   |-- firmwarekms@7e600000
|   |-- gpio@7e200000
|   |   |-- audio_pins
|   |   |-- bt_pins
|   |   |-- i2c0
|   |   |-- i2c1
|   |   |-- i2s
|   |   |-- sdhost_pins
|   |   |-- sdio_pins
|   |   |-- spi0_cs_pins
|   |   |-- spi0_pins
|   |   |-- uart0_pins
|   |   `-- uart1_pins
|   |-- gpiomem
|   |-- gpu
|   |-- hdmi@7e902000
|   |-- hvs@7e400000
|   |-- i2c@7e205000
|   |-- i2c@7e804000
|   |-- i2c@7e805000
|   |-- i2cdsi
|   |   |-- bridge@38
|   |   `-- bridge@45
|   |-- i2s@7e203000
|   |-- interrupt-controller@7e00b200
|   |-- local_intc
|   |-- mailbox@7e00b880
|   |-- mmc@7e300000
|   |-- pixelvalve@7e206000
|   |-- pixelvalve@7e207000
|   |-- pixelvalve@7e807000
|   |-- power
|   |-- pwm@7e20c000
|   |-- rng@7e104000
|   |-- sdhost@7e202000
|   |-- serial@7e201000
|   |-- serial@7e215040
|   |-- smi@7e600000
|   |-- sound
|   |-- spi@7e204000
|   |   |-- spidev@0
|   |   `-- spidev@1
|   |-- spi@7e215080
|   |-- spi@7e2150c0
|   |-- syscon@40000000
|   |-- thermal
|   |-- timer
|   |-- usb@7e980000
|   |   `-- usb1@1
|   |       `-- usbether@1
|   |-- v3d@7ec00000
|   |-- vchiq
|   |-- vec@7e806000
|   |-- virtgpio
|   `-- watchdog@7e100000
`-- system

device tree sources (.dts)

Raspi main device tree

For inspection and further configuration, there are also the device tree source files (.dts) and the device tree compiler available during build.

Open a bitbake shell and enter

bitbake -c devshell virtual/kernel

This will open a new shell, a devshell suitable for kernel development. This new shell starts in the kernel source top level folder like ~/raspi/build/tmp/work-shared/raspberrypi3/kernel-source. From here, enter command

ls -l arch/arm/boot/dts/bcm27*

This shows several .dts file which are text files and include files (.dtsi), as the C preprocessor can be used on .dts files.

bcm2710-rpi-3-b.dts is, of course, the one for Raspberry Pi 3 Module B. View it with your favorite editor:

vi arch/arm/boot/dts/bcm2710-rpi-3-b.dts

A .dts file contains nodes and node properties (key-value pairs). Nodes are hierarchically organized in a tree. At the top level you find the root node /.

In this typical example, most parts of the device tree are defined in a base file for the SoC (line #include "bcm2710.dtsi" and board specific settings are overridden in a board specific file:

/dts-v1/;

#include "bcm2710.dtsi"

/ {
        compatible = "brcm,bcm2710","brcm,bcm2709";
        model = "Raspberry Pi 3 Model B";
};

&gpio {
        sdhost_pins: sdhost_pins {
                brcm,pins = <48 49 50 51 52 53>;
                brcm,function = <4>; /* alt0 */
        };

        spi0_pins: spi0_pins {
                brcm,pins = <9 10 11>;
                brcm,function = <4>; /* alt0 */
        };

        spi0_cs_pins: spi0_cs_pins {
                brcm,pins = <8 7>;
                brcm,function = <1>; /* output */
        };

        i2c0_pins: i2c0 {
                brcm,pins = <0 1>;
                brcm,function = <4>;
        };

The &gpio is a label referring to an existing node within the device tree. Within he &gpio section, the subsection

        i2c1_pins: i2c1 {
                brcm,pins = <2 3>;
                brcm,function = <4>;
        };

means: "program the BCM pads 2 and 3 to their alternate function ALT4" (which means: route them to a on-chip I2C hardware unit, see hardware docs.

Further down, the label &i2c1 overrides settings for on-chip i2c1 (i2c hardware unit 1):

&i2c1 {
        pinctrl-names = "default";
        pinctrl-0 = <&i2c1_pins>;
        clock-frequency = <100000>;
};

This means, that i2c1 should use the pins described in label &i2c1_pins and will be initialized to a default clock frequency of 100 kHz.

The kernel will load all necessary hardware drivers mentioned in the device tree and the kernel mode device drivers can query the device tree for settings.

device tree compiler

dtc, the device tree compiler can be invoked from the kernel devshell using make:

make bcm2710-rpi-3-b.dtb

The result is in folder

${BUILDDITR}/tmp/work/raspberrypi3-poky-linux-gnueabi/linux-raspberrypi/*/linux-raspberrypi3-standard-build/arch/arm/boot/dts

Again: you will rarely need to change device tree sources, because much has already been prepared for you. Check config.txt for configuring pre-compiled device tree overlays.

Besides the main device tree, there are pre-compiled device tree overlays for various scenarios, see overlays/ folder on the boot partition.

These must be loaded or even be changed as needed.

device tree overlay: PWM

The device tree overlay sources are in the ${BUILDDIR}/tmp/work-shared/raspberrypi3/kernel-source/arch/arm/boot/dts/overlays folder. Check for the file pwm-overlay.dts:

/dts-v1/;
/plugin/;

/*
Legal pin,function combinations for each channel:
  PWM0: 12,4(Alt0) 18,2(Alt5) 40,4(Alt0)            52,5(Alt1)
  PWM1: 13,4(Alt0) 19,2(Alt5) 41,4(Alt0) 45,4(Alt0) 53,5(Alt1)

N.B.:
  1) Pin 18 is the only one available on all platforms, and
     it is the one used by the I2S audio interface.
     Pins 12 and 13 might be better choices on an A+, B+ or Pi2.
  2) The onboard analogue audio output uses both PWM channels.
  3) So be careful mixing audio and PWM.
*/

/ {
	fragment@0 {
		target = <&gpio>;
		__overlay__ {
			pwm_pins: pwm_pins {
				brcm,pins = <18>;
				brcm,function = <2>; /* Alt5 */
			};
		};
	};

	fragment@1 {
		target = <&pwm>;
		frag1: __overlay__ {
			pinctrl-names = "default";
			pinctrl-0 = <&pwm_pins>;
			assigned-clock-rates = <100000000>;
			status = "okay";
		};
	};

	__overrides__ {
		pin   = <&pwm_pins>,"brcm,pins:0";
		func  = <&pwm_pins>,"brcm,function:0";
		clock = <&frag1>,"assigned-clock-rates:0";
	};
};

device tree overlays: Sense HAT

The Sense HAT is a popular HAT board for the Raspi.

A device tree overlay is a piece of a device tree situated in a separate file. Lets take the sense hat add-on board as an example which features, among others, a number of i2c sensors.

Here is the corresponding source file rpi-sense-overlay.dts located in ${BUILDDIR}/tmp/work-shared/raspberrypi3/kernel-source/arch/arm/boot/dts/overlays:

// rpi-sense HAT
/dts-v1/;
/plugin/;

/ {
	compatible = "brcm,bcm2708", "brcm,bcm2709";

	fragment@0 {
		target = <&i2c1>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			rpi-sense@46 {
				compatible = "rpi,rpi-sense";
				reg = <0x46>;
				keys-int-gpios = <&gpio 23 1>;
				status = "okay";
			};

			lsm9ds1-magn@1c {
				compatible = "st,lsm9ds1-magn";
				reg = <0x1c>;
				status = "okay";
			};

			lsm9ds1-accel6a {
				compatible = "st,lsm9ds1-accel";
				reg = <0x6a>;
				status = "okay";
			};

			lps25h-press@5c {
				compatible = "st,lps25h-press";
				reg = <0x5c>;
				status = "okay";
			};

			hts221-humid@5f {
				compatible = "st,hts221-humid";
				reg = <0x5f>;
				status = "okay";
			};
		};
	};
};

The line target = <&i2c1> addresses the target of the overlay: i2c bus number 1. Five i2c devices will be instantiated on this bus: A driver named rpi,rpi-sense will be loaded which "drives" the i2c device at address 0x46, a driver named st,lsm9ds1-magn will be loaded which "drives" the i2c device at address 0x1c, and so on. See also sense hat for the various i2c devices.

On the RasPi the corresponding kernel modules can be separate files (loadable kernel modules):

/lib/modules/4.9.13/kernel/drivers/mfd/rpisense-core.ko

There are a number of readily available device tree overlays, see https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README

Building a device tree / device tree overlay

The .dts source files are located in the kernel source folder tmp/work-shared/raspberrypi3/kernel-source/arch/arm/boot/dts and its overlays subfolder.

If the source file is not present, check Raspbian online: https://github.com/raspberrypi/linux/tree/rpi-4.14.y/arch/arm/boot/dts but note that the .dts may depend on the kernel version. If everything else fails: write your own .dts.

The compiled .dtb and .dtbo files are located in the tmp/work/raspberrypi3-poky-linux-gnueabi/linux-raspberrypi/*/image/boot folder.

If the compiled file is missing, it can be built:

build with kernel recipe

The .dtb/.dtbo are build by the kernel recipe:

bitbake virtual/kernel

This recipe is automatically executed during when the image is bitbaked.

Open a kernel devshell as follows:

bitbake -c devshell virtual/kernel

The .dts source files are built by issuing the following command from the devshell:

make dtbs

using the device tree compiler

The device tree compiler dtc can be executed manually from a kernel devshell like:

dtc -I dts -O dtb -o mydtbo.dtbo mydtbo.dts

further reading

Clone this wiki locally