Index RSS

Fixing my EDID

When I switched jobs in May, I also switched from having a corporate notebook to using my own device for working (this is not as bad as it sounds; the real development work still takes place on corporate hardware, but I use my own device as an RDP and Microsoft Teams client).

I wanted to make a good first impression, so I needed a device that would just work. This meant that my beloved OpenBSD was not the system to go for - or at least I did not dare to try. But I also wanted to keep that system, so my Thinkpad X240 was out (it also lacks a webcam, but this could have fixed of course). My Thinkpad T430 often shows its age with its mechanical HDD and all, which only made it acceptable as a temporary solution. I therefore bought a refurbished Asus VivoBook, a sleek little machine that runs Debian and fulfills its role just fine.

But that required some additional work by me, which will be the topic of this post.

Unexpected problems in need of (re)solution

When my new notebook arrived, I was very enthusiastic - I always am when I get new toys, and I love to setup new Unix systems. I did not expect any issues since I bought the notebook from a shop specialized in Linux. It should just take an hour or so installing the needed browsers, Teams, Remmina, Emacs ... but when I connected my new device to my external monitor (a Samsung C24F396FHU), the only supported resolution was 640x480.

I went looking in dmesg and the Xorg log files and somewhere (sorry, I do not remember and do not want to reproduce my problem to find out) found that my monitors EDID was broken. EDID is a blob of data that the monitor uses to tell the operating system what kind of modes it supports. Without that information, the system cannot do much more than fall back to a very conservative setting that any relevant monitor will most likely support.

I was totally taken by surprise, since the very same monitor worked flawlessly both with the corporate notebook of my previous employer and with my Thinkpad T430. I found horror stories online about how the EDID on the monitor itself could get lost when the HDMI cable is attached or detached and something short circuits. Was my monitor a hopeless case?

A plan is born

To find out if my EDID was deleted, I tried multiple devices in my household: It worked with all of them, but not with my new notebook. That was proof that the EDID itself was correct, but it somehow could not be read by the VivoBook. Maybe the notebook has a subtle defect (it is refurbished after all)? Or maybe the Debian installation is missing something that all other systems do correctly? Who knows? I just wanted to have a working systems, no questions asked.

My online research lead me to an interesting Linux kernel parameter which allows overriding an EDID. A plan was born: I would extract the EDID from a working system and use the override to install it on my new device.

Their was a small detail that should delay executing my plan somewhat: My new system connected to the monitor via HDMI (like the corporate notebook did), but my other devices only had VGA or DisplayPort connectors. And the EDID is different between different kinds of connectors (at least between VGA, which is analogue, and HDMI, which is digital; I could not test DisplayPort since my monitor has no connector for that). Thankfully, the FreeBSD notebook my wife uses for her work does have an HDMI connector, so I borrowed that for a while.

Extracting the EDID

Unix systems using X11 make it easy to get a dump of the EDID. All you have to do is executing

xrandr --verbose

This outputs a lot of stuff, but it also should contain a section like

EDID:
	00ffffffffffff004c2d2c0d46415a42
	0e1e010380341d782a5295a556549d25
	0e5054bb8c00b30081c0810081809500
	a9c001010101023a801871382d40582c
	450009252100001e000000fd0032481e
	5111000a202020202020000000fc0043
	3234463339300a2020202020000000ff
	0048345a4e3331383137330a2020016e
	02031af14690041f1312032309070783
	01000066030c00100080011d00bc52d0
	1e20b828554009252100001e8c0ad090
	204031200c4055000925210000188c0a
	d08a20e02d10103e9600092521000018
	00000000000000000000000000000000
	00000000000000000000000000000000
	000000000000000000000000000000c9

This is my monitor's EDID as a hex dump. The next step is to transform this into a binary file. A text editor should be able to convert it easily, but writing a script for reading a hex dump and saving it as a binary is also no big issue.

Testing the override

With the EDID at hand, you know can test whether it would work for your monitor. To do so, simply pipe it into the edid_override "file" of your monitor. For me, this meant executing the following as root:

cat edid.bin >/sys/kernel/debug/dri/0/HDMI-A-1/edid_override

This at first did not change anything. My resolution still was restricted to 640x480 and xrandr did not offer any other resolutions. What gives?

Turns out that you have to disconnect and reconnect your monitor to see the override in action. And there it was: my desired 1980x1080 in all its glory!

Persisting the override

All that was left to do was to make sure that this happened automatically at boot time. The Linux kernel expects to find any EDID override files somewhere below /usr/lib/firmware, so I made a new subdirectory "edid" and copied my file into it, using "samsung.edid" as a file name.

I then added the necessary parameter to my kernel command line, by changing GRUB_CMDLINE_LINUX_DEFAULT in my /etc/default/grub:

GRUB_CMDLINE_LINUX_DEFAULT="quiet drm.edid_firmware=HDMI-A-1:edid/samsung.bin"

I updated grub, rebooted and ... nothing.

Turns out that the EDID file is read at a very early time during the boot process, which means that it has to be part of the initramfs.

I created a file /etc/initramfs-tools/hooks/samsung-edid with this contents:

 #!/bin/sh
PREREQ=""
prereqs()
{
    echo "$PREREQ"
}

case $1 in
prereqs)
    prereqs
    exit 0
    ;;
esac

. /usr/share/initramfs-tools/hook-functions

mkdir -p "${DESTDIR}/lib/firmware/edid"
cp -a /usr/lib/firmware/edid/samsung.bin "${DESTDIR}/lib/firmware/edid/samsung.bin"
exit 0

Then, I used mkinitramfs to rebuild the initramfs, rebooted and ... it worked!

Conclusion

I have been using this setup since the second half of May and never had any problem with it. I am very grateful that the Linux developers created this override, which allowed me to fix a problem that would have felt unsolvable otherwise.

Maybe I should start making backups of all my monitor's EDIDs, just in case? At least for this monitor (connected via HDMI), I will find a working EDID conserved in this blog post.