ATI Binärtreiber (fglrx) benutzt nur Modes die via EDID ausgelesen werden / Faken von EDID Informationen
Auf Arbeit bin/war ich dabei einen PC für eine Videowall zu konfigurieren, welcher eine FirePro W7000 als Grafikkarte benutzt. Die Grafikkarte hat 4 Ausgänge, wovon jeder jeweils zwei Display’s ansteuern soll. Die zwei Display’s pro Ausgang sind untereinander jeweils per DaisyChain verbunden. Bei den Display’s handelt es sich um NEC X463UN.
Beispielhafte Darstellung:
|----------------| |----------------| | | | | | NEC | | NEC | | |\ /| | |----------------| | DaisyChain | |----------------| | |/ \| | | NEC | | NEC | | |\ /| | |----------------| \ / |----------------| | | \___ ___/ | | | NEC | | | | NEC | | |\ | | /| | |----------------| | | | | |----------------| | |/ | | \| | | NEC | | | | NEC | | |___ | | ___| | |----------------| | | | | |----------------| | | | | __Y_Y____Y_Y__ | | |PC mit Firepro| |______________|
Jeden Monitor möchte ich mit 720p ansprechen, was ich mit einer Auflösung von 1280×1440 pro Ausgang bewerkstellige. Und hier fingen nun die Probleme an, bzw. nachdem ich den binären Treiber nutzen musste, denn am Anfang hatte ich alles wunderbar, ohne Probleme mit dem Opensource-Treiber am laufen. Leider vertrug der sich bei Übergängen von HTML-Items zu Videos nicht sonderlich gut mit unserem Player. Also war/bin ich leider auf den Binär-Treiber von ATI angewiesen. Bei dem Binär-Treiber wunderte ich mich warum er die oben geschriebene Auslösung auf den Tod nicht annehmen wollte, auch wenn ich eine Modeline hinzufügte und prinzipiell alles richtig war. Ich las schon früh das der fglrx Treiber sich weigert andere Auflösungen anzunehmen, als die die er vom Monitor bekommt. Das muss ja aber zu umgehen sein, dachte ich und so fand ich die beiden Optionen:
Option "IgnoreEDID" "true" Option "NoDDC" "true"
welche man in die Device Sektion der xorg.conf hinzufügen konnte. Allerdings weiß ich nicht in welcher Version des Treibers dies funktioniert hatte, denn die aktuellste Version kommentiert das in der Xorg.0.log mit einem:
fglrx(0): Option "IgnoreEDID" is not used fglrx(0): Option "NoDDC" is not used
Irgendwann startete dann der X gar nicht mehr, weil er plötzlich die Modelines nicht mehr mochte. Dann fand ich einen guten Tipp, wo ich gar nicht wusste das der Treiber damit klar kommt. Man kann einfach die Datenbank Datei im /etc/ati Ordner löschen, wo hin sich der Treiber die xorg.conf übersetzt, die da heißt amdpcsdb. Nachdem ich das getan hab zeigte er mir zumindest schonmal mit xrandr die Modeline an, auch wenn er sie nicht auswählte und nur eine komische Auflösung von 1920×1920 ausgab.
Nachdem ich mit meinem Latein langsam am Ende war holt ich einen unseren Entwicker hinzu, der für mich wie eine laufende Linux Bibel ist. Nachdem ihm das Problem erläutert habe, schaute er sich auch nochmal alles an und wir probierten noch locker eine Stunder herum bis wir bei google auf eine lustige Entdeckung stießen. Und zwar versucht der fglrx Treiber aus dem Verzeichnis /etc/ati/ .edid Files auszulesen. Also machte wir uns schlau wir eine EDID Datein erstellen können, die wir dem Treiber mitgeben können. Um eine Datei zu erstellen nutzten wir das Programm Phoenix EDID Designer. Damit waren wir nun auch eine Weile beschäftigt. Warum erklär ich. Wir nahmen uns den EDID HEX Code eines Monitors aus der Xorg.0.log, welcher wie folgt aussieht:
00ffffffffffff0038a38c6801010101 161701038066398ceab7eda5554f9826 11474aa1090081c08100814081809040 9500a940b300f03c00d051a035506088 3a00fa3c3200001e000000fd0030551c 5c11000a202020202020000000fc0058 343633554e0a202020202020000000ff 0033353130383038374e420a2020012a
Nun mussten wir raus finden wie wir den Code formatieren damit ihn das Programm versteht, denn exportieren konnte es das im .raw Format, einlesen jedoch nur formatiert im .dat Format. Also haben wir eine Dummy Datei im .dat Format aus dem Programm erzeugt die wie folgt aussieht:
EDID BYTES: 0x 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ------------------------------------------------ 00 | 00 FF FF FF FF FF FF 00 04 21 00 00 00 00 00 00 10 | 01 00 01 03 00 00 00 00 00 00 00 00 00 00 00 00 20 | 00 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 30 | 01 01 01 01 01 01 64 00 00 00 00 00 00 00 00 00 40 | 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 00 50 | 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 60 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 70 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38
Also unseren HEX Code da rein gehauen und ja der muss genau so formatiert werden damit das Programm das annimmt. Das heißt nach jedem zweiten Zeichen eine Leerstelle und alle kleinen Buchstaben durch große ersetzen. Am Ende muss die Datei 128k groß sein, dann sollte alles richtig sein. Nachdem das geschehen war konnten wir nun endlich die Datei mit dem Programm öffnen, wo wir nun beim nächsten Problem standen, welche Werte der Modeline bei den Timings eintragen.
Das Schema war allerdings schnell gefunden. Ich erkläre es an Hand der Modeline die wir verwendet haben:
Modeline "1280x1440_60.00" 156.00 1280 1376 1512 1744 1440 1443 1453 1493 -hsync +vsync
Im Grunde sind für uns die drei Zahlengruppen zwischen „ und -hsync interessant, bestehend aus einer Zahl, gefolgt von zwei Zahlengruppen á 4 Zahlen.
1. Zahl:
Pixel Clk: 156.00
1. Zahlen Gruppe aus 4 Zahlen, welche die Horizontal Werte enthält:
H Active Pxl: 1280
H Blank: 1744 – 1280 = 464
H Sync Offset: 1376 – 1280 = 96
H Sync Width: 1512 – 1280 – 96 = 136
H Image Size: Die tatsächliche horizontale Abmessung des Panels in mm
2. Zahlen Gruppe aus 4 Zahlen, welche die Vertikal Werte enthält:
V Active Pxl: 1440
V Blank: 1493 – 1440 = 53
V Sync Offset: 1443 – 1440 = 3
V Sync Width: 1453 – 1440 – 3 = 10
V Image Size: Die tatsächliche vertikale Abmessung des Panels in mm
So nun noch die Datei als .raw exportieren und der komplizierte Teil war geschafft. Also haben wir der Datei noch einen eindeutigen Namen gegeben, diese dann in den /etc/ati Ordner kopiert und Symlinks angelegt mit den Namen der Grafikkarten Ausgänge mit .edid daran, da in unserem Fall auf allen die gleiche Auflösung ausgegeben werden soll. Einmal den X neugestartet und man sieht im Xorg.0.log das er nun die gewünschte Modeline anzeigt. Nun haben wir noch die Modelines aus der xorg.conf entfernt und wir trauten unseren Augen kaum – Es geht!!!
Alles in allen hat mich der ganze Spaß 5 Stunden und meinen Kollegen 3 Stunden gekostet. Man kann sich nun sicher drüber streiten wem man hier die Schuld zuschreiben kann. Den Entwicklern bei ATI welche, warum auch immer, es nicht zulassen andere Auslösungen anzunehmen, obwohl die Display’s es unterstützen oder NEC welche eigentlich davon ausgehen müssten, wenn sie Display’s mit DaisyChain verkaufen, da auch höhere Auslösungen gefahren werden müssen. Also sollte NEC für diesen Fall eigentlich noch, das Display, zusätzliche EDID Informationen übertragen lassen. Ich persönlich gebe aber ATI die Schuld, denn Warum kann es denn der Opensource Treiber und der eigene nicht, Warum baut man denn überhaupt so eine hirnrissige Hürde ein – ich mein das macht doch hinten und vorn keinen Sinn und vor allem Was macht denn ein normaler User der vielleicht ein Consumer Display nutzt welches fehlerhafte EDID Informationen eingetragen hat und übermittelt.
Jedenfalls haben wir es nun geschafft und ich hoffe das anderen hiermit geholfen ist, auch wenn es dennoch ein recht umständlicher Weg ist. Wenn man jedoch auf die Binärtreiber angewiesen ist führt wohl kein Weg vorbei. Sollte es dennoch einen geben würde ich diesen gern erfahren.
Ich danke auf jeden Fall Martin H. für seine Hilfe, der mir immer wieder beweist das ich keinen anderen kenne, der sich so sehr mit Linux auskennt wie er.
Quellen: DASTRUP Tech Logs – ATI fglrx Propriertary Driver Problems, Hot Ceshew – Fix corrupt EDID in Linux running ATI/Catalyst/fglrx Driver