How to use the Atmel KMS/DRM LCD driver
Since
linux-3.18-at91, the recent Atmel SoCs have a new LCD driver that is based on the Linux KMS/DRM sub-system. As the old fbdev (framebuffer) subsystem is being deprecated and is certainly limited, we decided to move to a more future proof infrastructure.
This driver can be found in the
drivers/gpu/drm/atmel-hlcdc/ directory.
A good introduction to this driver by its author is the paper that Boris Brezillon wrote for Embedded Linux Conference Europe 2014:
The DRM/KMS subsystem from a newbie's point of view.
The atmel-hlcdc driver supports:
- base layer
- overlays (planes in DRM words)
- alpha channel blending of overlays
- color space conversion: RGB (different formats), YUV (different formats as well)
- panning
- rotation
- scaling / upsampling
- hardware cursor (when supported by hardware)
Modetest is the testing tool for a DRM driver. It uses native DRM commands.
modetest output
Example on a SAMA5D4-EK with an HDMI monitor connected.
root@sama5d4ek:~# ./modetest
trying to open device 'i915'...failed.
trying to open device 'radeon'...failed.
trying to open device 'nouveau'...failed.
trying to open device 'vmwgfx'...failed.
trying to open device 'omapdrm'...failed.
trying to open device 'exynos'...failed.
trying to open device 'tilcdc'...failed.
trying to open device 'msm'...failed.
trying to open device 'sti'...failed.
trying to open device 'tegra'...failed.
trying to open device 'imx-drm'...failed.
trying to open device 'atmel-hlcdc'...success.
Raw EDID:
ff ff ff ff ff ff 00 10 ac 42 f0 53 33 37 43 20
17 01 03 80 2f 1e 78 ea 23 c5 a5 57 4f 9e 26 0f
50 54 a5 4b 00 71 4f 81 80 b3 00 01 01 01 01 01
01 01 01 01 01 21 39 90 30 62 1a 27 40 68 b0 36
00 d9 28 11 00 00 1c 00 00 00 ff 00 34 34 46 47
59 33 38 38 43 37 33 53 0a 00 00 00 fc 00 44 45
4c 4c 20 50 32 32 31 33 0a 20 20 00 00 00 fd 00
38 4b 1e 53 10 00 0a 20 20 20 20 20 20 00 b9 0e
Encoders:
id crtc type possible crtcs possible clones
5 15 TMDS 0x00000001 0x00000000
7 0 LVDS 0x00000001 0x00000000
Connectors:
id encoder status type size (mm) modes encoders
6 5 connected HDMI-A 470x300 11 5
modes:
name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
1680x1050 60 1680 1784 1960 2240 1050 1053 1059 1089 flags: nhsync, pvsync; type: preferred, driver
1280x1024 75 1280 1296 1440 1688 1024 1025 1028 1066 flags: phsync, pvsync; type: driver
1280x1024 60 1280 1328 1440 1688 1024 1025 1028 1066 flags: phsync, pvsync; type: driver
1152x864 75 1152 1216 1344 1600 864 865 868 900 flags: phsync, pvsync; type: driver
1024x768 75 1024 1040 1136 1312 768 769 772 800 flags: phsync, pvsync; type: driver
1024x768 60 1024 1048 1184 1344 768 771 777 806 flags: nhsync, nvsync; type: driver
800x600 75 800 816 896 1056 600 601 604 625 flags: phsync, pvsync; type: driver
800x600 60 800 840 968 1056 600 601 605 628 flags: phsync, pvsync; type: driver
640x480 75 640 656 720 840 480 481 484 500 flags: nhsync, nvsync; type: driver
640x480 60 640 656 752 800 480 490 492 525 flags: nhsync, nvsync; type: driver
720x400 70 720 738 846 900 400 412 414 449 flags: nhsync, pvsync; type: driver
props:
1 EDID:
flags: immutable blob
blobs:
value:
00ffffffffffff0010ac42f053333743
20170103802f1e78ea23c5a5574f9e26
0f5054a54b00714f8180b30001010101
01010101010121399030621a274068b0
3600d9281100001c000000ff00343446
4759333838433733530a000000fc0044
454c4c2050323231330a2020000000fd
00384b1e5310000a20202020202000b9
2 DPMS:
flags: enum
enums: On=0 Standby=1 Suspend=2 Off=3
value: 0
8 0 connected LVDS 152x91 1 7
modes:
name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
800x480 60 800 801 865 929 480 481 504 526 flags: ; type:
props:
1 EDID:
flags: immutable blob
blobs:
value:
2 DPMS:
flags: enum
enums: On=0 Standby=1 Suspend=2 Off=3
value: 0
CRTCs:
id fb pos size
15 31 (0,0) (1680x1050)
1680x1050 60 1680 1784 1960 2240 1050 1053 1059 1089 flags: nhsync, pvsync; type: preferred, driver
props:
Planes:
id crtc fb CRTC x,y x,y gamma size possible crtcs
11 15 31 0,0 0,0 0 0x00000001
formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24
props:
4 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 1
10 rotation:
flags: bitmask
values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
value: 1
12 0 0 0,0 0,0 0 0x00000001
formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24
props:
4 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 0
9 alpha:
flags: range
values: 0 255
value: 255
10 rotation:
flags: bitmask
values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
value: 1
13 0 0 0,0 0,0 0 0x00000001
formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24
props:
4 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 0
9 alpha:
flags: range
values: 0 255
value: 255
10 rotation:
flags: bitmask
values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
value: 1
14 0 0 0,0 0,0 0 0x00000001
formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24 AYUV YUYV UYVY YVYU VYUY NV21 NV61 YU16 YU12
props:
4 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 0
9 alpha:
flags: range
values: 0 255
value: 255
10 rotation:
flags: bitmask
values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
value: 1
Frame buffers:
id size pitch
Some modetest commands
Here are some useful commands:
Display a basic test pattern with selected geometry (Don't press "enter" again until you're done) on the HDMI monitor:
modetest -M atmel-hlcdc -s 6@15:1024x768
Larger resolution if the HDMI connected monitor supports it:
modetest -M atmel-hlcdc -s 6@15:1680x1050
Now same test patern on the LCD PDA 7" display:
modetest -M atmel-hlcdc -s 8@15:800x480
or (if the HDMI cable is not connected):
modetest -M atmel-hlcdc -s 6@14:800x480
A test patern for background + a 300x200 overlay at 150 and 50 location:
modetest -M atmel-hlcdc -s 8@15:800x480 -P 15:300x200+150+50
Here is the output of this last command (HDMI screen unplugged):
root@sama5d4ek:~# modetest -M atmel-hlcdc -s 8@15:800x480 -P 15:300x200+150+50
setting mode 800x480@XR24 on connectors 8, crtc 15
testing 300x200@XR24 overlay plane 12
PDA 4" on sama5d2:
modetest -M atmel-hlcdc -s 6@13:480x272
The different features are supported and accessible in the Linux kernel. The constrain is to use the libdrm to access them and the proper call to our KMS/DRM driver named atmel-hlcdc. Note that these feature are not reachable using the fbdev emulation.
Here are some two more links detailing simple use cases:
Home of libdrm and the
modetest tool source code is actually part of libdrm.
Panel definitions are stored in C code and called from DT by the simple-panel.
So, you can store your panel definition here: drivers/gpu/drm/panel/panel-simple.c
Here is an example of the definition structure for the PDA 4.3" equipped with a Innolux at043tn24 LCD. The geometry is thus described like this:
static const struct drm_display_mode innolux_at043tn24_mode = {
.clock = 9000,
.hdisplay = 480,
.hsync_start = 480 + 2,
.hsync_end = 480 + 2 + 41,
.htotal = 480 + 2 + 41 + 2,
.vdisplay = 272,
.vsync_start = 272 + 2,
.vsync_end = 272 + 2 + 11,
.vtotal = 272 + 2 + 11 + 2,
.vrefresh = 60,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
};
static const struct panel_desc innolux_at043tn24 = {
.modes = &innolux_at043tn24_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 95,
.height = 54,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};
[..]
static const struct of_device_id platform_of_match[] = {
{
[..]
}, {
.compatible = "innolux,at043tn24",
.data = &innolux_at043tn24,
}, {
[..]
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, platform_of_match);
And here is the DT description that links to this panel:
panel: panel {
compatible = "innolux,at043tn24", "simple-panel";
backlight = <&backlight>;
power-supply = <&panel_reg>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
panel_input: endpoint@0 {
reg = <0>;
remote-endpoint = <&hlcdc_panel_output>;
};
};
};
For DRM drivers, you can use the old fbdev emulation. It is somehow a temporary workaround for software that still uses the fbdev interface. The preferred way of taking advantage of this driver is to use the DRM kernel API.
Anyway, if you still need this emulated fbdev interface, you can use the following instructions.
Choose supported modes
By default, the fbdev emulation on top of DRM driver is in 24 bits (RGB888).
For changing the the
fbdev emulation color mode to 16 bits (RGB565) on top of DRM driver, you
must choose the mode at boot time on the Linux command line.
So, you can add to the cmdline:
for PDA7" 16 bits color mode:
video=Unknown-1:800x480-16
or for PDA4.3" 16 bits color mode:
video=Unknown-1:480x272-16
For HDMI, here are some tricks as we have 2 different connectors:
For HDMI only: disable LCD:
video=HDMI-A-1:800x600-16 video=Unknown-1:d
For only screen and disabling HDMI output if it's connected:
video=HDMI-A-1:d video=Unknown-1:800x480-16
Set mode before using the fbdev
For fbdev emulation of DRM drivers, we
must set the mode the fb0 need to use.
Example for
/dev/fb0
and PDA7" LCD screen:
echo U:800x480p-0 > /sys/class/graphics/fb0/mode
or for
/dev/fb0
and PDA4.3" LCD screen:
echo U:480x272p-0 > /sys/class/graphics/fb0/mode
Note that you can check available modes in the file:
$ cat /sys/class/graphics/fb0/modes
U:480x272p-0
The easies way to do so is to run:
head -1 /sys/class/graphics/fb0/modes > /sys/class/graphics/fb0/mode
You can also use fbset:
fbset -g 800 480 800 480 16
You may also need to disable the blanking of the LCD:
echo 0 > /sys/class/graphics/fb0/blank