Friday, April 22, 2016

Display panels are not special

Why are video timings not specified in device tree?


This is a question that arises every once in a while regarding display panel device tree bindings. This post tries to provide a complete rationale for why this is, so that I will hopefully never have to answer that question again.

First, let's see how a panel is typically described in device tree:
 panel: panel {  
   compatible = "auo,b133xtn01";  
   backlight = <&backlight>;  
   ddc-i2c-bus = <&dpaux>;  
 };
The node name is panel and it has an associated label ("panel:") that consumers can use to easily reference it. The first property defines the compatible string. It identifies both the binding that the device tree node adheres to and also provides the primary means of identifying what kind of device it is.

What binding the device tree node adheres to is important because it defines the other properties, required and optional, that are relevant. In this case the panel can have a backlight associated with it (via a phandle reference) and a DDC bus (via another phandle reference) that is typically used to query the panel's EDID1.

Given that compatible strings are required to uniquely identify a device (via a vendor prefix separated from the model by a comma), they imply a great deal of information about the device. For IP blocks they imply the register layout and programming model. They also imply many static properties of the device, such as internal delays or constraints imposed on external signals.

Extending this to display panels it is natural to conclude that video timings are implied by the compatible string. Similarly, properties such as the physical dimensions of the active display area, type of video bus or pixel format are all implicitly defined by the compatible string.

But panels are special!


For some reason that evades me, people keep thinking that display panels are somehow special.

They really aren't.

Very early on in the process of defining the device tree bindings for panels people suggested that we come up with a generic binding that would allow us to fully describe all panels. But it became clear very quickly that this was never going to work.

I suspect one of the reasons why people think panels are special is because they think that video timings (and perhaps physical dimensions) are the only relevant properties of a panel. However once you go into the details, there are quite a few very important other characteristics.

It didn't take very long before panels were encountered that required a number of external resources (such as enable GPIO, reset GPIO, power supply regulator and so forth) to be controlled in a very specific way in order to properly turn a panel on and off. The first attempt at a solution was a debacle. The idea was to introduce a generic binding to describe power sequences in device tree and attach these power sequences to devices. The curious reader can find the discussion in public mailing list archives, but the gist of it is that the implementation turned into a monster of a scripting language within device tree that nobody wanted to have in the end.

Once you decide that the power sequences are implied by the compatible string this problem solves itself because you can simply write a driver that binds to the compatible string and provides simple C code to request the resources and control them in exactly the right way to match the sequences as specified in the datasheet.

Complex display panels


The matter becomes even more important when you start using complex display panels such as those on a DSI bus. It's fairly common for these display panels to require register level programming to get into a functional state. There are standards (such as DCS) that try to make this somewhat uniform, but the reality is that most panels require vendor- and model-specific register programming before they start displaying anything.

If you wanted to support such panels in a fully generic device tree binding you'd need to add support for DSI register programming to your power sequencing script language. You don't want to go there.

Dumb display panels


Many panels, fortunately, are fairly dumb and require a small set of resources with relatively simple power on and power off sequences. The Linux kernel implements a simple-panel driver that can support a large number of these simple panels with a single device tree binding.

Bloat versus duplication


People were, and still are, concerned about the kernel becoming bloated by the large number of video timings within the kernel. I don't think that's turned out to be true. The simple-panel driver supports 46 panels (in v4.6-rc4) and the resulting loadable kernel module is ~37 KiB with a .rodata section of ~20 KiB. In my opinion that's not very much. If people cared enough they could always go and add Kconfig symbols for all the simple panels in order to allow the size to be reduced.

While it is certainly true that this data wouldn't be shipped with every kernel image if the data was contained within device tree, doing so comes at its own cost: duplication. As argued above, the compatible string implies the video timings for a display panel. It follows that specifying the video timings in device tree is duplicating information. Even more so if you happen to have two boards which use the same display panel.

With the current model it is fairly trivial to add board support. Provided that your panel is already supported it is a simple matter of adding the node with the given compatible string and hooking up the board-specific resources (GPIOs, regulators, ...). If, however, the video timings, physical dimensions and power sequences had to be defined in device tree, everybody would have to tediously copy/paste all that data from existing boards, or resort to reading the datasheet in order to find out the information.


1 Ironically the EDID is where, among other things, the panel's video timings are stored. If an EDID is found, the DRM panel framework will of course use those timings and fall back to built-ins otherwise.