From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 28452 invoked from network); 9 Apr 2023 07:01:17 -0000 Received: from 9front.inri.net (168.235.81.73) by inbox.vuxu.org with ESMTPUTF8; 9 Apr 2023 07:01:17 -0000 Received: from pb-smtp20.pobox.com ([173.228.157.52]) by 9front; Sun Apr 9 02:59:57 -0400 2023 Received: from pb-smtp20.pobox.com (unknown [127.0.0.1]) by pb-smtp20.pobox.com (Postfix) with ESMTP id 1F69B1F0A2C for <9front@9front.org>; Sun, 9 Apr 2023 02:59:53 -0400 (EDT) (envelope-from unobe@cpan.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; d=pobox.com; h=message-id :to:subject:date:from:in-reply-to:mime-version:content-type; s= sasl; bh=akLQVUtARLuSNo4ZQCg1MFc2GqIjpv7Zj+Md3qniziI=; b=QUr6flD /SQeupS6ilg0Z9n9AtTufOGTS0mG7I0tViSdvCMzf7PCvT2vHJVZWhNEMgRtPdy4 hncH3N1KiRmWr6unJh8b6+c8cjpU5/iPho19lvT7nMScRbmzaMDPw8kQA4Uay/XK Bne/gTY4GGmFkrVQ9lUKsuv9SxIjPjhRAqJ0= Received: from pb-smtp20.sea.icgroup.com (unknown [127.0.0.1]) by pb-smtp20.pobox.com (Postfix) with ESMTP id 17A391F0A2A for <9front@9front.org>; Sun, 9 Apr 2023 02:59:53 -0400 (EDT) (envelope-from unobe@cpan.org) Received: from strider.localdomain (unknown [75.204.169.210]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by pb-smtp20.pobox.com (Postfix) with ESMTPSA id C123D1F0A28 for <9front@9front.org>; Sun, 9 Apr 2023 02:59:49 -0400 (EDT) (envelope-from unobe@cpan.org) Message-ID: <852DC7E19786830AC75B24805D3FE9A4@smtp.pobox.com> To: 9front@9front.org Date: Sat, 08 Apr 2023 23:59:47 -0700 From: unobe@cpan.org In-Reply-To: <7EF5E553AFCDEAD2C89D011D4DEA3330@wopr.sciops.net> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="upas-ijrxmjzqeucgxhduilovegucix" X-Pobox-Relay-ID: 1ED5F498-D6A4-11ED-BB49-C2DA088D43B2-09620299!pb-smtp20.pobox.com List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: lossless configuration replication singleton Subject: Re: [9front] displayport thinkpad x230 external monitor black screen Reply-To: 9front@9front.org Precedence: bulk This is a multi-part message in MIME format. --upas-ijrxmjzqeucgxhduilovegucix Content-Disposition: inline Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Quoth qwx@sciops.net: > On Wed Apr 5 00:39:47 +0200 2023, igor@9lab.org wrote: > > I have a TP t420s as well as a x230i connected to an LG Ultrawide > > screen at 3440x1440. The following shows the TP t420s: > >=20 > > =E2=80=A2 https://9lab.org/plan9/thinkpad-t420s/#monitor > >=20 > > The LG Ultrawide works just as well via DP with the TP x230i; here is > > my /lib/vgadb entry for the screen: > >=20 > > # LG ULTRAWIDE > > lgUW=3D3440x1440 # 60Hz > > clock=3D319.75 > > shb=3D3488 ehb=3D3520 ht=3D3600 > > vrs=3D1443 vre=3D1453 vt=3D1481 > > hsync=3D+ vsync=3D- > >=20 > > With that entry in place I can use the monitor on the x230i as > > follows: > >=20 > > % @{rfork n; aux/realemu; aux/vga -m lgUW -l '3440x1440'} > >=20 > > =E2=80=A6 with a resolution of 3440x1440. >=20 > Nice! The issue does also depend on the actual monitor as well, but > it's good to know that some work at least. I should recheck my own. >=20 > Cheers, > qwx Thank you, sl, igor, qwx. I figured out the problem--the DisplayPort link training needed to be implemented more fully. I didn't know really much at all about DisplayPort; that has changed. I've attached a patch that implements pattern 1 & 2 training for HBR, along with fixing a couple other minor things I came across.[1] I'd be curious if the patch works for you, igor and qwx. I don't see why it wouldn't, but who knows. Reader be warned: I'm not a C programmer, so I'm sure there's much that can be improved upon. To test my patch, I defined this test function to ensure I could get my working display back. I didn't need to add anything to /lib/vgadb. fn lg { @ { rfork n; aux/realemu; cd /sys/src/cmd/aux/vga; mk; /sys/src/cmd/aux/vga= /6.out -v -V -m igfx -l 2560x1080; sleep 5; aux/vga -m igfx -l 1366x768 } } My monitor is consistently working at 2560x1080 now, with a passive DP cable. However, since the LG is a monitor that is notorious for agress power-savings mode, I need to run 'lg' pretty quickly upon connection, otherwise the monitor will already be in a deep sleep state.[2] - Romano [1] VGA connected displays are defined the VGA BIOS OEM docs from 1989; EDID data (or perhaps its superset, DisplayID) can wrap, so the shifting sub should account for that. [2] My next project might be implementing I2C over DP AUX more generally, which I think is needed query and send a monitor control command to "wake up" the monitor before running the training patterns. There's i2c(3), which I looked at briefly, and am wondering if it would make sense to create a driver to expose the I2C-over-AUX DisplayPorts as I2C devices so that i2c(3) can then be leveraged. --upas-ijrxmjzqeucgxhduilovegucix Content-Disposition: attachment; filename=igfx-dp.patch.txt Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit From: Romano Date: Sun, 09 Apr 2023 06:31:09 +0000 Subject: [PATCH] [PATCH] 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. --- diff 60b1a2f82dc96b254d6dec1bfd1c14ca056c21dd f2bdc9318599dc0cf578f83765fb6024b6290fe5 --- 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,40 @@ 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){ + 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); + i = 1; + } + } + + 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; --- a/sys/src/cmd/aux/vga/igfx.c +++ b/sys/src/cmd/aux/vga/igfx.c @@ -501,22 +501,22 @@ 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 @@ return -1; return buf[0]; } + static int wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val) { @@ -2202,9 +2203,86 @@ } static int +trainpatt(Igfx *igfx, Dp *dp, int w, int rd, int tr0, int mask1, int mask2) +{ + int ln[4], tr[4], la, 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<>4; + ln[0] = r & mask1; + if(r & 0x11){ + if(!((r = rdpaux(igfx, dp, 0x204)) & 1)){ + 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 @@ 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 @@ 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,36 +2344,8 @@ /* 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* snarfdpedid(Igfx *igfx, Dp *dp, int addr) { @@ -2319,7 +2363,7 @@ if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0) return nil; - for(i=0; i> 8; /* CH = connected, CL = available? */ + dspcon = (u.cx >> 8) & 0xf; /* detect active display devices */ vbesetup(vbe, &u, 0x5F64); --- a/sys/src/cmd/aux/vga/vga.h +++ b/sys/src/cmd/aux/vga/vga.h @@ -294,6 +294,7 @@ }; extern Flag edidflags[]; extern void printflags(Flag *f, int b); +extern uchar* edidshift(uchar*); extern Edid* parseedid128(void *v); extern void printedid(Edid *e); --upas-ijrxmjzqeucgxhduilovegucix--