shithub: patch

ref: fcf385299ac63be5f7e660fbf52a22d420f4603b
dir: /igfx-linktraining-fix/

View raw version
diff 10afa189d5ee84e1935ead905b3bbe38060a92e8 uncommitted
--- a/sys/src/cmd/aux/vga/igfx.c
+++ b/sys/src/cmd/aux/vga/igfx.c
@@ -372,12 +372,12 @@
 	if(igfx->pci->vid != 0x8086)
 		return -1;
 	switch(igfx->pci->did){
+	case 0x1616:	/* HD 5500 - 5th Gen Core (ULT) */
 	case 0x0a16:	/* HD 4400 - 4th Gen Core (ULT) */
 		igfx->isult = 1;
 		/* wet floor */
 	case 0x0a06:
 	case 0x3185:    /* UHD 600 - 9.5 Gen Core */
-	case 0x1616:	/* HD 5500 - 5th Gen Core */
 	case 0x0412:	/* HD 4600 - 4th Gen Core */
 		return TypeHSW;
 	case 0x0166:	/* 3rd Gen Core - ThinkPad X230 */
@@ -523,6 +523,8 @@
 	case TypeHSW:
 		igfx->npipe = 4;	/* A,B,C,eDP */
 		igfx->cdclk = igfx->isult ? 450 : 540;	/* MHz */
+		if(igfx->pci->did == 0x1616)	// ?
+			igfx->cdclk = 540;
 
 		igfx->dpll[0].ctrl	= snarfreg(igfx, 0x130040);	/* LCPLL_CTL */
 		igfx->dpll[1].ctrl	= snarfreg(igfx, 0x46040);	/* WRPLL_CTL1 */
@@ -927,9 +929,11 @@
 	vlong v;
 	int n;
 
+	trace("needlanes %d %d %d\n", freq, lsclk, bpp);
 	v = ((vlong)freq * bpp) / 8;
 	for(n=1; n<4 && v>lsclk; n<<=1, v>>=1)
 		;
+	trace("needlanes %d v %llud lsclk %d\n", n, v, lsclk);
 	return n;
 }
 
