summaryrefslogtreecommitdiff
path: root/sys/src/cmd
diff options
context:
space:
mode:
authorRomano <unobe@cpan.org>2023-04-09 06:31:09 +0000
committerqwx <qwx@sciops.net>2023-04-09 06:31:09 +0000
commit101b3c2724779fcb0e503ae274abd7b751a3a48f (patch)
tree3d0651a32925618ca4f7afb99ba5d7f8758ed443 /sys/src/cmd
parent83b569cbc7e772ec454f87ccd71104b23faebbc8 (diff)
DP 1.2 on igfx; EDID wrapping; VGA display connections
This patch more fully implements the training patterns for DP 1.2 per the spec, which then allows more monitors to successfully train and therefore connect. In my case it was an LG 34UM68-P. Secondly, this fixes EDID shifting to work with a wider range of values, notably ones which wrap. Lastly, a small correction in vesa.c as to which bits are used to determine available connections.
Diffstat (limited to 'sys/src/cmd')
-rw-r--r--sys/src/cmd/aux/vga/edid.c36
-rw-r--r--sys/src/cmd/aux/vga/igfx.c180
-rw-r--r--sys/src/cmd/aux/vga/vesa.c2
-rw-r--r--sys/src/cmd/aux/vga/vga.h1
4 files changed, 149 insertions, 70 deletions
diff --git a/sys/src/cmd/aux/vga/edid.c b/sys/src/cmd/aux/vga/edid.c
index 09a0acbbc..ea1bb970a 100644
--- a/sys/src/cmd/aux/vga/edid.c
+++ b/sys/src/cmd/aux/vga/edid.c
@@ -6,6 +6,8 @@
#include "pci.h"
#include "vga.h"
+static uchar magic[8] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
+
static void
addmode(Modelist **l, Mode m)
{
@@ -180,10 +182,42 @@ decodesti(Mode *m, uchar *p)
return vesalookup(m, str);
}
+uchar*
+edidshift(uchar buf[256])
+{
+ uchar tmp[263];
+ int i = 256;
+ if(memcmp(buf, magic, 8) == 0)
+ return buf;
+
+ /*
+ * Some devices (e.g., igfx) access address space which has
+ * wrapped values, so shift if needed. Comparing and copying is
+ * easier by extending temp buffer slightly.
+ */
+ memcpy(tmp, buf, 256);
+ memcpy(tmp+256, buf, 7);
+ while(--i > 0)
+ if(memcmp(tmp+i, magic, 8) == 0){
+ trace("magic begins at index %d, shifting\n", i);
+ memcpy(buf, tmp+i, 256-i);
+ memcpy(buf+(256-i), tmp, i);
+ break;
+ }
+
+ trace("edid:\n");
+ for(i=0; i<256; i++){
+ trace("\t%x", buf[i]);
+ if ( (i+1) % 16 == 0)
+ trace("\n");
+ }
+
+ return buf;
+}
+
Edid*
parseedid128(void *v)
{
- static uchar magic[8] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
uchar *p, *q, sum;
int dpms, estab, i, m, vid;
Mode mode;
diff --git a/sys/src/cmd/aux/vga/igfx.c b/sys/src/cmd/aux/vga/igfx.c
index 06d0441ef..654ae906d 100644
--- a/sys/src/cmd/aux/vga/igfx.c
+++ b/sys/src/cmd/aux/vga/igfx.c
@@ -501,22 +501,22 @@ snarf(Vga* vga, Ctlr* ctlr)
igfx->dp[x].ctl = snarfreg(igfx, 0xE4000 + 0x100*x);
igfx->hdmi[1].ctl = snarfreg(igfx, 0x0E1140); /* HDMI_CTL_B */
- igfx->hdmi[1].bufctl[0] = snarfreg(igfx, 0x0FC810); /* HTMI_BUF_CTL_0 */
- igfx->hdmi[1].bufctl[1] = snarfreg(igfx, 0x0FC81C); /* HTMI_BUF_CTL_1 */
- igfx->hdmi[1].bufctl[2] = snarfreg(igfx, 0x0FC828); /* HTMI_BUF_CTL_2 */
- igfx->hdmi[1].bufctl[3] = snarfreg(igfx, 0x0FC834); /* HTMI_BUF_CTL_3 */
+ igfx->hdmi[1].bufctl[0] = snarfreg(igfx, 0x0FC810); /* HDMI_BUF_CTL_0 */
+ igfx->hdmi[1].bufctl[1] = snarfreg(igfx, 0x0FC81C); /* HDMI_BUF_CTL_1 */
+ igfx->hdmi[1].bufctl[2] = snarfreg(igfx, 0x0FC828); /* HDMI_BUF_CTL_2 */
+ igfx->hdmi[1].bufctl[3] = snarfreg(igfx, 0x0FC834); /* HDMI_BUF_CTL_3 */
igfx->hdmi[2].ctl = snarfreg(igfx, 0x0E1150); /* HDMI_CTL_C */
- igfx->hdmi[2].bufctl[0] = snarfreg(igfx, 0x0FCC00); /* HTMI_BUF_CTL_4 */
- igfx->hdmi[2].bufctl[1] = snarfreg(igfx, 0x0FCC0C); /* HTMI_BUF_CTL_5 */
- igfx->hdmi[2].bufctl[2] = snarfreg(igfx, 0x0FCC18); /* HTMI_BUF_CTL_6 */
- igfx->hdmi[2].bufctl[3] = snarfreg(igfx, 0x0FCC24); /* HTMI_BUF_CTL_7 */
+ igfx->hdmi[2].bufctl[0] = snarfreg(igfx, 0x0FCC00); /* HDMI_BUF_CTL_4 */
+ igfx->hdmi[2].bufctl[1] = snarfreg(igfx, 0x0FCC0C); /* HDMI_BUF_CTL_5 */
+ igfx->hdmi[2].bufctl[2] = snarfreg(igfx, 0x0FCC18); /* HDMI_BUF_CTL_6 */
+ igfx->hdmi[2].bufctl[3] = snarfreg(igfx, 0x0FCC24); /* HDMI_BUF_CTL_7 */
igfx->hdmi[3].ctl = snarfreg(igfx, 0x0E1160); /* HDMI_CTL_D */
- igfx->hdmi[3].bufctl[0] = snarfreg(igfx, 0x0FD000); /* HTMI_BUF_CTL_8 */
- igfx->hdmi[3].bufctl[1] = snarfreg(igfx, 0x0FD00C); /* HTMI_BUF_CTL_9 */
- igfx->hdmi[3].bufctl[2] = snarfreg(igfx, 0x0FD018); /* HTMI_BUF_CTL_10 */
- igfx->hdmi[3].bufctl[3] = snarfreg(igfx, 0x0FD024); /* HTMI_BUF_CTL_11 */
+ igfx->hdmi[3].bufctl[0] = snarfreg(igfx, 0x0FD000); /* HDMI_BUF_CTL_8 */
+ igfx->hdmi[3].bufctl[1] = snarfreg(igfx, 0x0FD00C); /* HDMI_BUF_CTL_9 */
+ igfx->hdmi[3].bufctl[2] = snarfreg(igfx, 0x0FD018); /* HDMI_BUF_CTL_10 */
+ igfx->hdmi[3].bufctl[3] = snarfreg(igfx, 0x0FD024); /* HDMI_BUF_CTL_11 */
igfx->lvds = snarfreg(igfx, 0x0E1180); /* LVDS_CTL */
goto PCHcommon;
@@ -2193,6 +2193,7 @@ rdpaux(Igfx *igfx, Dp *dp, int addr)
return -1;
return buf[0];
}
+
static int
wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
{
@@ -2202,9 +2203,86 @@ wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
}
static int
+trainpatt(Igfx *igfx, Dp *dp, int w, int rd, int tr0, int mask1, int mask2)
+{
+ int ln[4], tr[4], retry, try, i, r;
+
+ ln[0] = ln[1] = ln[2] = ln[3] = 0;
+ tr[0] = tr[1] = tr[2] = tr[3] = tr0;
+ for(try=0;; try++){
+ if(try > 5)
+ goto FailPatt;
+ sleep(1 << rd);
+ for(i=0; i<=w; i++)
+ wdpaux(igfx, dp, 0x103 + i, tr[i]);
+ sleep(1 << rd);
+ if((r = rdpaux(igfx, dp, 0x202)) < 0)
+ goto FailPatt;
+ trace("lane 0,1 status is %x\n", r);
+ retry = 0;
+ ln[1] = (r & mask1 << 4) >> 4;
+ ln[0] = r & mask1;
+ if(r & 0x11){
+ if(((r = rdpaux(igfx, dp, 0x204)) & 1) == 0){
+ trace("lane 0,1 align status is %x\n", r);
+ if((r = rdpaux(igfx, dp, 0x206)) >= 0){
+ trace("adjust tr[0,1] %x\n", r);
+ if(tr[0] != (r & mask2) << 1){
+ tr[0] = (r & mask2) << 1;
+ retry++;
+ }
+ if(tr[1] != ((r & mask2 << 4) >> 4) << 1){
+ tr[1] = ((r & mask2 << 4) >> 4) << 1;
+ retry++;
+ }
+ }
+ }
+ }
+ if(w > 1){
+ if((r = rdpaux(igfx, dp, 0x202)) < 0)
+ goto FailPatt;
+ trace("lane 2,3 status is %x\n", r);
+ ln[2] = r & mask1;
+ ln[3] = (r & mask1 << 4) >> 4;
+ if(r & 0x11){
+ if((r = rdpaux(igfx, dp, 0x204)) & 0x80){
+ trace("lane 2,3 align status is %x\n", r);
+ if((r = rdpaux(igfx, dp, 0x207)) >= 0){
+ trace("adjust tr[2,3] %x\n", r);
+ if(tr[2] != (r & mask2) << 1){
+ tr[2] = (r & mask2) << 1;
+ retry++;
+ }
+ if(tr[3] != ((r & mask2 << 4) >> 4) << 1){
+ tr[3] = ((r & mask2 << 4) >> 4) << 1;
+ retry++;
+ }
+ }
+ }
+ }
+ }
+ for(i=0; i<=w; i++)
+ if(ln[i] != mask1)
+ retry++;
+ if(!retry)
+ break;
+ }
+ trace("pattern finished after try %d: %x %x %x %x\n", try, ln[0], ln[1], ln[2], ln[3]);
+ return 0;
+
+FailPatt:
+ trace("training pattern failed on try %d: %x %x %x %x\n", try, ln[0], ln[1], ln[2], ln[3]);
+ /* disable port */
+ dp->ctl.v &= ~(1<<31);
+ loadreg(igfx, dp->ctl);
+ wdpaux(igfx, dp, 0x102, 0x00);
+ return -1;
+}
+
+static int
enabledp(Igfx *igfx, Dp *dp)
{
- int try, r;
+ int r, rd, try;
u32int w;
if(dp->ctl.a == 0)
@@ -2212,6 +2290,9 @@ enabledp(Igfx *igfx, Dp *dp)
if((dp->ctl.v & (1<<31)) == 0)
return 0;
+ r = rdpaux(igfx, dp, 0x0);
+ trace("DPCD Rev. 1.%d%c\n", (r & ~0xf) >> 4 & 0xf, (r & 0xf) + 0x60);
+
/* Link configuration */
for(try=0; try<30; try++)
if(wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000) >= 0)
@@ -2219,46 +2300,37 @@ enabledp(Igfx *igfx, Dp *dp)
if(try >= 30)
trace("can\'t start training\n");
w = dp->bufctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
+ if(igfx->type == TypeIVB)
+ w = (dp->ctl.v >> 19) & 7;
+ trace("using %x lane(s)\n", w+1);
wdpaux(igfx, dp, 0x101, w+1);
- r = 0;
+ rd = rdpaux(igfx, dp, 0x0e);
+ trace("read interval is %x\n", rd);
- /* Link training pattern 1 */
+ /* Link training pattern 1, see DisplayPort 1.2 Spec, p. 356ff. */
+ trace("link training pattern \n");
dp->ctl.v &= ~(7<<8);
loadreg(igfx, dp->ctl);
- for(try = 0;;try++){
- if(try > 5)
- goto Fail;
- /* Link training pattern 1 */
- wdpaux(igfx, dp, 0x102, 0x01);
- sleep(100);
- if((r = rdpaux(igfx, dp, 0x202)) < 0)
- goto Fail;
- if(r & 1) /* LANE0_CR_DONE */
- break;
- }
- trace("pattern1 finished: %x\n", r);
+ wdpaux(igfx, dp, 0x102, 0x10001);
+ wdpaux(igfx, dp, 0x102, 0x21);
+ if(trainpatt(igfx, dp, w, rd, 0x1, 0x1, 0x3))
+ return -1;
- /* Link training pattern 2 */
+ /* Link training pattern 2, see DisplayPort 1.2 Spec, p. 358ff. */
+ trace("link training pattern 2\n");
dp->ctl.v &= ~(7<<8);
dp->ctl.v |= 1<<8;
loadreg(igfx, dp->ctl);
- for(try = 0;;try++){
- if(try > 5)
- goto Fail;
- /* Link training pattern 2 */
- wdpaux(igfx, dp, 0x102, 0x02);
- sleep(100);
- if((r = rdpaux(igfx, dp, 0x202)) < 0)
- goto Fail;
- if((r & 7) == 7)
- break;
- }
- trace("pattern2 finished: %x\n", r);
+ wdpaux(igfx, dp, 0x102, 0x10002);
+ wdpaux(igfx, dp, 0x102, 0x22);
+ if(trainpatt(igfx, dp, w, rd, 0x8, 0x7, 0xc))
+ return -1;
if(igfx->type == TypeHSW){
/* set link training to idle pattern and wait for 5 idle
* patterns */
+ trace("idle pattern\n");
dp->ctl.v &= ~(7<<8);
dp->ctl.v |= 2<<8;
loadreg(igfx, dp->ctl);
@@ -2272,34 +2344,6 @@ enabledp(Igfx *igfx, Dp *dp)
/* stop training */
wdpaux(igfx, dp, 0x102, 0x00);
return 1;
-
-Fail:
- trace("training failed: %x\n", r);
-
- /* disable port */
- dp->ctl.v &= ~(1<<31);
- loadreg(igfx, dp->ctl);
- wdpaux(igfx, dp, 0x102, 0x00);
- return -1;
-}
-
-static uchar*
-edidshift(uchar buf[256])
-{
- uchar tmp[256];
- int i;
-
- /* shift if neccesary so edid block is at the start */
- for(i=0; i<256-8; i++){
- if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
- && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
- memmove(tmp, buf, i);
- memmove(buf, buf + i, 256 - i);
- memmove(buf + (256 - i), tmp, i);
- break;
- }
- }
- return buf;
}
static Edid*
diff --git a/sys/src/cmd/aux/vga/vesa.c b/sys/src/cmd/aux/vga/vesa.c
index 9b7165e31..5d8d5db86 100644
--- a/sys/src/cmd/aux/vga/vesa.c
+++ b/sys/src/cmd/aux/vga/vesa.c
@@ -638,7 +638,7 @@ vbesnarf(Vbe *vbe, Vga *vga)
u.bx = 0x200;
if(vbecall(vbe, &u) < 0)
u.cx = 0;
- dspcon = u.cx >> 8; /* CH = connected, CL = available? */
+ dspcon = (u.cx >> 8) & 0xf;
/* detect active display devices */
vbesetup(vbe, &u, 0x5F64);
diff --git a/sys/src/cmd/aux/vga/vga.h b/sys/src/cmd/aux/vga/vga.h
index cea109fc4..d5f600593 100644
--- a/sys/src/cmd/aux/vga/vga.h
+++ b/sys/src/cmd/aux/vga/vga.h
@@ -294,6 +294,7 @@ enum {
};
extern Flag edidflags[];
extern void printflags(Flag *f, int b);
+extern uchar* edidshift(uchar*);
extern Edid* parseedid128(void *v);
extern void printedid(Edid *e);