LCD

Allwinner SoCs can output display signals to LCD panels.

For devices with LCD displays, the resolution and timing values can be found in the FEX file.

= Software =

Mainline U-Boot
Support for LCD displays is available in mainline U-boot, starting from release v2015.04.

FEX conversion rules
The timing definitions and values are slightly different from the FEX files. The following is a translation table.

Mainline Linux (simple-panel)
Conversion from LCD timing from u-boot configuration string to struct drm_display_mode in mainline kernel:

CONFIG_VIDEO_LCD_MODE="x:1024,y:768,depth:18,pclk_khz:100000,le:799,ri:260,up:15,lo:16,hs:1,vs:1,sync:3,vmode:0"

static const struct drm_display_mode unknown_display = { .clock = 100000,                   // pclk_khz (FEX: lcd_dclk_freq * 1000) .hdisplay = 1024,                  // x (FEX: lcd_x) .hsync_start = 1024 + 260,         // x + ri    .hsync_end = 1024 + 260 + 1,        // x + ri + hs    .htotal = 1024 + 260 + 1 + 799,     // x + ri + hs + le (FEX: lcd_ht) .vdisplay = 768,                   // y (FEX: lcd_y) .vsync_start = 768 + 16,           // y + lo    .vsync_end = 768 + 16 + 1,          // y + lo + vs    .vtotal = 768 + 16 + 1 + 15,        // y + lo + vs + up (FEX: lcd_vt / 2) .vrefresh = 60, // };

Example timing calculation from a INNOLUX EJ070NA-01J 7inch LVDS LCD datasheet (tested on DS167 board):



Corresponding u-boot configuration string:

CONFIG_VIDEO_LCD_MODE="x:1024,y:600,depth:18,pclk_khz:51000,le:22,ri:297,up:1,lo:33,hs:1,vs:1,sync:3,vmode:0"

Note: Some values above such as pclk, le, ri,lo...etc have margins as seen from above datasheet. You may get perfectly fine picture if you set ri=296 instead of ri=297 here. You might experience visual artifacts if your settings are beyond defined limits in the datasheet.

Script for automated conversion
The following ruby script takes fex file name as a command line parameter and produces the corresponding config line for u-boot according to the rules from the table above. Here is the ruby script (click on the 'Expand' link to see it):
 * 1) !/usr/bin/env ruby

if !ARGV[0] || !File.exists?(ARGV[0]) then abort "Usage: ruby #{__FILE__} [fex_file_name]\n" end

def parse_fex_section(filename, section) results = {} current_section = "" File.open(filename).each_line {|l| current_section = $1 if l =~ /^\[(.*?)\]/ next if current_section != section results[$1] = $2.strip if l =~ /^(\S+)\s*\=\s*(.*)/ results[$1] = $2.to_i if l =~ /^(\S+)\s*\=\s*(\d+)\s*$/ } return results end

def print_video_lcd_mode(lcd0_para, vt_div) x       = lcd0_para["lcd_x"] y       = lcd0_para["lcd_y"] depth   = { 0 => 24, 1 => 18 }[lcd0_para["lcd_frm"]] pclk_khz = lcd0_para["lcd_dclk_freq"] * 1000 hs      = [1, (lcd0_para["lcd_hv_hspw"] || lcd0_para["lcd_hspw"])].max vs      = [1, (lcd0_para["lcd_hv_vspw"] || lcd0_para["lcd_vspw"])].max le      = lcd0_para["lcd_hbp"] - hs  ri       = lcd0_para["lcd_ht"] - x - lcd0_para["lcd_hbp"] up      = lcd0_para["lcd_vbp"] - vs  lo       = lcd0_para["lcd_vt"] / vt_div - y - lcd0_para["lcd_vbp"]

abort "Unsupported 'lcd_frm' parameter" if !depth

printf("CONFIG_VIDEO_LCD_MODE=\"" +        "x:#{x},y:#{y},depth:#{depth},pclk_khz:#{pclk_khz}," +         "le:#{le},ri:#{ri},up:#{up},lo:#{lo},hs:#{hs},vs:#{vs}," +         "sync:3,vmode:0\"\n") end

lcd0_para = parse_fex_section(ARGV[0], "lcd0_para") abort "Not a valid 'lcd0_para' section" if lcd0_para["lcd_used"] != 1

printf("== for sun[457]i ==\n") print_video_lcd_mode(lcd0_para, 2)

printf("\n== for sun[68]i ==\n") print_video_lcd_mode(lcd0_para, 1)

Dithering test program
If in doubt regarding 18-bit vs. 24-bit depth, it is possible to compile and run on the device the following simple test program. It should show a smooth gradient picture. If the gradient looks blocky, then the depth most likely needs to be changed to 18. Here is the C source code (click on the 'Expand' link to see it): /* gcc -O2 -o fbgradient fbgradient.c */


 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 
 * 5) include 
 * 6) include 

int main {   int fd, x, y;    uint32_t *fb; struct fb_fix_screeninfo finfo; struct fb_var_screeninfo vinfo;

if ((fd = open("/dev/fb0", O_RDWR)) == -1) { printf("Can't open /dev/fb0\n"); return 1; }

if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo)) { printf("FBIOGET_FSCREENINFO failed\n"); return 1; }

if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) { printf("FBIOGET_VSCREENINFO failed\n"); return 1; }

if (vinfo.bits_per_pixel != 32) { printf("Only 32bpp framebuffer is supported\n"); return 1; }

fb = mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (fb == (void *)-1) { printf("mmap failed\n"); return 1; }

for (y = 0; y < vinfo.yres; y++) for (x = 0; x < vinfo.xres; x++) fb[y * vinfo.xres + x] = (255 * x / vinfo.xres) * 0x000100 + (255 * y / vinfo.yres) * 0x010001;

return 0; }

Bulk automatic conversion of all FEX files from the sunxi-boards repository
The results of automatic FEX files conversion are listed in the table below. The CONFIG_VIDEO_LCD_MODE line should be accurate and calculated exactly as described in the first section of this page. But the GPIO settings need careful human review. "Green" settings are likely to be usable as-is. "Yellow" most definitely need some tweaks. "Orange" are impossible to support with the current u-boot code.

CONFIG_VIDEO_LCD_PANEL_LVDS conversion rules - http://lists.denx.de/pipermail/u-boot/2015-January/200168.html

CONFIG_VIDEO_LCD_DCLK_PHASE conversion rules - http://lists.denx.de/pipermail/u-boot/2015-January/201751.html

= LCD panel =

LCD LVDS panels can be found on old notebook or desktop monitor.

Monitor with vertical size bigger 768 px and 24bit deep need u-boot patch to add lvds dual channel support.

= Downloadable LCD panel datasheets = Some of the LCD panel web shops are kind enough to conveniently provide freely downloadable collections of datasheets:
 * http://yslcd.com.tw/Docs.aspx
 * http://www.beyondinfinite.com/library.html