Disclaimer: Try the following at your own risk, it may brick your TV/monitor

My TV set (an "old" LG 32LG5000 model) never played well with Linux. Whenever I
connected to it via an HDMI port, the kernel would complain:

kernel: [ 869.677850] [drm:drm_edid_block_valid] *ERROR* EDI has major version 2, instead of 1

and then would completely ignore the TV.

Because I didn't use it all that much anyway (and the VGA still worked,
although at 1360x768), I hadn't really bothered to find out what was wrong.
Today however, I wanted to watch a movie and the laptop's VGA output quality
really sucked, so I decided to have a look and see if I could get things to
work.

Analyzing the EDID

For those unfamiliar with the terms, the EDID is a small piece of data that
encodes a monitor's capabilities, most notably the resolutions and timings it
supports, allowing zero-configuration use of monitors. The above error is
particularly interesting, in that there (almost) never was a version 2.0 EDID:
according to Wikipedia,

EDID structure versions range from v1.0 to v1.4; all these define
upwards-compatible 128-byte structures. EDID structure v2.0 defined a new
256-byte structure, but subsequently has been deprecated and replaced by v1.3.

It seems that EDID 2.0 was deprecated around 2000, and it's funny that a TV set
manufactured in 2008 reports this version.

After googling a bit, I found some sporadic references that this model was
erroneously labeled as having a version 2.0 EDID, while in fact its EDID was
1.3. I tried a firmware update to the latest version, but it didn't fix the
issue, so at this point I had 2 options:

Patch the kernel and remove the major version check. This was ugly, plus I
would have to compile at least the drm module every time I upgraded my
kernel.

Patch the EDID and try to get either the TV or the kernel to use it.

Feeling a bit adventurous, I opted for the latter. Loading the i2c-dev
module gives us access to the raw EDID data, using get-edid (part of the
read-edid package in Debian):

# get-edid > /tmp/edid.bin
This is read-edid version 3.0.1. Prepare for some fun.
Attempting to use i2c interface
No EDID on bus 0
No EDID on bus 1
No EDID on bus 2
No EDID on bus 4
No EDID on bus 5
No EDID on bus 7
2 potential busses found: 3 6
Will scan through until the first EDID is found.
Pass a bus number as an option to this program to go only for that one.
256-byte EDID successfully retrieved from i2c bus 3
Looks like i2c was successful. Have a good day.

Note that we got the EDID from i2c bus 3. Let's see now what's in there:

The model name confirms we have the right EDID. Note the # EDID version 2.0
string that parse-edid reports, which agrees with what the kernel complains
about. Also note that parse-edid found an extension block as well, one
specifying the timings and resolutions supported by the TV. Let's have a look
at the raw data now:

The raw EDID data comprises two sections, 128 bytes each (remember, this is an
EDID 1.3 blob, incorrectly labeled as 2.0). The first section is the main one
and the second one is the extension, an EIA/CEA-861 extension block
containing the native resolutions and timings. Using the Wikipedia article as
a reference, we quickly find out that bytes 0x12 and 0x13 are the EDID
version (with values 0x02 and 0x00 in our case) and the checksum byte
0xf7 (with a value of 0xf9).

Hot-patching the EDID

In theory, if we replace the values of bytes 0x12 and 0x13 with
0x01 and 0x03 respectively and adjust the checksum, we should end up
with a fixed EDID. This can be trivially done using a hex editor, and we will
have to change the checksum byte's value from 0xf9 to 0xf7 (the sum of
all 128 bytes in the section modulo 256 must be 0).

Now that we have a fixed, valid EDID perhaps we can write it to the TV (it
turns out there are people who have succesfully done this). The i2c-tools
Debian package provides a handy pair of utilities, i2cget and i2cset
that can read and write bytes to an I²C device. Remember that get-edid
retrieved the EDID from bus 3 and it seems like the chip address for EDID is
always 0x50, so let's try to read the bytes in question directly: