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.