-
Notifications
You must be signed in to change notification settings - Fork 9
device tree
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
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.
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.
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";
};
};
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
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:
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
The device tree compiler dtc
can be executed manually from a kernel devshell like:
dtc -I dts -O dtb -o mydtbo.dtbo mydtbo.dts
- https://www.raspberrypi.org/documentation/configuration/device-tree.md
- https://github.com/raspberrypi/documentation/blob/master/configuration/pin-configuration.md
- Device Trees for Dummies http://events.linuxfoundation.org/sites/events/files/slides/petazzoni-device-tree-dummies.pdf
- Device Tree Usage http://www.devicetree.org/Device_Tree_Usage
- http://elinux.org/Device_Tree_Reference
- devicetree: kernel internals and practical troubleshooting http://events.linuxfoundation.org/sites/events/files/slides/dt_internals.pdf