mirror of
https://github.com/akatrevorjay/edid-generator.git
synced 2026-01-15 23:50:28 +01:00
Simplify
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -35,4 +35,6 @@
|
||||
*.c
|
||||
*.bin
|
||||
*.ihex
|
||||
*.o.pre
|
||||
*.o.post
|
||||
|
||||
|
||||
@@ -39,6 +39,5 @@
|
||||
#define ESTABLISHED_TIMING2_BITS 0x08 /* Bit 3 -> 1024x768 @60 Hz */
|
||||
#define HSYNC_POL 0
|
||||
#define VSYNC_POL 0
|
||||
#define CRC 0x55
|
||||
|
||||
#include "edid.S"
|
||||
|
||||
@@ -39,6 +39,5 @@
|
||||
/* No ESTABLISHED_TIMINGx_BITS */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0xa0
|
||||
|
||||
#include "edid.S"
|
||||
|
||||
@@ -39,6 +39,5 @@
|
||||
/* No ESTABLISHED_TIMINGx_BITS */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0x9d
|
||||
|
||||
#include "edid.S"
|
||||
|
||||
@@ -39,6 +39,5 @@
|
||||
/* No ESTABLISHED_TIMINGx_BITS */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0x26
|
||||
|
||||
#include "edid.S"
|
||||
|
||||
@@ -39,6 +39,5 @@
|
||||
/* No ESTABLISHED_TIMINGx_BITS */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0x05
|
||||
|
||||
#include "edid.S"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* 3840x2160: 3840x2160 594.000 3840 4016 4104 4400 2160 2168 2178 2250 +hsync +vsync */
|
||||
/* 3840x2160: Modeline "3840x2160" 594.000 3840 4016 4104 4400 2160 2168 2178 2250 +hsync +vsync */
|
||||
#define HSYNC_POL 1
|
||||
#define CRC 0x9b
|
||||
#define VSYNC_POL 1
|
||||
#define YPULSE (63+10)
|
||||
#define XPULSE 88
|
||||
|
||||
@@ -36,6 +36,5 @@
|
||||
#define ESTABLISHED_TIMING1_BITS 0x01 /* Bit 0: 800x600 @ 60Hz */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0xc2
|
||||
|
||||
#include "edid.S"
|
||||
|
||||
58
HOWTO.txt
58
HOWTO.txt
@@ -1,58 +0,0 @@
|
||||
In the good old days when graphics parameters were configured explicitly
|
||||
in a file called xorg.conf, even broken hardware could be managed.
|
||||
|
||||
Today, with the advent of Kernel Mode Setting, a graphics board is
|
||||
either correctly working because all components follow the standards -
|
||||
or the computer is unusable, because the screen remains dark after
|
||||
booting or it displays the wrong area. Cases when this happens are:
|
||||
- The graphics board does not recognize the monitor.
|
||||
- The graphics board is unable to detect any EDID data.
|
||||
- The graphics board incorrectly forwards EDID data to the driver.
|
||||
- The monitor sends no or bogus EDID data.
|
||||
- A KVM sends its own EDID data instead of querying the connected monitor.
|
||||
Adding the kernel parameter "nomodeset" helps in most cases, but causes
|
||||
restrictions later on.
|
||||
|
||||
As a remedy for such situations, the kernel configuration item
|
||||
CONFIG_DRM_LOAD_EDID_FIRMWARE was introduced. It allows to provide an
|
||||
individually prepared or corrected EDID data set in the /lib/firmware
|
||||
directory from where it is loaded via the firmware interface. The code
|
||||
(see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for
|
||||
commonly used screen resolutions (800x600, 1024x768, 1280x1024, 1600x1200,
|
||||
1680x1050, 1920x1080) as binary blobs, but the kernel source tree does
|
||||
not contain code to create these data. In order to elucidate the origin
|
||||
of the built-in binary EDID blobs and to facilitate the creation of
|
||||
individual data for a specific misbehaving monitor, commented sources
|
||||
and a Makefile environment are given here.
|
||||
|
||||
To create binary EDID and C source code files from the existing data
|
||||
material, simply type "make".
|
||||
|
||||
If you want to create your own EDID file, copy the file 1024x768.S,
|
||||
replace the settings with your own data and add a new target to the
|
||||
Makefile. Please note that the EDID data structure expects the timing
|
||||
values in a different way as compared to the standard X11 format.
|
||||
|
||||
X11:
|
||||
HTimings: hdisp hsyncstart hsyncend htotal
|
||||
VTimings: vdisp vsyncstart vsyncend vtotal
|
||||
|
||||
EDID:
|
||||
#define XPIX hdisp
|
||||
#define XBLANK htotal-hdisp
|
||||
#define XOFFSET hsyncstart-hdisp
|
||||
#define XPULSE hsyncend-hsyncstart
|
||||
|
||||
#define YPIX vdisp
|
||||
#define YBLANK vtotal-vdisp
|
||||
#define YOFFSET (63+(vsyncstart-vdisp))
|
||||
#define YPULSE (63+(vsyncend-vsyncstart))
|
||||
|
||||
The CRC value in the last line
|
||||
#define CRC 0x55
|
||||
also is a bit tricky. After a first version of the binary data set is
|
||||
created, it must be checked with the "edid-decode" utility which will
|
||||
most probably complain about a wrong CRC. Fortunately, the utility also
|
||||
displays the correct CRC which must then be inserted into the source
|
||||
file. After the make procedure is repeated, the EDID data set is ready
|
||||
to be used.
|
||||
22
Makefile
22
Makefile
@@ -10,22 +10,28 @@ CODE := $(patsubst %.S, %.c, $(SOURCES))
|
||||
all: $(BIN) $(IHEX) $(CODE)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.bin.ihex *.bin *.c
|
||||
rm -f *.o *.crc *.bin *.bin.ihex *.c
|
||||
|
||||
%.o: %.S
|
||||
cc -c $^
|
||||
cc -c -DCRC="0x00" -o $@ $^
|
||||
|
||||
%.bin: %.o
|
||||
%.bin.nocrc: %.o
|
||||
objcopy -Obinary $^ $@
|
||||
|
||||
%.bin.ihex: %.o
|
||||
%.crc: %.bin.nocrc
|
||||
cat $^ | edid-decode \
|
||||
| sed -ne 's/^Checksum: 0x\w\+ (should be \(0x\w\+\))$$/\1/p' >$@
|
||||
|
||||
%.p: %.crc %.S
|
||||
cc -c -DCRC="$$(cat $*.crc)" -o $@ $*.S
|
||||
|
||||
%.bin: %.p
|
||||
objcopy -Obinary $^ $@
|
||||
|
||||
%.bin.ihex: %.p
|
||||
objcopy -Oihex $^ $@
|
||||
dos2unix $@ 2>/dev/null
|
||||
|
||||
%.c: %.bin
|
||||
@echo "{" >$@; hexdump -f hex $^ >>$@; echo "};" >>$@
|
||||
|
||||
%.crc: %.bin
|
||||
./compute-crc $^ >$@
|
||||
echo $(MAKE) $^
|
||||
|
||||
|
||||
65
README.md
65
README.md
@@ -1,2 +1,65 @@
|
||||
# edid-generator
|
||||
edid-generator
|
||||
==============
|
||||
|
||||
Hackerswork to generate an EDID binary file from given Xorg Modelines
|
||||
|
||||
An extension of the awesome work provided in the Linux kernel documentation (in `docs/EDID`).
|
||||
|
||||
Simplifies the process greatly by allowing you to use a standard modeline as well as automatically calculating the CRC
|
||||
and applying it to the resulting image.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
```
|
||||
sudo apt install zsh edid-decode automake
|
||||
```
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
If you don't have a `<mode>.S` prepared yet, generate one using a file containing Xorg Modelines. Lines that do not
|
||||
contain modelines are ignored, so you can just read right from `xorg.conf`.
|
||||
|
||||
```s
|
||||
./modeline2edid /etc/X11/xorg.conf
|
||||
```
|
||||
|
||||
You can also just read from `stdin` the way you'd expect:
|
||||
|
||||
```s
|
||||
./modeline2edid
|
||||
# or explicitly:
|
||||
./modeline2edid -
|
||||
```
|
||||
|
||||
After this creates your `<name>.S` files for each modeline it encounters, simply `make`:
|
||||
|
||||
```sh
|
||||
make
|
||||
```
|
||||
|
||||
The end result, providing all goes well, is a glorious EDID bin image for each mode you gave to it. A `<name>.S` file
|
||||
is templated, and then `make` is invoked to compile it into `<name>.bin`. It's actually compiled twice; once with an
|
||||
invalid CRC in order to generate said CRC to enter it into the template, after which we recompile, hence glorious bins.
|
||||
|
||||
NOTE: If you use a ratio other than 16:9, you'll need to specify it at the end of the modeline.as `ratio=4:3`.
|
||||
Ratios are hard defined in `edid.S`, so if you are trying to do something non-standard you'll need to add it.
|
||||
|
||||
Why?
|
||||
----
|
||||
|
||||
Many monitors and TVs (both high and low end) provide invalid EDID data. After dealing with this for years, I wanted to
|
||||
automate this process.
|
||||
|
||||
The final straw was when I bought a Sceptre 4K tv for ~$225 and ran into a long series of hurdles to get it to operate
|
||||
as expected at `3840x2160@60`. After doing this enough times, I had to automate it or I was going to go crazy.
|
||||
|
||||
I used this to quickly iterate while troubleshhooting, finally it's all working from KMS all the way down to X!
|
||||
|
||||
(Via `drm_kms_helper.edid_firmware=DP-1:edid/blah.bin``if you're interested. I'm using radeon + intel, with nvidia you
|
||||
have to specify it in `xorg.conf`/`xorg.conf.d` as they don't yet support KMS for the fb console yet; their beta
|
||||
drivers, 367 at the time of writing, only support using KMS for the xorg server.)
|
||||
|
||||
Sometimes I hate being such a perfectionist. Keep in mind this project was made in a couple hours, I certainly didn't
|
||||
attempt to polish it in the least ;)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
# A tad gross, but hey, it works.
|
||||
cat "$bin_fn" | edid-decode | sed -ne 's/^Checksum: 0x\w\+ (should be \(0x\w\+\))$/\1/p'
|
||||
173
modeline2edid
173
modeline2edid
@@ -1,148 +1,97 @@
|
||||
#!/bin/zsh
|
||||
setopt errexit errreturn
|
||||
setopt sourcetrace verbose
|
||||
setopt xtrace
|
||||
#setopt xtrace
|
||||
|
||||
template-S() {
|
||||
[[ ${(L)1} = mode(|line) ]] || return 1
|
||||
echo "-- Found naughty unicorn: $@"
|
||||
shift 1
|
||||
|
||||
munge-x11-modeline() {
|
||||
local args=() arg
|
||||
for arg in "$@"; do
|
||||
[[ "$arg" != \"*\" ]] || arg="${arg:1:-1}"
|
||||
args+=("$arg")
|
||||
done
|
||||
set -- ${(@)args}
|
||||
local name="${1//\"}"
|
||||
[[ -z "$name" ]] && echo "Could not parse modeline: $@" >&2 && return 1
|
||||
local fn="${name}.S"
|
||||
|
||||
[[ "$1" != "Modeline" ]] || shift 1
|
||||
name="$1" pixel_clock_mhz="$2"; shift 2
|
||||
hdisp="$1" hsyncstart="$2" hsyncend="$3" htotal="$4"; shift 4
|
||||
vdisp="$1" vsyncstart="$2" vsyncend="$3" vtotal="$4"; shift 4
|
||||
local -F pixel_clock_mhz=$2
|
||||
local -i pixel_clock_khz=$((pixel_clock_mhz * 1000))
|
||||
shift 2
|
||||
|
||||
fn="${name}.S"
|
||||
bin_fn="${name}.bin"
|
||||
local -i hdisp="$1" hsyncstart="$2" hsyncend="$3" htotal="$4"; shift 4
|
||||
local -i vdisp="$1" vsyncstart="$2" vsyncend="$3" vtotal="$4"; shift 4
|
||||
|
||||
hsync_polarity=0
|
||||
vsync_polarity=0
|
||||
ratio="16:9" # todo calc
|
||||
dpi="96"
|
||||
edid_version="1.3"
|
||||
vfreq_hz="60"
|
||||
crc="0x00"
|
||||
local -i hsync_polarity=0 vsync_polarity=0 dpi=96 vfreq_hz=60
|
||||
local edid_version="1.3" ratio="16:9" # TODO calc ratio
|
||||
|
||||
local arg
|
||||
for arg in "$@"; do
|
||||
case "${(L)arg}" in
|
||||
*hsync) [[ "${arg:1:1}" == "-" ]] || hsync_polarity=1 ;;
|
||||
*vsync) [[ "${arg:1:1}" == "-" ]] || vsync_polarity=1 ;;
|
||||
[-+]hsync) [[ "${arg:1:1}" == "-" ]] || hsync_polarity=1 ;;
|
||||
[-+]vsync) [[ "${arg:1:1}" == "-" ]] || vsync_polarity=1 ;;
|
||||
ratio=*|xy_ratio=*) ratio="${arg#*=}" ;;
|
||||
dpi=*) dpi="${arg#*=}" ;;
|
||||
edid_version=*) edid_version="${arg#*=}" ;;
|
||||
vfreq=*|vfreq_hz=*) vfreq_hz="${arg#*=}" ;;
|
||||
crc=*) crc="${arg#*=}" ;;
|
||||
*) echo "Unknown modeline option passed: $arg" >&2 ;;
|
||||
*) echo "Ignoring unknown modeline option passed: '$arg'" >&2 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
gen-S-defines() {
|
||||
[[ $# -eq 0 ]] || munge-x11-modeline "$@"
|
||||
local -i pixel_clock_khz=$((pixel_clock_mhz * 1000))
|
||||
|
||||
local -A defines
|
||||
defines=(
|
||||
TIMING_NAME "${(qqq)name}"
|
||||
|
||||
CLOCK "$pixel_clock_khz"
|
||||
XPIX "$hdisp"
|
||||
XBLANK "$((htotal - hdisp))"
|
||||
XOFFSET "$((hsyncstart - hdisp))"
|
||||
XPULSE "$((hsyncend - hsyncstart))"
|
||||
CLOCK "$pixel_clock_khz"
|
||||
XPIX "$hdisp"
|
||||
XBLANK "$((htotal - hdisp))"
|
||||
XOFFSET "$((hsyncstart - hdisp))"
|
||||
XPULSE "$((hsyncend - hsyncstart))"
|
||||
|
||||
YPIX "$vdisp"
|
||||
YBLANK "$((vtotal - vdisp))"
|
||||
YOFFSET "(63+$((vsyncstart - vdisp)))"
|
||||
YPULSE "(63+$((vsyncend - vsyncstart)))"
|
||||
YPIX "$vdisp"
|
||||
YBLANK "$((vtotal - vdisp))"
|
||||
YOFFSET "(63+$((vsyncstart - vdisp)))"
|
||||
YPULSE "(63+$((vsyncend - vsyncstart)))"
|
||||
|
||||
VERSION "${edid_version%%.*}"
|
||||
REVISION "${edid_version#*.}"
|
||||
VERSION "${edid_version%%.*}"
|
||||
REVISION "${edid_version#*.}"
|
||||
|
||||
XY_RATIO "XY_RATIO_${(U)ratio//:/_}"
|
||||
DPI "$dpi"
|
||||
VFREQ "$vfreq_hz"
|
||||
HSYNC_POL "$hsync_polarity"
|
||||
VSYNC_POL "$vsync_polarity"
|
||||
CRC "$crc"
|
||||
XY_RATIO "XY_RATIO_${(U)ratio//:/_}"
|
||||
DPI "$dpi"
|
||||
VFREQ "$vfreq_hz"
|
||||
HSYNC_POL "$hsync_polarity"
|
||||
VSYNC_POL "$vsync_polarity"
|
||||
)
|
||||
}
|
||||
|
||||
template-S() {
|
||||
local -a lines=("/* $name: $* */")
|
||||
local -a lines=("/* $name: $REPLY */")
|
||||
local k
|
||||
for k in ${(k)defines}; do
|
||||
lines+=("#define $k ${defines[$k]}")
|
||||
done
|
||||
lines+=('#include "edid.S"')
|
||||
|
||||
echo "${(j:\n:)lines[@]}" | tee "$fn"
|
||||
echo "Wrote $fn" >&2
|
||||
echo "${(j:\n:)lines[@]}" > "$fn"
|
||||
echo "Wrote $fn"
|
||||
}
|
||||
|
||||
compile() {
|
||||
rm -fv $bin_fn
|
||||
echo "Compiling $bin_fn" >&2
|
||||
local i=0
|
||||
while true; do
|
||||
let i++ || :
|
||||
make >/dev/null 2>&1 || :
|
||||
! test -f "$bin_fn" || break
|
||||
[[ $i -lt 100 ]] || (echo "Failed to compute checksum for $bin_fn" >&2; exit 1)
|
||||
done
|
||||
echo "Compiled $bin_fn in $i iterations" >&2
|
||||
}
|
||||
local f=${1:-'-'}
|
||||
[[ $f != '-' ]] || f="/dev/stdin"
|
||||
|
||||
modeline2edid() {
|
||||
local name
|
||||
local -A defines
|
||||
gen-S-defines "$@"
|
||||
[[ -n "$name" ]] || (echo "Didn't get a name? The hell?" >&2 && exit 1)
|
||||
|
||||
# Template and compile
|
||||
template-S "$@"
|
||||
compile
|
||||
|
||||
# Fix CRC
|
||||
local crc=$(${0:h}/compute-crc)
|
||||
# we're done if we don't have a crc to fix
|
||||
[[ -n "$crc" ]] || return
|
||||
|
||||
# Re-template and compile with proper CRC
|
||||
defines[CRC]=$crc template-S "$@"
|
||||
compile
|
||||
}
|
||||
|
||||
|
||||
main() {
|
||||
zmodload -i zsh/zutil
|
||||
|
||||
# support single argument filename
|
||||
[[ -z $1 || $1 = -* ]] || set -- -f "$@"
|
||||
|
||||
local o_file=()
|
||||
zparseopts -K -D -E -- f:o_file
|
||||
local f=${o_file[-1]}
|
||||
|
||||
case $f in
|
||||
-|) f="/dev/stdin" ;;
|
||||
esac
|
||||
|
||||
if [ -z "$f" ]; then
|
||||
echo "Usage:" >&2
|
||||
echo "$0 [-f] FILENAME Parse modelines out of a file (eg xorg.conf) or '-' for stdin." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for unicorns in $f" >&2
|
||||
while read; do
|
||||
echo "-- Found a unicorn: $REPLY" >&2
|
||||
modeline2edid $=REPLY
|
||||
done < $f
|
||||
}
|
||||
if [[ -z "$f" || "$f" == "-h" ]]; then
|
||||
self=${0:t}
|
||||
cat >&2 <<-EOF
|
||||
Modeline2EDID, version forever 0.0.1
|
||||
Help:
|
||||
$self -h
|
||||
Parse modelines from stdin:
|
||||
$self
|
||||
$self -
|
||||
Parse modelines from a file (eg xorg.conf)
|
||||
$self FILENAME
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for runaway unicorns in '$f'"
|
||||
while read; do
|
||||
# trim
|
||||
REPLY=($=REPLY)
|
||||
[[ -n "$REPLY" ]] || continue
|
||||
template-S ${(@)REPLY} || :
|
||||
done < $f
|
||||
|
||||
Reference in New Issue
Block a user