Skip to content

Linux AMDGPU

EDID Override

The amdgpu driver does not provide a way to set the Output Colur Format such as Full RGB, Limited RGB, etc.

My monitor, an LG 4K 27 inch, indicates in its EDID that it supports YCbCr444 and the amdgpu driver would automatically pick and use that. The result was an image which had overly-bright greys, even if the black level was set to Low in the monitor OSD (with it set to High, it was even brighter).

The solution below walks you through the steps on Pop!_OS 22.04. It has been compiled from various sources, referenced inline as appropriate.

Note: the following assumes that the monitors are always connected to the same outputs on the graphics card.

Methodology

EDID is stored on the monitor, and tells connected devices (in this case, the graphics card and its driver) which resolutions and output modes are supported.

The process here is to take the EDID from the monitor, make some changes to it to remove support for the YCbCr444 mode that we don't want, and then tell the OS/driver to load the modified version at boot instead of the one provided by the monitor.

Install wxEDID

The EDID are stored in binary, and as such it is easiest to use a tool which can load and parse the EDID, make the changes, and then save.

wxEDID can be installed on Pop!_OS 22.04 via the Pop!_Shop.

Export the EDID

First, identify which monitor you want to override. The EDID from the monitors are available at /sys/devices/ and the easiest way to locate them is using the find command, like this:

$ find /sys/devices/ -name edid

On my system, this produces the following output:

/sys/devices/pci0000:00/0000:00:03.1/0000:09:00.0/0000:0a:00.0/0000:0b:00.0/drm/card1/card1-HDMI-A-1/edid
/sys/devices/pci0000:00/0000:00:03.1/0000:09:00.0/0000:0a:00.0/0000:0b:00.0/drm/card1/card1-DP-2/edid
/sys/devices/pci0000:00/0000:00:03.1/0000:09:00.0/0000:0a:00.0/0000:0b:00.0/drm/card1/card1-Writeback-1/edid
/sys/devices/pci0000:00/0000:00:03.1/0000:09:00.0/0000:0a:00.0/0000:0b:00.0/drm/card1/card1-HDMI-A-2/edid
/sys/devices/pci0000:00/0000:00:03.1/0000:09:00.0/0000:0a:00.0/0000:0b:00.0/drm/card1/card1-DP-1/edid

Note the names after the /drm/cardn part, e.g. card1-HDMI-A-1, card1-HDMI-A-2, card1-DP-1, card1-DP-2.

Create a new directory in your home directory:

$ mkdir ~/edid

Copy the relevant EDID image to the ~/edid directory. For example, my 27 inch monitor is connected to card1-HDMI-A-1, so the command is:

$ cp -n "/sys/devices/pci0000:00/0000:00:03.1/0000:09:00.0/0000:0a:00.0/0000:0b:00.0/drm/card1/card1-HDMI-A-1/edid" ~/edid/edid27.bin

The name of the image does not matter, but it might be useful to name it after your monitor for easier reference.

If you're unsure which output is the correct monitor, look at the directories under /sys/kernel/debug/dri/1. From there, you can interact with the outputs/monitors.

For example, this command will trigger a HDMI hotplug event on HDMI-A-1. This should cause the monitor to briefly blank out if it's the correct one:

$ echo 1 > /sys/kernel/debug/dri/1/HDMI-A-1/trigger_hotplug

Edit the image in wxEDID

credit to TingPing's blog [https://blog.tingping.se/2018/12/01/amdgpu-fullrgb.html] for these steps.

Open the file in wxEDID and edit it as follows to disable YCbCr support:

SPF: Supported features -> change value of vsig_format to 0b00 CHD: CEA-861 header -> change the value of YCbCr420 and YCbCr444 to 0 VSD: Vendor Specific Data Block -> change the value of DC_Y444 to 0

Use the modified EDID file:

Option -> Recalc Checksum

File -> Save EDID Binary (to ~/modified_edid.bin for example)

Test the new EDID image

