📜 ⬆️ ⬇️

Patch EDID TV from under Linux

My TV ("old" model LG 32LG5000) never worked in Linux. Every time I connected it via the HDMI port, the kernel reported an error to me:
kernel: [ 869.677850] [drm:drm_edid_block_valid] *ERROR* EDI has major version 2, instead of 1 

and completely ignored him.

This problem did not bother me too much, because I did not use it often, and the VGA port worked, albeit with a maximum resolution of 1360 × 768. However, today, when I decided to watch the movie, the quality of the output via VGA was incredibly bad, and I decided to end it.

Analyzing EDID


For those who do not know, EDID is a small amount of data containing information about the capabilities of the monitor, mainly resolutions and timings, which it supports. The error message is interesting because it says about EDID 2.0, which (almost) never existed. This is what Wikipedia tells us:
The EDID structure has versions from v1.0 to v1.4, 128 bytes in size, each subsequent version is backward compatible with the previous one. The EDID v2.0 structure was 256 bytes in size, but was later declared obsolete and replaced by v1.3.

It seems that EDID 2.0 was declared obsolete somewhere in 2000. It is rather funny that 2008 TV used this particular version.
')
After a brief googling, I found EDID error messages in this model, and that in fact it is EDID 1.3. I tried to update the firmware to the latest version, but this did not help. So, I had two choices:
  1. Patch the kernel and remove the version check. This is ugly, and at least you will have to reassemble the drm- module with each kernel update.
  2. Patch EDID and force either the kernel or TV to use it.

I craved adventure, so I chose the latter. Load the i2c-dev module ; get the direct i2c access to the EDID; use get-edid :
 # 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. 

We got the EDID from i2c bus 3. Now let's see what is there.
 # parse-edid < /tmp/edid.bin Checksum Correct Section "Monitor" Identifier "32LG5000" ModelName "32LG5000" VendorName "GSM" # Monitor Manufactured week 9 of 2008 # EDID version 2.0 # Digital Display DisplaySize 700 390 Gamma 2.20 Option "DPMS" "true" Horizsync 28-67 VertRefresh 50-75 # Maximum pixel clock is 150MHz #Not giving standard mode: 640x480, 60Hz #Not giving standard mode: 800x600, 60Hz #Not giving standard mode: 1024x768, 60Hz #Not giving standard mode: 1920x1080, 60Hz #Extension block found. Parsing... Modeline "Mode 16" +hsync +vsync Modeline "Mode 0" -hsync -vsync Modeline "Mode 1" -hsync +vsync Modeline "Mode 2" 27.027 720 736 798 858 480 489 495 525 -hsync -vsync Modeline "Mode 3" 27.000 720 732 796 864 576 581 586 625 -hsync -vsync Modeline "Mode 4" 25.200 640 656 752 800 480 490 492 525 -hsync -vsync Modeline "Mode 5" 27.027 720 736 798 858 480 489 495 525 -hsync -vsync Modeline "Mode 6" 27.000 720 732 796 864 576 581 586 625 -hsync -vsync Modeline "Mode 7" 74.250 1280 1720 1760 1980 720 725 730 750 +hsync +vsync Modeline "Mode 8" 74.250 1280 1390 1420 1650 720 725 730 750 +hsync +vsync Modeline "Mode 9" 74.250 1920 2448 2492 2640 1080 1082 1089 1125 +hsync +vsync interlace Modeline "Mode 10" 74.250 1920 2008 2052 2200 1080 1082 1087 1125 +hsync +vsync interlace Modeline "Mode 11" 74.250 1920 2448 2492 2640 1080 1084 1089 1125 +hsync +vsync Modeline "Mode 12" 148.500 1920 2448 2492 2640 1080 1084 1089 1125 +hsync +vsync Modeline "Mode 13" 74.250 1920 2558 2602 2750 1080 1084 1089 1125 +hsync +vsync Modeline "Mode 14" 74.250 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync Modeline "Mode 15" 148.500 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync Modeline "Mode 17" +hsync +vsync Modeline "Mode 18" +hsync +vsync interlace Modeline "Mode 19" -hsync -vsync Option "PreferredMode" "Mode 16" EndSection 

