Display configuration from U-Boot

Published on October 21, 2016

Archived Notice

This article has been archived and may contain broken links, photos and out-of-date information. If you have any questions, please Contact Us.

Starting with Linux kernel v3.14.x and above, the way to setup the display on our platforms has changed. This blog post will detail how to set the proper display configuration from U-Boot.This applies to all operating systems that use the Linux kernel (Ubuntu, Debian, Yocto, Buildroot, Android).

What was the problem?

At first, back in the 3.0.x days it was all handled from the kernel bootargs. It required the kernel to know of a display and to recognize the boot parameter and then apply the values. At that time, we were "detecting" the display setup depending on the touch screen controllers present on the I2C bus.

Then, when using the device trees starting with the 3.10.x kernels, we kept this approach of detecting the touch controllers but had to change it a little since the display timings were held in the device tree. So we decided to have a node for each display and then the bootscript would be in charge of deleting the nodes/displays not used.

As the number of supported displays increased, the above approach was not suitable anymore because:

  • The detection on touch controller wasn't flexible enough
    • Several displays are using the FT5x06 for instance
  • The number of display nodes inside the device tree was getting out of control
  • Each new display required a modification in U-Boot and in the device tree (Kernel)

For all those reasons we decided to change the display configuration for kernel 3.14.x and above.

So what has changed?

Since U-Boot can easily read/write/update nodes inside the device tree blob before booting the kernel, the idea is to have a generic display node in the device tree which U-Boot will populate with the proper values.You can see in our source tree that all our device trees contain:

So U-Boot is now is charged to setup those nodes which will configure your display(s) easily.Note that the touch controller detection is still present as a legacy mode, it means that if you don't provide any information, U-Boot will try to guess which display is connected, but there's now an easy way to override that setting.

How does it work?

First of all it requires a U-Boot >= v2015.07, at the time of this writing our latest version is v2016.03 but you can always grab the latest U-Boot from the link below:

So if your board contains an older version of U-Boot, please upgrade. You can follow the v2016.03 instructions.

Once you have a recent U-Boot, you can have a look at the supported display for your board by issuing:

=> fbpanel
         clock-frequency hactive vactive hback-porch hfront-porch vback-porch vfront-porch hsync-len vsync-len
hdmi: 1280x720M@60:m24x1,50:74161969,1280,720,220,110,20,5,40,5
                74161969    1280     720         220          110          20            5        40         5
hdmi: 1920x1080M@60:m24x1,50:148500148,1920,1080,148,88,36,4,44,5
               148500148    1920    1080         148           88          36            4        44         5
...

Since the list is actually pretty long and not always easy to read, you can also filter by type of display (hdmi, lcd or lvds)

=> fbpanel lcd
         clock-frequency hactive vactive hback-porch hfront-porch vback-porch vfront-porch hsync-len vsync-len
lcd: fusion7:m18x2,10:33264586,800,480,96,24,31,11,136,3
                33264586     800     480          96           24          31           11       136         3
lcd: CLAA-WVGA:m18x2,48:27000027,800,480,40,60,10,10,20,10
                27000027     800     480          40           60          10           10        20        10
...
=> fbpanel lvds
         clock-frequency hactive vactive hback-porch hfront-porch vback-porch vfront-porch hsync-len vsync-len
lvds: hannstar7:18x2,38:71108582,1280,800,80,48,15,2,32,6
                71108582    1280     800          80           48          15            2        32         6
...

The above command just lists the available displays, when you want to set one, you need will to set the following variables:

  • fb_hdmi controls HDMI display selection
  • fb_lcd controls LCD display selection
  • fb_lvds controls LVDS display selection
  • fb_lvds2 controls LVDS2 display selection

Note that those variables are parsed by U-Boot at bootup, so when set one of those variables: remember to save the environment and reboot the board.Also, when a display isn't used, you need to set it to off. Here is an example on how to setup the HDMI to display at 1080P and LVDS display to be the Hannstar 10".

=> setenv fb_lvds hannstar
=> setenv fb_hdmi 1920x1080M@60
=> setenv fb_lcd off
=> saveenv
Saving Environment to SPI Flash...
SF: Detected SST25VF016B with page size 256 Bytes, erase size 4 KiB, total 2 MiB
Erasing SPI flash...Writing to SPI flash...done
=> reset

Once rebooted, you can have a look at the cmd_hdmi, cmd_lcd and cmd_lvds that U-Boot will have set

=> print cmd_hdmi
cmd_hdmi=fdt set fb_hdmi status okay;fdt set fb_hdmi mode_str 1920x1080M@60;
=> print cmd_lvds
cmd_lvds=fdt set fb_lvds status okay;fdt set fb_lvds interface_pix_fmt RGB666;fdt set ldb/lvds-channel@0 fsl,data-width ;fdt set ldb/lvds-channel@0 fsl,data-mapping spwg;fdt set t_lvds clock-frequency ;fdt set t_lvds hactive ;fdt set t_lvds vactive ;fdt set t_lvds hback-porch ;fdt set t_lvds hfront-porch ;fdt set t_lvds vback-porch ;fdt set t_lvds vfront-porch ;fdt set t_lvds hsync-len ;fdt set t_lvds vsync-len ;
=> print cmd_lcd
cmd_lcd=fdt set fb_lcd status disabled

Do not try to set those cmd_* variables yourself, they will be overwritten by U-Boot at bootup anyway.That's it, you should now be able to list, select and setup the displays the way you want.

Can I use yet another display easily?

It depends on the type of display:

  • LVDS: yes, since all the timings are inside the device tree node you can change them.

Here is an example for our latest 7" 1280x800 display, although only the latest U-Boot binary lists it, you can have it running by entering:

=> setenv fb_lvds tm070jdhg30:24:68152388,1280,800,5,63,2,39,1,1
=> saveenv

Note that it goes like this:

setenv fb_xxx mode_str:connection-type:clk-frequency,hactive,vactive,hback-porch,hfront-porch,vback-porch,vfront-porch,hsync-len,vsync-len

The connection-type is very important since it allows to specify:

  • The data mapping: default is SPWG, need to add "j" to switch to JEIDA
  • The split mode: for dual LVDS channels operations (for 1080P display for instance) need to add "s"
  • The data width: can be 18 or 24

For instance, here is a fb_lvds setup for a dual channel JEIDA LVDS display with 24-bit witdth:

=> setenv fb_lvds 1080P60:js24:148500148,1920,1080,148,88,36,4,44,5
  • LCD: yes for U-Boot display, no for the kernel

You can set the fb_lcd like it is done for LVDS above, however the timings will only be used to setup U-Boot, only the mode_str will be passed on to the kernel. This means that the kernel needs to know about the LCD beforehand.Here is an example for the ASIT500MA6F5D display:

=> setenv fb_lcd ASIT500MA6F5D:m24:32341861,800,480,88,40,32,13,48,3
=> saveenv

The above line will make the display work in U-Boot, however the kernel will require this change to work.

  • HDMI: yes (well more or less)

Same as the LCD setting, only the mode_str is passed on to the kernel. The difference is that it can work out of the box on the kernel side if you ask for a standard resolution and standard refresh rate.For instance, setting fb_hdmi to 1920x1080M@30 will work automatically since the kernel is smart enough to recognize a known resolution (1080P) with a standard refresh rate (30fps).As usual, let us know if you have question in comment section below.