@@ -1063,6 +1067,7 @@
 	/* bits per color for cpu pipe */
 	for(i=0; i<nelem(bpctab); i++){
 		if(bpctab[i] == bpc){
+			// FIXME: csr, etc.
 			if(igfx->type == TypeHSW){
 				p->dpctl.v &= ~(7<<20);
 				p->dpctl.v |= i<<20;
@@ -1090,8 +1095,6 @@
 	if(m->z != 32)
 		error("%s: unsupported color depth %d\n", ctlr->name, m->z);
 
-	bpc = 8;	/* bits per color channel */
-
 	igfx = vga->private;
 
 	/* disable vga */
@@ -1133,12 +1136,11 @@
 
 	if((val = dbattr(m->attr, "display")) != nil){
 		port = atoi(val)-1;
-		if(igfx->type == TypeHSW && !igfx->dp[port-PortDPA].hdmi)
-			bpc = 6;
 	}else if(dbattr(m->attr, "lcd") != nil)
 		port = PortLCD;
 	else
 		port = PortVGA;
+	bpc = 8;	/* bits per color channel */
 
 	trace("%s: display #%d\n", ctlr->name, port+1);
 
@@ -1206,10 +1208,15 @@
 
 		if(igfx->type == TypeHSW){
 			if(port == PortDPA){
+				int c;
+
 				/* only enable panel for eDP */
 				igfx->ppcontrol.v |= 5;
 				/* use eDP pipe */
 				x = 3;
+				c = rr(igfx, igfx->pipe[x].dpctl.a);
+				if((c & 7<<20) == 2<<20)	/* 0 is bpc=8 */
+					bpc = 6;
 			}
 
 			/* reserved MBZ */
@@ -1216,8 +1223,8 @@
 			r->v &= ~(7<<28) & ~(1<<26) & ~(63<<19) & ~(3<<16) & ~(15<<11) & ~(1<<7) & ~31;
 			/* displayport SST mode */
 			r->v &= ~(1<<27);
-			/* link not in training, send normal pixels */
-			r->v |= 3<<8;
+			/* enable with training pattern 1 armed */
+			r->v &= ~(7<<8);
 			if(igfx->dp[port-PortDPA].hdmi){
 				/* hdmi: do not configure displayport */
 				r->a = 0;
@@ -1229,11 +1236,6 @@
 			r->v |= 1<<31;
 			/* reserved MBZ */
 			r->v &= ~(7<<28) & ~(127<<17) & ~(255<<8) & ~(3<<5);
-			/* grab lanes shared with port e when using port a */
-			if(port == PortDPA)
-				r->v |= 1<<4;
-			else if(port == PortDPE)
-				igfx->dp[0].bufctl.v &= ~(1<<4);
 			/* dp port width */
 			r->v &= ~(15<<1);
 			if(!igfx->dp[port-PortDPA].hdmi){
@@ -1243,6 +1245,11 @@
 					goto Badport;
 				r->v |= nl-1 << 1;
 			}
+			/* grab lanes shared with port e when using port a */
+			if(port == PortDPA)	// FIXME: shoudn't be touched?
+				r->v |= 1<<4;
+			else if(port == PortDPE)
+				igfx->dp[0].bufctl.v &= ~(1<<4);
 			/* port reversal: off */
 			r->v &= ~(1<<16);
 
@@ -1306,7 +1313,7 @@
 	}
 	p = &igfx->pipe[x];
 
-	/* plane enable, 32bpp */
+	/* plane enable, 32bit BGRX 8:8:8 */
 	p->dsp->cntr.v = (1<<31) | (6<<26);
 	if(igfx->type == TypeG45)
 		p->dsp->cntr.v |= x<<24;	/* pipe assign */
@@ -1556,9 +1563,6 @@
 {
 	int i;
 
-	/* deselect pipe clock */
-	csr(igfx, t->clksel.a, 7<<29, 0);
-
 	/* disable displayport transcoder */
 	if(igfx->type == TypeHSW){
 		csr(igfx, t->dpctl.a, 15<<28, 0);
@@ -1582,6 +1586,9 @@
 	/* workaround: clear timing override bit */
 	csr(igfx, t->chicken.a, 1<<31, 0);
 
+	/* deselect pipe clock */
+	csr(igfx, t->clksel.a, 7<<29, 0);
+
 	/* disable dpll  */
 	if(igfx->type != TypeHSW && t->dpll != nil)
 		csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
@@ -1644,6 +1651,8 @@
 		if((gtt[i] & ~((1<<11)-1<<1)) != pa)
 			break;
 	n = m->x * m->y * m->z / 8;
+	trace("checkgtt %d %d %d = %lud >=? %ud (%d)\n",
+		m->x, m->y, m->z, n, i<<12, i);
 	if(i<<12 >= n)
 		return;
 
@@ -1766,6 +1775,9 @@
 			csr(igfx, igfx->dpll[x].ctrl.a, 1<<31, 0);
 	}
 
+	/* program lcd power */
+	loadreg(igfx, igfx->ppcontrol);
+
 	/* program new clock sources */
 	loadreg(igfx, igfx->rawclkfreq);
 	loadreg(igfx, igfx->drefctl);
@@ -1781,6 +1793,7 @@
 	/* new dpll setting */
 	for(x=0; x<nelem(igfx->dpllsel); x++)
 		loadreg(igfx, igfx->dpllsel[x]);
+	sleep(10);
 
 	/* program all pipes */
 	for(x = 0; x < igfx->npipe; x++)
@@ -1794,16 +1807,25 @@
 	loadreg(igfx, igfx->sdvob);
 	loadreg(igfx, igfx->sdvoc);
 	for(x = 0; x < nelem(igfx->dp); x++){
+		if((igfx->dp[x].ctl.a == 0 || (igfx->dp[x].ctl.v & 1<<31) == 0) && !igfx->dp[x].hdmi)
+			continue;
+		if(!igfx->dp[x].hdmi){
+			igfx->dp[x].ctl.v &= ~(7<<8);	/* arm pattern 1 */
+			loadreg(igfx, igfx->dp[x].ctl);
+		}
 		for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
 			loadreg(igfx, igfx->dp[x].buftrans[y]);
+		sleep(100);
 		loadreg(igfx, igfx->dp[x].bufctl);
+		sleep(500);	/* needs to take a breath before training */
 		if(enabledp(igfx, &igfx->dp[x]) < 0)
 			ctlr->flag |= Ferror;
+		if(!igfx->dp[x].hdmi){
+			igfx->dp[x].ctl.v |= 3<<8;	/* send normal pixels */
+			loadreg(igfx, igfx->dp[x].ctl);
+		}
 	}
 
-	/* program lcd power */
-	loadreg(igfx, igfx->ppcontrol);
-
 	ctlr->flag |= Fload;
 }
 
@@ -2138,7 +2160,7 @@
 	buf[1] = addr >> 8;
 	buf[2] = addr;
 	buf[3] = len-1;
-	r = 3;	
+	r = 3;
 	if(data != nil && len > 0){
 		if((cmd & CmdRead) == 0)
 			memmove(buf+4, data, len);
@@ -2188,13 +2210,13 @@
 	if((dp->ctl.v & (1<<31)) == 0)
 		return 0;
 
-	/* FIXME: always times out */
-	if(igfx->type == TypeHSW && dp == &igfx->dp[0])
-		goto Skip;
-
 	/* Link configuration */
-	wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000);
-	w = dp->ctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
+	for(try=0; try<30; try++)
+		if(wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000) >= 0)
+			break;
+	if(try >= 30)
+		trace("can\'t start training\n");
+	w = dp->bufctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
 	wdpaux(igfx, dp, 0x101, w+1);
 
 	r = 0;
@@ -2244,11 +2266,8 @@
 				break;
 		}
 	}
-Skip:
+
 	/* stop training */
-	dp->ctl.v &= ~(7<<8);
-	dp->ctl.v |= 3<<8;
-	loadreg(igfx, dp->ctl);
 	wdpaux(igfx, dp, 0x102, 0x00);
 	return 1;