Real quickly, what is a device tree [DT] overlay? Well, just like a .config file - such as those used in Minecraft Mods - a device tree overlay describes how the kernel is wired in order to take advantage of any new hardware peripherals dynamically - in the case of the bone, it is most commonly used to describe which pins are wire to what device and who has compatibility.
Let's review over the structure of a simple device tree: (Thanks to Adafruit for their valuable detailing)
Unfortunately, Debian and several other distros do not come with device tree source files, just the compiled blobs. This was unfortunate for me as I had four Debian-imaged bones and one Angstrom bone that I forgot the login info to... after several hours I managed to reimage the Angstrom copy to see if the source files were even there, and thankfully they were!
EDIT: While browsing through the raw Linux Kernel source code, I found a number of other *.dts files linking to many other devices. To find specific names and values for these trees, the kernel tree its self has all the answers - it may be intimidating at first but really I feel it is no different from Minecraft: Kernel=Vanilla, Drivers=Mods, Hardware Descriptors=Config Files. The Beaglebone Black uses an OMAP3 [OMAP3630] microprocessor also references as AM33XX in the source code. Linux Source Code
This is the version of the DT, which is 'version 1'
/dts-v1/;
This comes next, tagging the DT as a plugin
/plugin/;
Without specifying compatibility, this plugin would not work
compatible = "ti,beaglebone", "ti,beaglebone-black";
Next is the identification, including the DT name and version - which seems to always be '00A0' (this is also the name of the file in the form NAME-VERSION.dtbo)
part-number = "BB-BONE-DT-NAME";
version = "00A0";
Include any and all resources to be used. (In some cases, just the pins are enough, otherwise it is always good to include the device the pins will be muxed to as well) Here the pin is specified in the form HEADER.PIN, the first pru will also be used:
exclusive-use = "P9.27", "pru0";
And finally the fragments, which can be seen as partitions, or 'structs' in a c-stylized way of looking at things. A device tree can have as many fragments as it needs, but for the simplest layouts, one only needs two: the first for pin muxing and the second for device initialization and pin binding. The syntax goes as follows: fragment@NUM { }; so fragment@0 {}; or fragment@2 {};
A fragment will begin with a target, followed by the __overlay__ block, and within that block resides the settings to be applied to or through the targeted device. For example:
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
token_name: sub_name {
pinctrl-single,pins = <
0x1a4 0x25
>;
};
};
};
The target is am33xx_pinmux and through the target via 'pinctrl-single,pins,' pin P9.27(0x1a4) is muxed to pin mode 5 as a 'fast-input' with an internal pull-down (0x25) - this prepares the pins for PRU0 output. The 'token_name:' is referenced in other fragments further down.
When initializing a device in the device tree, one must set the status to 'okay.' Then in order to do anything with that device, one must assign the pins created earlier:
fragment@2 {
target = <&pruss>;
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&token_name>;
};
};
The pin names can be left as 'default.' Sometimes there are other names that can be added for state manipulation such as found in the source file: cape-boneblack-hdmi-00A0.dts: pinctrl-names = "default", "off"; which can be seen in action through shell:
# cat /sys/devices/ocp.*/hdmi.*/pinmux_state
default
# echo off > /sys/devices/ocp.*/hdmi.*/pinmux_state
# cat /sys/devices/ocp.*/hdmi.*/pinmux_state
off
# echo "test" > /sys/devices/ocp.*/hdmi.*/pinmux_state
-sh: echo: write error: No such device
The following is a list of devices that can be modified or used via device tree overlays:
am33xx_pinmux | ocp - on chip peripherals |
tscadc - analog digital converter | mac - media access control |
eCAP0_in_PWM0_out | eCAP1_in_PWM1_out |
eCAP2_in_PWM2_out | tps - transaction processing system |
mcasp0 - multichannel audio serial port | mcasp1 |
eMMC_RSTn | gpmc - general purpose memory controller |
pruss - programmable real-time unit subsystem | pru |
pru0 | pru1 |
spi0 - serial peripheral interface | spi1 |
uart1 - universal asynchronous receive transmit | uart2 |
uart3 | uart4 |
uart5 | uart6 |
i2c0 - inter-integrated circuit | i2c1 |
i2c2 | intc - interrupt controller |
ehrpwm0 - enhanced high resolution pwm | ehrpwm0A |
ehrpwm0B | ehrpwm1 |
ehrpwm1A | ehrpwm1B |
ehrpwm2 | ehrpwm2A |
ehrpwm2B | epwmss0 |
epwmss1 - enhanced pulse-width mod. subsystem | epwmss2 |
ecap0 - enhanced capture | ecap1 |
ecap2 | edma - enhanced direct memory access |
lcd - liquid crystal display | lcdc - liquid crystal display controller |
aes - advanced encryption standard | sham |
usb_otg_hs | tps-bl |
dcan0 | dcan1 |
clkout2 | mmc1 - multimedia card |
mmc2 | mmc3 |
timer1 | timer2 |
timer3 | timer4 |
timer5 | timer6 |
timer7 | wdt |
gpio1 - general purpose input output | gpio2 |
gpio3 | gpio4 |
gpio0_0-31 | gpio1_0-31 |
gpio2_031 | gpio3_0-31 |
P8.1-P8.46 | P9.1-P9.46 |
rtc | usb - universal serial bus |
sgx | mdio |
. | . |
To compile the source, run the following shell command:
dtc -O dtb -o $NAME-$VERSION.dtbo -b 0 -@ $NAME-$VERSION.dts
To apply the new overlay, copy the *.dtbo file to /lib/framework and run the command:
echo $NAME > /sys/devices/bone_capemgr.*/slots
Confirm that it has loaded:
cat /sys/devices/bone_capemgr.*/slots
And to remove it, use the slot number where it is found:
echo -$SLOT_NUM > /sys/devices/bone_capemgr.*/slots