Have a monitor with a broken EDID? Debian may have everything you need to fix it.
Flash a Display EDID with Debian
THIS PROCEDURE COMES WITHOUT ANY WARRANTY. YOU CAN SERIOUSLY DAMAGE YOUR COMPUTER, INCLUDING YOUR DRAM, AND RENDER YOUR COMPUTER UNBOOTABLE. PROCEED AT YOUR OWN RISK.
One day, I ran out of screen space and added a third monitor from storage to my primary workstation. It was an older-model ViewSonic V201b. The device was not my favorite screen, but it had a good resolution at 1600x1200.
The trouble started when I activated Intel's integrated, on-board graphics controller. I connected the digital output and made it the primary adapter in the BIOS. The screen remained dark. I switched monitors around and realized why: The EDID from the digital input was broken.
Aside from the BIOS problem, the kernel greeted me with this message on a different monitor:
*ERROR* DVI-I-2: probed a monitor but no|invalid EDID
A look inside the logs showed more detail:
radeon 0000:05:00.0: DVI-I-2: EDID is invalid:  BAD 00 ff ff ff ff ff ff 00 ff ff ff ff ff ff ff ff  BAD 1c 0f 01 03 0e 29 1f 78 2e 30 85 a6 56 4a 99 24  BAD 14 50 54 bf ef 80 a9 40 81 80 81 40 71 4f 01 01  BAD 01 01 01 01 01 01 48 3f 40 30 62 b0 32 40 40 c0  BAD 13 00 98 32 11 00 00 1e 00 00 00 ff 00 41 32 31  BAD 30 35 32 38 41 30 31 37 33 0a 00 00 00 fd 00 32  BAD 4b 1e 5c 11 00 0a 20 20 20 20 20 20 00 00 00 fc  BAD 00 56 50 32 30 31 62 0a 20 20 20 20 20 20 00 50
Thanks to Lisandro Damián Nicanor Pérez Meyer and Paul Wise for figuring out the initial diagnosis.
After some research, I realized that EDID issues are actually fairly common. The EEPROMs used to store the information are not always write-protected. Some people say hot-plugging the cables can cause corruption.
First off, let me mention that the Linux kernel has a great way to deal with the issue. It can load EDID information on a non-permanent basis like firmware via the kernel command line. In my case, I included the EDID file in the initrd and reconfigured my bootloader with:
It worked great! I simply used the EDID data from the analog input, even though monitors present slightly different EDID data on their analog and digital inputs. I am not sure why or when it matters.
The kernel procedure does not flash anything. The system merely pretends that it received the data from the monitor.
Going through these steps with the kernel is good for two reasons. Firs, it shows you if the EDID you are about to flash actually makes your monitor perform better. (Without EDID data, most systems offer only lower VESA resolutions.) Second, it will give you confidence that there is an acceptable backup solution in case you break the EEPROM, although I think that particular risk is small.
If you like the kernel solution and it works for you, please do not proceed further. Anything else could damage your hardware. Your computer could become completely unusable.
A permanent fix
As someone with electronics experience, I was hoping for a permanent fix. One person suggested a Bus Pirate, but the device costs about $30 USD.
I also looked into repurposing an old USB to serial dongle I had used for something similar in the past. Then I found this post. It turns out that my graphics card (and probably yours, too) had everything I needed to fix the problem for good.
All monitor connectors, such as VGA, DVI and HDMI, have dedicated pins that do nothing but read the EDID information from monitors. They use the I2C protocol. It was designed for serial communications between integrated circuits. All graphics cards can read this bus, and many can write to it.
The following procedure worked great with an AMD Radeon HD 8490 graphics card. I also read from the Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (rev 06), but did not try writing.
Before you begin, please back up the working EDID information for all your monitors. You may wish to backtrack your work later.
For example, I successfully overwrote the digital EDID for my ViewSonic monitor with the analog version, but it ended up not working. In retrospect, it was probably a cabling issue (more on that later) but I chose to restore the original digital version, which was surprisingly easy.
You can find all your working EDIDs with
find /sys -name edid
You can use cat to store each piece of information in a separate file. I inspected the files with parse-edid and wxedid and gave them meaningful names such as:
The EDID data includes device-identifying information like the serial number and the week of manufacture.
Please do not forget to switch your cables around to get the other inputs also. For each monitor that is fully functional you should have two EDID files—one for the analog and another for the digital input.
Get the broken EDID
The method above seems to work only for the EDID that were recognized as valid. For any others (and hopefully it is just one) we will use the eeprom driver:
modprobe i2c-dev modprobe eeprom
Now look at the output of this command (or at the contents of that folder):
ls -al /sys/bus/i2c/devices/*-0050/eeprom
The folder contains a bunch of devices and buses but we only care about those with a start offset of 0x50. The data is similar to the edid data above, but here you get the actual hardware contents. In my case, all monitors used 256 byte EEPROMS.
I think the offset of 0x50 is part of the EDID specification, but I am not sure.
Once again I used cat to save the data returned by each of the eeprom devices. Unlike the EDIDs, which can be of variable length, all data here was 256 bytes long (although all higher bytes were empty).
Use tools like parse-edid, hexdump or wxedid to figure out which eeprom corresponds to the broken EDID. (You may have to tell wxedid to ignore the checksum.) Make a copy of the broken file.
Also remember the number of the bus. You do not want to write to the wrong bus later.
Make or find a working EDID
An early version of the service manual for my monitor stated that both analog and digital EDIDs were identical. Initially, simply programmed the working analog data into the broken digital input. Still, the monitor was not recognized on reboot (although I now think it was a cabling issue). That is how I ended up patching the digital file.
I opened up two instances of wxedid. One was for the working and another for the broken EDID, respectively. (Again, you may have to tell the program to ignore the checksum on the broken file.) I then adjusted a few parts of the broken digital data to look more like the working analog copy.
In my case, it was enough to copy two pairs of zeroes into the header (at the beginning and the end) which was otherwise full of 0xFFs. I also added the correct three-letter manufacturer code and fixed the serial number, which looked like a maximum unsigned long (again, probably all 0xFFs). I looked around some more but decided to stop there for now.
When I asked wxedid to compute the checksum—hey presto—it matched the existing record. The data I added probably restored the EDID to what it was once. I used wxedid to save it as a *.bin file. The length was 128 bytes long, which was what I expected.
For a manual inspection, you can also save the data as a hexadecimal text file.
If cannot reconstruct a working version from the broken EDID, you could try to find a matching firmware here.
Some double checking
The eeprom driver is incompatible with the direct I2C access we will use next. Please unload the module with
modproble -r eeprom
Then make sure we have the I2C consumer-grade tools:
apt install i2c-tools
Now we can have some fun with the EEPROMS. You can use this command to print a hex dump of the broken EEPROM:
i2cdump [insert bus number from above] 0x50
You can even do this for the working ones, to make sure you got your buses straight. Please examine and account for all the buses (monitors), and especially also for those you do not wish to overwrite.
Some of the hexdumps can look a little different from one to another. In my case, some were on a byte basis, while another used two-byte words. Just make sure you are looking at the same thing. Again, the broken EDID should be in the bus number you memorized above.
You can also use the following commands to snoop around, but I did either not need them or found the output confusing:
i2cdetect [bus number] -- showed which byte offsets were active i2cdetect -l -- showed a lot of buses and was confusing
At this point, you probably want to have lunch or take a walk and come back to the computer later. There should be no hurry. Do no proceed unless you feel comfortable that you are in the right place, and on the right bus.
Time to write
Writing to EEPROMs is a very dangerous operation. You can literally destroy your computer. You just have to write to the wrong place, or perhaps write too much data. There is particular risk with your DRAM chips.
Serious EEPROM programmers should use other software options instead. The i2c-tools maintainers only ship a version that changes a single byte, but it is enough for us.
With this creative one-liner, we can create a script that will flash our data byte by byte, while allowing for electrical recovery in between. Make sure you change the string BUS to your bus number.
xxd -g 1 -c 1 EDID.bin | sed 's/......\(..\):\ \(..\).*/i2cset\ -y\ BUS\ 0x50\ 0x\1 0x\2\nsleep\ 0.1/g' > flash.sh
Do not get confused here. Double check with i2cdump to make absolutely sure you are writing to the right bus.
We can now examine the script to see if it really does what we expect. Without any loops, a caveman can probably figure it out. It writes bunch of single bytes with commands like this:
i2cset -y BUS 0x50 0x00 VALUE sleep 0.1 i2cset -y BUS 0x50 0x01 VALUE sleep 0.1 i2cset -y BUS 0x50 0x02 VALUE sleep 0.1 [...]
A data block with 128 bytes will end at offset 0x7F. The last value should be the EDID checksum. You might want to check both those items.
Make the file executable with:
chmod +x flash.sh
Check the bus number is the batch file one more time. Now you can write the data with
This will take a few seconds. If your shell supports it, you could add set -x at the top of the script. That way, you might see the commands as they are executed, but it is not necessary (and I did not try it).
Finally, please verify with i2cdump that the EEPROM contains the correct data now. Reboot to see if your BIOS and the Linux kernel agree with your assessment.
It is possible that this technique works only with some graphics cards (or drivers). There was some mention of it on the web, but those post did not relate directly to the procedure presented here.
In my case, I encountered a vexing problem. Even though the data in the EEPROM was clearly correct, neither the BIOS nor the kernel accepted the first EDID during reboots (and dmesg showed it was defective).
It was a cabling problem that disappeared when I rearranged the affected video cable in the back of the computer to run perpendicular to a power cord, rather than parallel to it.
That video cable was thinner and somewhat fancy compared to the others. It probably had insufficient shielding. I plan to replace it when I come across another one.
All credit for the procedure described herein goes to the user TEN who wrote the post that explained it all. Thank you very much!
These posts describe a 25-Cent Adapter that uses the dedicated pins in video cables in very similar way to address I2C devices, but they are not monitors. I did not rely on these posts in any manner, but some information may be interesting for related endeavors, particularly the pin outs for the various cables.