After reading about the much discussed Device Tree for quite a long time as a holy savior of the ARM world I had the chance to get my fingers on it in a real world application. The issue was to upgrade Linux system from 3.0 kernel to 3.13 on a custom Vybrid VF610 board. The original 3.0-based system from Timesys was not working properly in some aspects and needed a bit of an overhaul.
With the new 3.13 kernel the need to describe hardware in device tree emerged. For those of you who didn’t have the pleasure with this concept yet, the device tree offers a way to let the non device-specific kernel know exactly what kind of hardware is it running on. It is useful for platforms, where there is no standardized way to detect this automatically (like in x86 systems).
The device tree system consists of Device Tree Source (DTS), Device Tree Compiler (DTC) and compiled Device Tree Blob (DTB). The source is hierarchically sorted based on processor architecture, family and finally the board itself, by including the parent layer in each file. After writing DTS, you compile it with DTC and load the created blob to specified memory location next to kernel itself by the bootloader. The blob is fetched by kernel at boot time and device drivers are loaded and configured accordingly.
On first sight, this way of describing hardware seems very clean, organized and easy to use. Actually, if you are porting Linux onto a new board and not run into any weird problems, describing hardware takes very short time. But, here is the catch. There seem to be many weird problems. As the device tree is not yet used for a very long time, there are many bugs, inconsistencies and the documentation for many devices could be substantially better. As it is, you spend a very long time finding examples how to write a DTS node properly, because the documentation gave you only a vague idea.
Still, these problems could be resolved, given time, and result in a lot less headache for developers and maintainers, than the former method using custom board files. However, there is one thing principally wrong with this whole concept. I’m obviously not the first to think about this, as seen in a discussion at the Debian forum. The problem is, custom ARM boards have vastly distinct hardware configuration, often with some compromises and dirty solutions, with which the linux programmer must deal later. It is commonplace to some piece of hardware to require its own startup procedure, timing or prerequisites. For example, the hardware designed wanted to save some cash on external clock and wants to use a processor’s PWM pin as clock source for sound Codec. Using a board file, this could be simply accomplished by setting corresponding PWM registers prior to loading the driver. But how do you do this with device tree? There is nowhere to put executable code and little support for sequencing. Set registers in bootloader? Tough luck, the kernel can reset them at boot time for no obvious reason. So what else? Write your own driver for it? And how do you properly delay loading of other drivers, before the custom initialization completes?
It seems like the Device Tree is a nice concept… on paper. It possibly makes many things cleaner and helps the maintainers, but it is actually not very good at providing support for custom hardware, which is exactly what it is meant to do.