Make sure this is the correct EDID, by model ID. We see EDID version 2.0, which is reported by parse-edid, to which the core itself actually swears. We can also see that parse-edid has found a block with the timings and permissions that TV supports. Now take a look at the RAW data:
 # hd /tmp/edid.bin 00000000 00 ff ff ff ff ff ff 00 1e 6d f0 75 01 01 01 01 |.........mu...| 00000010 09 12 02 00 80 46 27 78 ea d9 b0 a3 57 49 9c 25 |.....F'x....WI.%| 00000020 11 49 4b a5 6e 00 31 40 45 40 61 40 d1 c0 01 01 |.IK.n.1@E@a@....| 00000030 01 01 01 01 01 01 26 36 80 a0 70 38 1f 40 50 20 |......&6..p8.@P | 00000040 85 00 bc 86 21 00 00 18 1b 21 50 a0 51 00 1e 30 |....!....!PQ.0| 00000050 48 88 35 00 bc 86 21 00 00 1c 00 00 00 fc 00 33 |H.5...!........3| 00000060 32 4c 47 35 30 30 30 0a 20 20 20 20 00 00 00 fd |2LG5000. ....| 00000070 00 32 4b 1c 43 0f 00 0a 20 20 20 20 20 20 01 f9 |.2K.C... ..| 00000080 02 03 21 f1 4e 02 11 01 03 12 13 04 14 05 21 1f |..!.N.........!.| 00000090 20 22 10 23 09 07 07 83 01 00 00 65 03 0c 00 30 | ".#.......e...0| 000000a0 00 01 1d 00 bc 52 d0 1e 20 b8 28 55 40 c4 8e 21 |.....R.. .(U@..!| 000000b0 00 00 1e 01 1d 00 72 51 d0 1e 20 6e 28 55 00 c4 |......rQ.. n(U..| 000000c0 8e 21 00 00 1e 01 1d 80 d0 72 1c 16 20 10 2c 25 |.!.......r.. .,%| 000000d0 80 c4 8e 21 00 00 9e 8c 0a d0 90 20 40 31 20 0c |...!....... @1 .| 000000e0 40 55 00 c4 8e 21 00 00 18 4e 1f 00 80 51 00 1e |@U...!...N...Q..| 000000f0 30 40 80 37 00 bc 88 21 00 00 18 00 00 00 00 ac |0@.7...!........| 00000100 

EDID consists of 2 sections, each 128 bytes in size (we remember that this is EDID 1.3, incorrectly named 2.0).
The first section is the main one, and the second is an additional, EIA / CEA-861 extension block , which contains information about permissions and timings. Using the article in Wikipedia, we understand that the bytes at offset 0x12 and 0x13 contain the EDID version (0x02 and 0x00 in our case), and the offset 0xf7f contains the checksum (0xf9).

EDID patches profitable


In theory, if we replace the values ​​at offset 0x12 and 0x13 by 0x01 and 0x03, respectively, and correct the checksum, we get the correct EDID. This can be easily done in the HEX editor; the checksum is set to 0x7f (the sum of all 128 bytes modulo 256 must be zero).
Try parsing the modified EDID:
 $ diff -u <(parse-edid </tmp/edid.bin) <(parse-edid </tmp/edid-fixed.bin) Checksum Correct Checksum Correct --- /proc/self/fd/11 2014-03-22 02:18:52.614474422 +0200 +++ /proc/self/fd/12 2014-03-22 02:18:52.614474422 +0200 @@ -3,7 +3,7 @@ ModelName "32LG5000" VendorName "GSM" # Monitor Manufactured week 9 of 2008 - # EDID version 2.0 + # EDID version 1.3 # Digital Display DisplaySize 700 390 Gamma 2.20 


Now that we have the right EDID, we need to somehow try to record it on the TV (and, it seems, there are people who did it). Debian has the i2c-tools package, which has i2cget utilities for reading and i2cset for writing to an I²C device. Recall that get-edid read from bus 3, and the EDID is located at 0x50, so let's try to read our bytes directly:
 # for byte in 0x12 0x13 0x7f; do i2cget -y 3 0x50 $byte; done 0x02 0x00 0xf9 

Happened! Despite the risk of shouting (and so useless) HDMI port, I decided to overwrite the bytes directly.
Attention! Repeat this action at your own peril and risk, and only if you understand the possible consequences. You were warned.

 # i2cset -y 3 0x50 0x12 0x01 # i2cset -y 3 0x50 0x13 0x03 # i2cset -y 3 0x50 0x7f 0xf7 

There are no mistakes. Check if it worked out:
 $ xrandr -q Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192 eDP1 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 294mm x 165mm 1920x1080 60.0*+ 59.9 40.0 1680x1050 60.0 59.9 1600x1024 60.2 1400x1050 60.0 1280x1024 60.0 1440x900 59.9 1280x960 60.0 1360x768 59.8 60.0 1152x864 60.0 1024x768 60.0 800x600 60.3 56.2 640x480 59.9 VGA1 disconnected (normal left inverted right x axis y axis) HDMI1 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 700mm x 390mm 1920x1080 60.0*+ 60.0 50.0 59.9 30.0 25.0 24.0 30.0 24.0 1920x1080i 60.1 50.0 60.0 1360x768 59.8 1280x768 60.4 1280x720 60.0 50.0 59.9 1024x768 75.1 70.1 60.0 832x624 74.6 800x600 75.0 60.3 720x576 50.0 720x480 60.0 59.9 640x480 75.0 60.0 59.9 59.9 720x400 70.1 DP1 disconnected (normal left inverted right x axis y axis) 

Aha I managed to set the resolution to 1080p via xrandr . It looks like the change is permanent, so you don’t have to rewrite the bytes every time you turn off the TV.

From the translator: on this TV matrix with a resolution of 1366 × 768, so it’s not quite clear where such a desire to expose 1920 × 1080 comes from, it will still go through the scaler.

Source: https://habr.com/ru/post/217583/


All Articles