You can load the EDID with the system running by setting edid_override on the relevant output, and then calling trigger_hotplug.

$ cat ~/edid/edid27_rgb.bin > /sys/kernel/debug/dri/1/HDMI-A-1/edid_override;echo 1 > /sys/kernel/debug/dri/1/HDMI-A-1/trigger_hotplug

Copy to the firmware directory

$ sudo install -Dm644 ~/edid/edid26.bin /usr/bin/firmware/edid/edid27_rgb.bin

Add to Linux boot command line

In Pop!_OS 22.04 you should use the kernelstub utility to add command line entries, rather than by the more traditional approach of editing config files and update-grub.

Check the current configuration:

$ sudo kernelstub -p
kernelstub.Config    : INFO     Looking for configuration...
kernelstub           : INFO     System information: 

    OS:..................Pop!_OS 22.04
    Root partition:....../dev/sdb3
    Root FS UUID:........8959c7c6-6f47-469b-8dba-753dc55b168f
    ESP Path:............/boot/efi
    ESP Partition:......./dev/sdb1
    ESP Partition #:.....1
    NVRAM entry #:.......-1
    Boot Variable #:.....0000
    Kernel Boot Options:.quiet loglevel=0 systemd.show_status=false splash drm.edid_firmware=HDMI-A-1:edid/edid27_rgb.bin
    Kernel Image Path:.../boot/vmlinuz-6.8.0-76060800daily20240311-generic
    Initrd Image Path:.../boot/initrd.img-6.8.0-76060800daily20240311-generic
    Force-overwrite:.....False

kernelstub           : INFO     Configuration details: 

   ESP Location:................../boot/efi
   Management Mode:...............True
   Install Loader configuration:..True
   Configuration version:.........3

Set a new Kernel Boot Options entry. There are two options - you can either append a new entry using kernelstub -a, or alternatively specify the complete line of options. This could be be useful if you have made errors which you wish to correct in one shot.

To specify a new option addition:

$ sudo kernelstub -a "drm.edid_firmware=HDMI-A-1:edid/edid27_rgb.bin"

To specify a complete options line:

$ sudo kernelstub -o "quiet loglevel=0 systemd.show_status=false splash drm.edid_firmware=HDMI-A-1:edid/edid27_rgb.bin"

Note that the structure of the added option is drm.edid_firmware= followed by the output name (in this case, HDMI-A-1), followed by a colon : and then the path to the overriding EDID file relative path.

Add the EDID to initramfs

credit to u/mgedmin on Reddit https://www.reddit.com/r/Ubuntu/comments/1afvgh1/comment/koeugjc/.

The boot process of Pop!_OS uses "early KMS" and so the EDID must be added to the initramfs image.

Add a new file /etc/initramfs-tools/hooks/edid with the following contents to the file:

Important: this is the file contents for /etc/initramfs-tools/hooks/edid - DO NOT execute in a terminal!

mkdir -p ${DESTDIR}/lib/firmware/edid
cp /lib/firmware/edid/*.bin ${DESTDIR}/lib/firmware/edid/

Note that we have used the edid subdirectory consistently both in /lib/firmware/edid and the lib/firmware/edid in initramfs.

Make the hook executable:

$ sudo chmod +x /etc/initramfs-tools/hooks/edid

Update initramfs for the current kernel:

$ sudo update-initramfs -u -k $(uname -r)

Reboot

Reboot and you should see that the new EDID has been applied.

If this is not the case, check that you have used the correct graphics card output (e.g. HDMI-A-1) and also check the output from sudo dmesg to check for any errors.

For example, if the following appears, it could indicate that the image has not been correctly copied to initramfs.

[   10.272584] kernel: amdgpu 0000:0b:00.0: Direct firmware load for edid/edid27_rgb.bin failed with error -2
[   10.272587] kernel: amdgpu 0000:0b:00.0: [drm] *ERROR* [CONNECTOR:106:HDMI-A-1] Requesting EDID firmware "edid/edid27_rgb.bin" failed (err=-2)