9front - general discussion about 9front
 help / color / mirror / Atom feed
* Re: [9front] core-i5(TypeSNB) and vesa mode
@ 2016-08-06 15:08 kokamoto
  0 siblings, 0 replies; 51+ messages in thread
From: kokamoto @ 2016-08-06 15:08 UTC (permalink / raw)
  To: kokamoto, 9front

After I dealt with display codes, I realised I'm just familier
with the whole codes of igfx.c.

I have a porpose to construct opur strategy.

1) make separate of the hard tie connection of pipe(x) and transcoder
number.

2) as we can judge which display device is connected to a port by
examimming the 2 bit of dpctl(e0300, e1300, e2300 etc),
we can put the dpctl enable of that port.

3) we can do above both for pipe(0) and pipe(1).
Let's the pipe(0) alone for native vga mode, even if we use it 
or not.  Do the change to pipe(1) above, because we are now
dealing with only frame buffer, which is not so heavy.
In a future, if we deal with 3D movie etc, let's consider about it.

4) for G965, we use pipe(1) for high resolution mode, however,
we use pipe(0) for Sandy/Ivy Bridge.   I wondered why at the
beginning.   Now I understand the reason, however, to make it
harmony with the case of G965 etc is the second reason.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-19 23:01                                                     ` kokamoto
@ 2016-08-20 17:11                                                       ` cinap_lenrek
  0 siblings, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-08-20 17:11 UTC (permalink / raw)
  To: 9front

i'v implemented displayport and fdi lane count determination now
(see needlanes() function) and tested on ivy bridge and g45 machine
with displayport and LVDS. 8bpc works now :)

also commited our work in progress sandy bridge code for fdi link
train sequence, but havnt included the changes for the dpll stuff as
they are in the wrong place and unexplained/make no sense.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-13 23:02                                                   ` kokamoto
@ 2016-08-19 23:01                                                     ` kokamoto
  2016-08-20 17:11                                                       ` cinap_lenrek
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-19 23:01 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 530 bytes --]

After I posted the sysinfo of Dell-790 machine, I intended to
make another 0x29a2 did old machine work, and then post
the results.

However, I got much tired, and can't do anything now.
It may continue one month or so.
Therefore, I'll post the diff to the last cdrom for Dell790 sandy-bridge machine
to work up to 1680x1050x32 resolution, not work for DP/HDMI, though.
This patch includes the one posted by cinap before.

It was made by the command:
diff -n /sys/src/cmd/aux/vga/igfx.c /n/cdrom/sys/src/cmd/aux/vga/igfx.c.

Kenji

[-- Attachment #2: Type: text/plain, Size: 12487 bytes --]

/sys/src/cmd/aux/vga/igfx.c:92,93 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:91
< 	Reg	rxiir;		/* FDI_RX_IIR */
< 	Reg	rximr;		/* FDI_RX_IMR */
/sys/src/cmd/aux/vga/igfx.c:221,222 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:218
< 
< /* South Display Engine */
/sys/src/cmd/aux/vga/igfx.c:227,233 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:223,229
< 	t->ht	= snarfreg(igfx, o + 0x00000);		/* HTOTAL */
< 	t->hb	= snarfreg(igfx, o + 0x00004);		/* HBLANK */
< 	t->hs	= snarfreg(igfx, o + 0x00008);		/* HSYNC */
< 	t->vt	= snarfreg(igfx, o + 0x0000C);		/* VTOTAL */
< 	t->vb	= snarfreg(igfx, o + 0x00010);		/* VBLANK */
< 	t->vs	= snarfreg(igfx, o + 0x00014);		/* VSYNC */
< 	t->vss	= snarfreg(igfx, o + 0x00028);		/* VSYNCSHIFT for interlaced */
---
> 	t->ht	= snarfreg(igfx, o + 0x00000);
> 	t->hb	= snarfreg(igfx, o + 0x00004);
> 	t->hs	= snarfreg(igfx, o + 0x00008);
> 	t->vt	= snarfreg(igfx, o + 0x0000C);
> 	t->vb	= snarfreg(igfx, o + 0x00010);
> 	t->vs	= snarfreg(igfx, o + 0x00014);
> 	t->vss	= snarfreg(igfx, o + 0x00028);
/sys/src/cmd/aux/vga/igfx.c:248,255 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:244,251
< 		t->dm[0] = snarfreg(igfx, o + 0x30);		/* Data M1 value (transcoder A) */
< 		t->dn[0] = snarfreg(igfx, o + 0x34);		/* Data N value (transcoder A) */
< 		t->dm[1] = snarfreg(igfx, o + 0x38);		/* Data M2 value (transcoder A) */
< 		t->dn[1] = snarfreg(igfx, o + 0x3c);		/* Data N2 value (transcoder A */
< 		t->lm[0] = snarfreg(igfx, o + 0x40);		/* Data Link M1 value (transcoder A) */
< 		t->ln[0] = snarfreg(igfx, o + 0x44);		/* Data Link N1 value (transcoder A) */
< 		t->lm[1] = snarfreg(igfx, o + 0x48);		/* Data Link M2 value (transcoder A) */
< 		t->ln[1] = snarfreg(igfx, o + 0x4c);		/* Data Link N2 value (transcoder A) */
---
> 		t->dm[0] = snarfreg(igfx, o + 0x30);
> 		t->dn[0] = snarfreg(igfx, o + 0x34);
> 		t->dm[1] = snarfreg(igfx, o + 0x38);
> 		t->dn[1] = snarfreg(igfx, o + 0x3c);
> 		t->lm[0] = snarfreg(igfx, o + 0x40);
> 		t->ln[0] = snarfreg(igfx, o + 0x44);
> 		t->lm[1] = snarfreg(igfx, o + 0x48);
> 		t->ln[1] = snarfreg(igfx, o + 0x4c);
/sys/src/cmd/aux/vga/igfx.c:269 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:265
< 	snarftrans(igfx, p, o);	/* HTOTAL Horizontal Total */
---
> 	snarftrans(igfx, p, o);
/sys/src/cmd/aux/vga/igfx.c:271 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:267
< 	p->src = snarfreg(igfx, o + 0x0001C);	/* SRCSZ source image size */
---
> 	p->src = snarfreg(igfx, o + 0x0001C);
/sys/src/cmd/aux/vga/igfx.c:279 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:274
< 		/* display port control */
/sys/src/cmd/aux/vga/igfx.c:298,299 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:293,294
< 	p->dsp->stride	= snarfreg(igfx, 0x70188 + x*0x1000);
< 	p->dsp->tileoff	= snarfreg(igfx, 0x701A4 + x*0x1000);
---
> 	p->dsp->stride		= snarfreg(igfx, 0x70188 + x*0x1000);
> 	p->dsp->tileoff		= snarfreg(igfx, 0x701A4 + x*0x1000);
/sys/src/cmd/aux/vga/igfx.c:304 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:300
> 	case TypeSNB:
/sys/src/cmd/aux/vga/igfx.c:312,313 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:308
< 		/* wet floor */
< 	case TypeSNB:
---
> 
/sys/src/cmd/aux/vga/igfx.c:329 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:323
< 	case 0x0102:	/* Dell Optiplex 790 */
/sys/src/cmd/aux/vga/igfx.c:333 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:326
< 	case 0x29a2:	/* 82P965/G965 HECI desktop */
/sys/src/cmd/aux/vga/igfx.c:407 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:400
< 		igfx->ppcontrol	= snarfreg(igfx, 0x61204);
---
> 		igfx->ppcontrol		= snarfreg(igfx, 0x61204);
/sys/src/cmd/aux/vga/igfx.c:414 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:407
< 		igfx->cdclk = 300;	/* Core Display Clock MHz */
---
> 		igfx->cdclk = 300;	/* MHz */
/sys/src/cmd/aux/vga/igfx.c:495 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:489
> 
/sys/src/cmd/aux/vga/igfx.c:576,579 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:569
< 
< print("freq=%lld, cref=%d, m1=%ud, m2=%ud, n=%ud,p1=%ud,p2=%ud\n", a, cref, *m1,*m2,*n,*p1,P2);	/* K.Okamoto */
< print("fitted frequency = %ulld\n", (uvlong)cref*(5*(*m1+2)+(*m2+2))/(*n+2)/(*p1*P2));
< 
/sys/src/cmd/aux/vga/igfx.c:611,623 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:600
< 		/* transcoder dpll enable */
< 		igfx->dpllsel.v |= 8<<(x*4);
< 		/* program rawclock to 125MHz */
< 		igfx->rawclkfreq.v = 125;
< 		if(port == PortLCD){
< 			igfx->drefctl.v |= 2<<11;
< 			igfx->drefctl.v |= 1;
< 		} else{
< 			igfx->drefctl.v |= 2<<9;
< //			igfx->drefctl.v |= 2<<11;
< //			igfx->drefctl.v |= 1;
< 		}
< 		goto PCHcommon1;
/sys/src/cmd/aux/vga/igfx.c:628,629 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:605
< //		igfx->rawclkfreq.v = 125;
< 		igfx->rawclkfreq.v = rr(igfx, 0xC6204);		/* K.Okamoto */
---
> 		igfx->rawclkfreq.v = 125;
/sys/src/cmd/aux/vga/igfx.c:644 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:619
< PCHcommon1:
/sys/src/cmd/aux/vga/igfx.c:658 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:633
< 	cref = getcref(igfx, x);	/* cref=120MHz for TypeSNB, 96MHz for TypeG45 */
---
> 	cref = getcref(igfx, x);
/sys/src/cmd/aux/vga/igfx.c:665 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:640
< 	dpll->ctrl.v &= ~(3<<24);		/* reset FP1 P2 divide */
---
> 	dpll->ctrl.v &= ~(3<<24);
/sys/src/cmd/aux/vga/igfx.c:677,678 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:652
< //		if(freq > 225*MHz){		/* K.Okamoto */
< 			p2 >>= 1;		/* p2 = 5 */
---
> 			p2 >>= 1;
/sys/src/cmd/aux/vga/igfx.c:697,699 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:670
< //m1=14, m2=8, n=3, p1=2  K.Okamoto
< // ctrl.a=c6014, dpll->fp0.a=c6048 K.Okamoto
< //print("m1=%d, m2=%d, n=%d, p1=%d, p2=%d\n", m1, m2, n, p1, p2);
/sys/src/cmd/aux/vga/igfx.c:724 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:695
< 	u32int m, n;
---
> 	uvlong m, n;
/sys/src/cmd/aux/vga/igfx.c:727 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:698
< 	m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
---
> 	m = (n * ((freq * bpp)/8)) / (lsclk * lanes);
/sys/src/cmd/aux/vga/igfx.c:733 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:704
< 	m = ((uvlong)n * freq) / lsclk;
---
> 	m = (n * freq) / lsclk;
/sys/src/cmd/aux/vga/igfx.c:750 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:721
< 	/* trans/pipe enable */
---
> 	/* tans/pipe enable */
/sys/src/cmd/aux/vga/igfx.c:760 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:732
> 
/sys/src/cmd/aux/vga/igfx.c:786 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:759
> 	lanes = 1;
/sys/src/cmd/aux/vga/igfx.c:788,792 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:760
< 	if((m->x * m->y) < 1680*1050)	/* quick & dirty hack */
< 		lanes = 1;
< 	else
< 		lanes = 2;			/* for 1680x1050x32 */
< 
/sys/src/cmd/aux/vga/igfx.c:794 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:762
< 	if(fdi->rxctl.a != 0){		/* TypeSNB or TypeIVB */
---
> 	if(fdi->rxctl.a != 0){
/sys/src/cmd/aux/vga/igfx.c:821 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:789
< 		fdi->rxtu[0].v = (tu-1)<<25;	/* set tusize=tu-1 */
---
> 		fdi->rxtu[0].v = (tu-1)<<25;
/sys/src/cmd/aux/vga/igfx.c:853 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:821
< 	/* disable vga compatibility */
---
> 	/* disable vga */
/sys/src/cmd/aux/vga/igfx.c:860 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:828,830
< 	igfx->adpa.v &= ~(1<<31);	/* disable ADPA */
---
> 	igfx->adpa.v &= ~(1<<31);
> 	if(igfx->type == TypeG45)
> 		igfx->adpa.v |= (3<<10);	/* Monitor DPMS: off */
/sys/src/cmd/aux/vga/igfx.c:891,893 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:861
< 		if(igfx->type == TypeG45)
< 			x = (igfx->adpa.v >> 30) & 1;
< 		if(igfx->type == TypeSNB || igfx->type == TypeIVB)
---
> 		if(igfx->npipe > 2)
/sys/src/cmd/aux/vga/igfx.c:894 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:863,864
> 		else
> 			x = (igfx->adpa.v >> 30) & 1;
/sys/src/cmd/aux/vga/igfx.c:897 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:867
<  			igfx->adpa.v &= ~(3<<10);	/* Monitor DPMS: on */
---
> 			igfx->adpa.v &= ~(3<<10);	/* Monitor DPMS: on */
/sys/src/cmd/aux/vga/igfx.c:906,913 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:875
< 		if(igfx->type == TypeSNB){	/* set DPMS VSYNC, HSYNC added K.Okamoto */
< 			igfx->adpa.v |= 3<<3;
< 			if(m->hsync == '-')
< 				igfx->adpa.v ^= 1<<3;
< 			if(m->vsync == '-')
< 				igfx->adpa.v ^= 1<<4;
< 				igfx->pipe[x].fdi->dpctl.v ^= 1<<4;
< 		}
/sys/src/cmd/aux/vga/igfx.c:917,920 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:879,882
< 		if(igfx->type == TypeG45)
< 			x = (igfx->lvds.v >> 30) & 1;	/* pipe select 0/1 */
< 		if(igfx->type == TypeSNB || igfx->type == TypeIVB)
< 			x = (igfx->lvds.v >> 29) & 3;	/* transcoder A or B or C */
---
> 		if(igfx->npipe > 2)
> 			x = (igfx->lvds.v >> 29) & 3;
> 		else
> 			x = (igfx->lvds.v >> 30) & 1;
/sys/src/cmd/aux/vga/igfx.c:1084,1092 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1046,1048
< 	if(p->fdi->rxctl.a != 0){		/* TypeSNB or TypeIVB */
< 		if(igfx->type == TypeSNB){
< 			csr(igfx, 0xC6200, 1<<11, 2);	/* pch ref souce & ssc enable */
< 			sleep(5);
< 		csr(igfx, 0xC6200, 1<<0, 1);	/* ssc1 enable */
< 		sleep(5);
< 		}
< 		p->fdi->rxctl.v &= ~(1<<31);	/* disable */
< 		p->fdi->rxctl.v &= ~(1<<4);	/* rawclk(not pcdclk) */
---
> 	if(p->fdi->rxctl.a != 0){
> 		p->fdi->rxctl.v &= ~(1<<31);
> 		p->fdi->rxctl.v &= ~(1<<4);	/* rawclk */
/sys/src/cmd/aux/vga/igfx.c:1100,1102 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1056,1057
< 		if(igfx->type != TypeSNB)
< 			p->fdi->txctl.v &= ~(1<<31);	/* disable */
< 		p->fdi->txctl.v |= (1<<14);	/* enable FDI pll */
---
> 		p->fdi->txctl.v &= ~(1<<31);
> 		p->fdi->rxctl.v |= (1<<14);	/* enable pll */
/sys/src/cmd/aux/vga/igfx.c:1149,1151 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1103
< 		if (igfx->type == TypeSNB){
< 			/* unmask bit lock and symbol lock bits */
< 			csr(igfx, p->fdi->rximr.a, 3<<8, 0);
/sys/src/cmd/aux/vga/igfx.c:1153,1156 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1105,1108
< 			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern1 */
< 			p->fdi->rxctl.v |= 1<<31;	/* enable */
< 			loadreg(igfx, p->fdi->rxctl);
<  
---
> 		p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 00 */
> 		p->fdi->rxctl.v |= 1<<10;	/* auto train enable */
> 		p->fdi->rxctl.v |= 1<<31;	/* enable */
> 		loadreg(igfx, p->fdi->rxctl);
/sys/src/cmd/aux/vga/igfx.c:1158,1160 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1110,1113
< 			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern1 */
< 			p->fdi->txctl.v |= 1<<31;	/* enable */
< 			loadreg(igfx, p->fdi->txctl);
---
> 		p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 00 */
> 		p->fdi->txctl.v |= 1<<10;	/* auto train enable */
> 		p->fdi->txctl.v |= 1<<31;	/* enable */
> 		loadreg(igfx, p->fdi->txctl);
/sys/src/cmd/aux/vga/igfx.c:1162,1186 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1115,1116
< 			/* wait for bit lock */
< 			for(i=0; i<10; i++){
< 				sleep(1);
< 				if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
< 					break;
< 			}
< 			csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
< 	
< 			/* switch to link train pattern2 */
< 			csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
< 			csr(igfx, p->fdi->txctl.a, 3<<8, 1<<8);
< 
< 			/* wait for symbol lock */
< 			for(i=0; i<10; i++){
< 				sleep(1);
< 				if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
< 					break;
< 			}
< 			csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
< 
< 			/* switch to link train normal */
< 			csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
< 			csr(igfx, p->fdi->txctl.a, 0, 3<<8);
< 
< 			/* wait idle pattern time */
---
> 		/* wait for link training done */
> 		for(i=0; i<200; i++){
/sys/src/cmd/aux/vga/igfx.c:1188,1204 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1118,1119
< 		} else {
< 			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 00 */
< 			p->fdi->rxctl.v |= 1<<10;	/* auto train enable */
< 			p->fdi->rxctl.v |= 1<<31;	/* enable */
< 			loadreg(igfx, p->fdi->rxctl);
< 
< 			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 00 */
< 			p->fdi->txctl.v |= 1<<10;	/* auto train enable */
< 			p->fdi->txctl.v |= 1<<31;	/* enable */
< 			loadreg(igfx, p->fdi->txctl);
< 
< 			/* wait for link training done */
< 			for(i=0; i<200; i++){
< 				sleep(5);
< 				if(rr(igfx, p->fdi->txctl.a) & 2)
< 					break;
< 			}
---
> 			if(rr(igfx, p->fdi->txctl.a) & 2)
> 				break;
/sys/src/cmd/aux/vga/igfx.c:1292 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1207
< 	csr(igfx, igfx->adpa.a, 1<<31, 0);	/* disable adpa */
---
> 	csr(igfx, igfx->adpa.a, 1<<31, 0);
/sys/src/cmd/aux/vga/igfx.c:1335,1336 d /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1249
< 	igfx->adpa.v &= ~(3<<10);	/* Monitor DPMS: on */
< 
/sys/src/cmd/aux/vga/igfx.c:1798 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1712
> 
/sys/src/cmd/aux/vga/igfx.c:1800 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1715
> 
/sys/src/cmd/aux/vga/igfx.c:1818 a /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1734
> 
/sys/src/cmd/aux/vga/igfx.c:1840 c /n/cdrom/sys/src/cmd/aux/vga/igfx.c:1756
< 	wr(igfx, igfx->gmbus[GMBUSCP].a, port);		/* set out device by port# */
---
> 	wr(igfx, igfx->gmbus[GMBUSCP].a, port);

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-13  5:57                                                 ` kokamoto
@ 2016-08-13 23:02                                                   ` kokamoto
  2016-08-19 23:01                                                     ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-13 23:02 UTC (permalink / raw)
  To: 9front

I posted sysinfo of this Dell Optiplex 790 ultrasmall desktop
machine with amd64 cputype at 9front's web, #177.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-13  4:14                                               ` kokamoto
@ 2016-08-13  5:57                                                 ` kokamoto
  2016-08-13 23:02                                                   ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-13  5:57 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 144 bytes --]

I included the diff of vga info at1680x1050x32 resolutions.
diff (lanes=2) (lanes=1)

The values of dm1, dm2 or dm1/dn1 are interesting.

Kenji

[-- Attachment #2: Type: text/plain, Size: 1699 bytes --]

320c320
< igfx pipe a dm1      [00060030] = 7e4e0000
---
> igfx pipe a dm1      [00060030] = ffe165ac
324c324
< igfx pipe a dm2      [00060038] = 7e4e0000
---
> igfx pipe a dm2      [00060038] = ffe165ac
329c329
< igfx pipe a dm1/dn1  0.609375
---
> igfx pipe a dm1/dn1  1.760915
339c339
< igfx fdi a dm1       [000e0030] = 7e4e0000
---
> igfx fdi a dm1       [000e0030] = ffe165ac
343c343
< igfx fdi a dm2       [000e0038] = 7e4e0000
---
> igfx fdi a dm2       [000e0038] = ffe165ac
348c348
< igfx fdi a dm1/dn1   0.609375
---
> igfx fdi a dm1/dn1   1.760915
357,359c357,359
< igfx fdi a dpctl     [000e0300] = 60000408
< igfx fdi a txctl     [00060100] = b00c4000
< igfx fdi a rxctl     [000f000c] = 800a2350
---
> igfx fdi a dpctl     [000e0300] = 60000418
> igfx fdi a txctl     [00060100] = b0044000
> igfx fdi a rxctl     [000f000c] = 80022350
627c627
< igfx pipe a dm1      [00060030] = 7e4e0000
---
> igfx pipe a dm1      [00060030] = ffe165ac
631c631
< igfx pipe a dm2      [00060038] = 7e4e0000
---
> igfx pipe a dm2      [00060038] = ffe165ac
636c636
< igfx pipe a dm1/dn1  0.609375
---
> igfx pipe a dm1/dn1  1.760915
646c646
< igfx fdi a dm1       [000e0030] = 7e4e0000
---
> igfx fdi a dm1       [000e0030] = ffe165ac
650c650
< igfx fdi a dm2       [000e0038] = 7e4e0000
---
> igfx fdi a dm2       [000e0038] = ffe165ac
655c655
< igfx fdi a dm1/dn1   0.609375
---
> igfx fdi a dm1/dn1   1.760915
664,666c664,666
< igfx fdi a dpctl     [000e0300] = 60000408
< igfx fdi a txctl     [00060100] = b00c4000
< igfx fdi a rxctl     [000f000c] = 800a2050
---
> igfx fdi a dpctl     [000e0300] = 60000418
> igfx fdi a txctl     [00060100] = b0044000
> igfx fdi a rxctl     [000f000c] = 80022050

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-09  8:47                                         ` cinap_lenrek
@ 2016-08-13  4:21                                           ` kokamoto
  0 siblings, 0 replies; 51+ messages in thread
From: kokamoto @ 2016-08-13  4:21 UTC (permalink / raw)
  To: 9front

> are you talking about multi monitor support?

No.

I just wondered what we know about which display port is which
on various models.   In the case of 0102, the dp->hdmi cabled
dp port is Display port C not A or even B, though its model has
only one display port on the box.    To know it at the time of
setting up a terminal is not easy.   However, if we could make it
automatic it's fancy.  That's all.

 Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-13  1:32                                             ` cinap_lenrek
@ 2016-08-13  4:14                                               ` kokamoto
  2016-08-13  5:57                                                 ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-13  4:14 UTC (permalink / raw)
  To: 9front

> ah, yes... i forgot about that. we should probably calculate the
> number of lanes needed for the requested resolution based on
> the bandwidth required.

Yes, I've read that prt of the manual, which is difficult to
understand.☺

1680x1050 resolution is very comfortable to do something!

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-12 23:27                                           ` kokamoto
@ 2016-08-13  1:32                                             ` cinap_lenrek
  2016-08-13  4:14                                               ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-08-13  1:32 UTC (permalink / raw)
  To: 9front

> This season in Japan is called 'Obon' when our ansester's spirits come back.
> We must visit our ansester's grave and worship, means holiday in general.

i understand.

> Now, I got a good rest, which introduced me how to solve 1680x1050x32
> resolution problem.   It was very simple, that is:

> in initpipe() function of /sys/src/cmd/aux/vga change the line:
> 	lanes = 1;
> to
> 	lanes = 2;			/* for 1680x1050x32 */

ah, yes... i forgot about that. we should probably calculate the
number of lanes needed for the requested resolution based on
the bandwidth required.

note, the displayport control registers also need this setting.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-09  9:40                                         ` cinap_lenrek
@ 2016-08-12 23:27                                           ` kokamoto
  2016-08-13  1:32                                             ` cinap_lenrek
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-12 23:27 UTC (permalink / raw)
  To: 9front


Thanks, and apologize the delay of my response.
This season in Japan is called 'Obon' when our ansester's spirits come back.
We must visit our ansester's grave and worship, means holiday in general.

Now, I got a good rest, which introduced me how to solve 1680x1050x32
resolution problem.   It was very simple, that is:

in initpipe() function of /sys/src/cmd/aux/vga change the line:
	lanes = 1;
to
	lanes = 2;			/* for 1680x1050x32 */

Tht's all!

Kenji

PS. I still have problem of how to utilize DP device.
However, it is low priority of the scope, then, if I could have 
a motivation to it and time, I'll come back there.


>> 1) make separate of the hard tie connection of pipe(x) and transcoder
>> number (pipe(0) for display port A, pipe(1) for display port B etc).
> 
> this is not what the code does. we assign cpu pipe 0 for all displayports.
> display port A is not on the PCH side, but on the CPU side, so fdi is
> not involved.
> 
> for lvds or analog vga, we use the cpu pipe that the bios picked before
> us.
> 
> --
> cinap



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-09  1:29                                       ` kokamoto
  2016-08-09  8:47                                         ` cinap_lenrek
@ 2016-08-09  9:40                                         ` cinap_lenrek
  2016-08-12 23:27                                           ` kokamoto
  1 sibling, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-08-09  9:40 UTC (permalink / raw)
  To: 9front

> 1) make separate of the hard tie connection of pipe(x) and transcoder
> number (pipe(0) for display port A, pipe(1) for display port B etc).

this is not what the code does. we assign cpu pipe 0 for all displayports.
display port A is not on the PCH side, but on the CPU side, so fdi is
not involved.

for lvds or analog vga, we use the cpu pipe that the bios picked before
us.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-09  1:29                                       ` kokamoto
@ 2016-08-09  8:47                                         ` cinap_lenrek
  2016-08-13  4:21                                           ` kokamoto
  2016-08-09  9:40                                         ` cinap_lenrek
  1 sibling, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-08-09  8:47 UTC (permalink / raw)
  To: 9front

are you talking about multi monitor support? you havnt even fugured
out the dpll setup, nor got dpaux to work and not understood what
is going on in the fdi link training code. please try to get
the *basics* working before trying to enable *multiple* pipes
at the same time...

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-07  0:38                                     ` cinap_lenrek
@ 2016-08-09  1:29                                       ` kokamoto
  2016-08-09  8:47                                         ` cinap_lenrek
  2016-08-09  9:40                                         ` cinap_lenrek
  0 siblings, 2 replies; 51+ messages in thread
From: kokamoto @ 2016-08-09  1:29 UTC (permalink / raw)
  To: 9front

After I touched with display codes, I realised I'm just familier
with the whole codes of igfx.c now.

I have a porpose to construct our strategy.

1) make separate of the hard tie connection of pipe(x) and transcoder
number (pipe(0) for display port A, pipe(1) for display port B etc).

2) as we can judge which display device is connected to a port by
examimming the 2 bit of dpctl(e0300, e1300, e2300 etc),
we can put the dpctl enable of that port.

3) we can do above both for pipe(0) and pipe(1).
Let's the pipe(0) alone for native vga mode, even if we use it 
or not.  Do the change to pipe(1) above, because we are now
dealing with only frame buffer, which is not so heavy.
In a future, if we deal with 3D movie etc, let's consider about it.

4) for G965, we use pipe(1) for high resolution mode, however,
we use pipe(0) for Sandy/Ivy Bridge.   I wondered why at the
beginning.   Now I understand the reason, however, to make it
harmony with the case of G965 etc is the second reason.

Kenji

PS. I maty be wrong, of course. If so please point it to me.



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-07  0:08                                   ` kokamoto
@ 2016-08-07  0:38                                     ` cinap_lenrek
  2016-08-09  1:29                                       ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-08-07  0:38 UTC (permalink / raw)
  To: 9front

i asked on the linux igfx mailinglist about this FDI C
thing... i'll report back when theres an answer.

display= is really an attribute was ment to come from
automatically reading edid information. its not a property
of the monitor, but rather what the port number of your
graphics card is.

if snarfing edid works, we wont need vgadb. on my thinkpad,
i just do:

aux/vga -m auto -l 1280x800x32

it automatically finds the monitor, edid and port from that.
no vgadb neccesary.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-06 12:55                                 ` kokamoto
  2016-08-06 13:05                                   ` cinap_lenrek
  2016-08-06 13:58                                   ` cinap_lenrek
@ 2016-08-07  0:08                                   ` kokamoto
  2016-08-07  0:38                                     ` cinap_lenrek
  2 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-07  0:08 UTC (permalink / raw)
  To: 9front

Thanks cinap!
I'll continue to examine what is wrong here.

> However, I have no message from this line in init():
> 	case PortDPA:
> 	case PortDPB:
> 	case PortDPC:
> 	case PortDPD:
> 		r = &igfx->dp[port - PortDPA].ctl;
> 
> 
> print("dp[%d] ctl address = %ullx\n", (port-PortDPA), r->a);  <====
> 
> 		if(r->a == 0)
> 			goto Badport;
> 		/* port enable */

This is solved.
Oh, my idiot!

I put the line
display=5
in my /cfg/pxe/xxxxxx ini file.
However, the codes requires it should be in
lib/vgadb!

Then, I put the lines in /lib/vgadb like:
#
# Full High resolution TV
#
fhirestv=1920x1080		# 60Hz
	clock=148.5
	shb=2008 ehb=2052 ht=2200
	vrs=1084 vre=1089 vt=1125
	hsync=+ vsync=+
	display=5

Ok, I'm going into the init() function now.
The dp[2] ctl address = e4200!

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-06 12:55                                 ` kokamoto
  2016-08-06 13:05                                   ` cinap_lenrek
@ 2016-08-06 13:58                                   ` cinap_lenrek
  2016-08-07  0:08                                   ` kokamoto
  2 siblings, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-08-06 13:58 UTC (permalink / raw)
  To: 9front

what is also interesting is that the register offset file lists
a 3rd FDI receiver (FDI C) and in the documentation for IVB 
it notes that FDI B and C share lanes. But the transmitter side is
undocumented for SNB, so we only have FDI_TX_CTL for pipe A and B.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-06 12:55                                 ` kokamoto
@ 2016-08-06 13:05                                   ` cinap_lenrek
  2016-08-06 13:58                                   ` cinap_lenrek
  2016-08-07  0:08                                   ` kokamoto
  2 siblings, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-08-06 13:05 UTC (permalink / raw)
  To: 9front

http://01.org/sites/default/files/documentation/ilk_ihd_os_vol3_part3r2.pdf

section 1.1.1 Display Diagram. This is not exactly sandy bridge but it
gives a good overview.

for displayport aux channel stuff, i dont think you need the FDI enabled,
just the clocks. Also dont attempt to modeset, all we want is just read
the EDID info over the displayport aux channel. Once we have that, setting
the right port is done automatically.

Note, without the DP AUX channel working, you wont get anything, because
displayport link training is controlled over it.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-06  5:51                               ` kokamoto
@ 2016-08-06 12:55                                 ` kokamoto
  2016-08-06 13:05                                   ` cinap_lenrek
                                                     ` (2 more replies)
  0 siblings, 3 replies; 51+ messages in thread
From: kokamoto @ 2016-08-06 12:55 UTC (permalink / raw)
  To: 9front

> I think I got the reason.
> in snarfpipe()
> codes looks like:
> 	if(igfx->type == TypeIVB || igfx->type == TypeSNB) {
> 		p->fdi->txctl = snarfreg(igfx, o + 0x100);
> 
> 		o = 0xE0000 | x*0x1000;
> 		snarftrans(igfx, p->fdi, o);
> 
> 		p->fdi->dpctl = snarfreg(igfx, o + 0x300);	<===
> 
> Here, as our SandyBridge has two pipes, the value of p->fdi->dpctl could
> be snarfed only for dp[0] and dp[1], because snarfpipe()'x is the value of
> pipe, here 0 or 1.
> However, in my case, this machine is connected to DP[2], Displayport C.

No, it's wrong!

However, I have no message from this line in init():
	case PortDPA:
	case PortDPB:
	case PortDPC:
	case PortDPD:
		r = &igfx->dp[port - PortDPA].ctl;


print("dp[%d] ctl address = %ullx\n", (port-PortDPA), r->a);  <====

		if(r->a == 0)
			goto Badport;
		/* port enable */

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-08-05 23:58                             ` kokamoto
@ 2016-08-06  5:51                               ` kokamoto
  2016-08-06 12:55                                 ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-06  5:51 UTC (permalink / raw)
  To: 9front

>> Do you get edid from
>> displayport aux channel?
> 
> No, I don't.

I think I got the reason.
in snarfpipe()
codes looks like:
	if(igfx->type == TypeIVB || igfx->type == TypeSNB) {
		p->fdi->txctl = snarfreg(igfx, o + 0x100);

		o = 0xE0000 | x*0x1000;
		snarftrans(igfx, p->fdi, o);

		p->fdi->dpctl = snarfreg(igfx, o + 0x300);	<===

Here, as our SandyBridge has two pipes, the value of p->fdi->dpctl could
be snarfed only for dp[0] and dp[1], because snarfpipe()'x is the value of
pipe, here 0 or 1.
However, in my case, this machine is connected to DP[2], Displayport C.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-29 13:01                           ` cinap_lenrek
  2016-07-29 23:41                             ` kokamoto
@ 2016-08-05 23:58                             ` kokamoto
  2016-08-06  5:51                               ` kokamoto
  1 sibling, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-08-05 23:58 UTC (permalink / raw)
  To: 9front

I don't get success for 1680x1050x32, though I tried many things.
Then, I'm testing DP->hdmi connector case.

> Do you get edid from
> displayport aux channel?

No, I don't.

I put a debug line in init() like:
	case PortDPA:
	case PortDPB:
	case PortDPC:
	case PortDPD:
		r = &igfx->dp[port - PortDPA].ctl;
		if(r->a == 0)
			goto Badport;
		/* port enable */


print("Passing case PortDP\n");


		r->v |= 1<<31;
		/* port width selection: x1 Mode */
		r->v &= ~(7<<19);

Nothing printed.

I tired display=3~6 in /cfg/pxe/xxxxxx.

I changed the sources from your updated one to:
1) in init()
	/* disable all pipes and ports */
	igfx->ppcontrol.v &= 0xFFFF;
	igfx->ppcontrol.v &= ~5;
	igfx->lvds.v &= ~(1<<31);
	igfx->adpa.v &= ~(1<<31);
/* from here */
		if(igfx->type == TypeSNB){	/* K.Okamoto */
			csr(igfx, 0xC6200, 3<<11, 2);	/* pch ref souce & ssc enable */
			sleep(5);
			csr(igfx, 0xC6200, 1<<0, 1);	/* ssc1 enable */
			sleep(5);
		}
/*  to here */
	if(igfx->type == TypeG45)
		igfx->adpa.v |= (3<<10);	/* Monitor DPMS: off */
	for(x=0; x<nelem(igfx->dp); x++)

2) in enablepipe()
	int i;
	Pipe *p;

	p = &igfx->pipe[x];
	if((p->conf.v & (1<<31)) == 0)
		return;	/* pipe is disabled, done */

	if(p->fdi->rxctl.a != 0){
		p->fdi->rxctl.v &= ~(1<<31);
		p->fdi->rxctl.v &= ~(1<<4);	/* rawclk */
		p->fdi->rxctl.v |= (1<<13);	/* enable pll */
		loadreg(igfx, p->fdi->rxctl);
		sleep(5);
		p->fdi->rxctl.v |= (1<<4);	/* pcdclk */
		loadreg(igfx, p->fdi->rxctl);
		sleep(5);
/* from here */
		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
		if(igfx->type != TypeSNB)
			p->fdi->txctl.v &= ~(1<<31);	/* disable */
		p->fdi->txctl.v |= (1<<14);	/* enable FDI pll */
		loadreg(igfx, p->fdi->txctl);
		sleep(5);
/* to here */
	}

	/* image size (vga needs to be off) */
	loadreg(igfx, p->src);

Kenji

PS. By the way, I haven't get edid data all from the beginning,
which means I didn't change the source anything.



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 13:26                   ` cinap_lenrek
@ 2016-08-01  6:51                     ` kokamoto
  0 siblings, 0 replies; 51+ messages in thread
From: kokamoto @ 2016-08-01  6:51 UTC (permalink / raw)
  To: 9front

Ok, I returned from vacation.

I hadn't noticed that you posted full version of the diff.

> full diff follows... note that i added rxiir and rximr softregs
> to the Fdi structure. this is because there can be multiple fdi
> links.
> 
> diff -r 7ecc3cd531be sys/src/cmd/aux/vga/igfx.c
> --- a/sys/src/cmd/aux/vga/igfx.c	Sun Jul 24 15:13:14 2016 +0200
> +++ b/sys/src/cmd/aux/vga/igfx.c	Thu Jul 28 14:57:05 2016 +0200

I test this, and it fails.
It shows unstable horizontal color bands only.

Howeveer, when I change the lines like:
	p = &igfx->pipe[x];
	if((p->conf.v & (1<<31)) == 0)
		return;	/* pipe is disabled, done */

	if(p->fdi->rxctl.a != 0){
/* from here */
		if(igfx->type == TypeSNB){	/* K.Okamoto */
			csr(igfx, 0xC6200, 1<<11, 2);	/* pch ref souce & ssc enable */
			sleep(5);
		}
/*  to here */
		p->fdi->rxctl.v &= ~(1<<31);
		p->fdi->rxctl.v &= ~(1<<4);	/* rawclk */
		p->fdi->rxctl.v |= (1<<13);	/* enable pll */
		loadreg(igfx, p->fdi->rxctl);
		sleep(5);
		p->fdi->rxctl.v |= (1<<4);	/* pcdclk */
		loadreg(igfx, p->fdi->rxctl);
		sleep(5);
/* from here */
		if(igfx->type == TypeSNB){	/* K.Okamoto */	
			p->fdi->txctl.v |= (1<<14);	/* enable FDI pll K.Okamoto */
			loadreg(igfx, p->fdi->txctl);
			sleep(5);
		}else{
			p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
			p->fdi->txctl.v &= ~(1<<31);	/* disable */
			p->fdi->txctl.v |= (1<<14);	/* enable pll */
			loadreg(igfx, p->fdi->txctl);
		sleep(5);
		}
/* to here */
	}

The behaviour is all the same I posted before.
This is the first one after the rest, which means my brain works week.
I'll continue working slowly as usual.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-29 23:41                             ` kokamoto
@ 2016-07-29 23:43                               ` cinap_lenrek
  0 siblings, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-29 23:43 UTC (permalink / raw)
  To: 9front

progress :-)

have a good rest.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-29 13:01                           ` cinap_lenrek
@ 2016-07-29 23:41                             ` kokamoto
  2016-07-29 23:43                               ` cinap_lenrek
  2016-08-05 23:58                             ` kokamoto
  1 sibling, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-29 23:41 UTC (permalink / raw)
  To: 9front

> FDI is the backbone for everything. your analog DACs (vga) and external display
> port connectors are on the PCH (north) side. the FDI is the connection from the
> cpu (north) side to the PCH.

After your suggestion,  "Is it really crt timing related?".
I researched my old 965 machine's log for 1680x01050x32 mode, though
that machine corrupted, and found it had also 146400000Htz for 146250000Hrz.
Although its value is the same value as the present i5 machine, it worked fine.
So, you are right.   My facing problem does not come from another reason.
Ok, I'll have just a rest (yes, much tired), and try your suggestion 
on the initialization process itself.

> I would guess that the reason for DP not working has todo with your code
> overriding DREF_CONTROL register. Some debugging in the display port link
> training code might give some hints whats going on. Do you get edid from
> displayport aux channel?

Yes, in the vesa mode, but not igfx mode.
for vesa mode like below:
....
vesa mode           0x160 848x480x8 m8 packed
vesa mode           0x161 848x480x16 r5g6b5 direct
vesa mode           0x162 848x480x32 x8r8g8b8 direct
vesa mode           0x165 1280x1024x32 x8r8g8b8 direct
vesa mode           0x168 1440x900x32 x8r8g8b8 direct
vesa mode           0x107 1280x1024x8 m8 packed
vesa mode           0x11a 1280x1024x16 r5g6b5 direct
vesa mode           0x11b 1280x1024x32 x8r8g8b8 direct
vesa mode           0x105 1024x768x8 m8 packed
vesa mode           0x117 1024x768x16 r5g6b5 direct
vesa mode           0x118 1024x768x32 x8r8g8b8 direct
vesa mode           0x112 640x480x32 x8r8g8b8 direct
vesa mode           0x114 800x600x16 r5g6b5 direct
vesa mode           0x115 800x600x32 x8r8g8b8 direct
vesa mode           0x101 640x480x8 m8 packed
vesa mode           0x103 800x600x8 m8 packed
vesa mode           0x111 640x480x16 r5g6b5 direct
vesa mode           0x17d 1920x1080x8 m8 packed (unoffered)
vesa mode           0x17e 1920x1080x16 r5g6b5 direct (unoffered)
vesa mode           0x17f 1920x1080x32 x8r8g8b8 direct (unoffered)
edid mfr            SHP
edid serialstr      
edid name           SHARP HDMI
edid product        4256
edid serial         0
edid version        1.3
edid mfrdate        2012.255
edid size (cm)      89x50
edid gamma          2.20
edid vert (Hz)      23-76
edid horz (Hz)      15000-68000
edid pclkmax        150000000
edid flags           digital activeoff
edid 1360x768@60Hz  
		clock=85.5
		shb=1424 ehb=1536 ht=1792
		vrs=771 vre=777 vt=795
		hsync=+ vsync=+ 
edid 1920x1080@60Hz 
		clock=148.5
		shb=2008 ehb=2052 ht=2200
		vrs=1084 vre=1089 vt=1125
		hsync=+ vsync=+ 
	....

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-29 11:49                         ` kokamoto
@ 2016-07-29 13:01                           ` cinap_lenrek
  2016-07-29 23:41                             ` kokamoto
  2016-08-05 23:58                             ` kokamoto
  0 siblings, 2 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-29 13:01 UTC (permalink / raw)
  To: 9front

FDI is the backbone for everything. your analog DACs (vga) and external display
port connectors are on the PCH (north) side. the FDI is the connection from the
cpu (north) side to the PCH.

On some laptops the embedded displayport is used for the LCD panel, without
involving the PCH.

I would guess that the reason for DP not working has todo with your code
overriding DREF_CONTROL register. Some debugging in the display port link
training code might give some hints whats going on. Do you get edid from
displayport aux channel?

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-29  8:15                       ` cinap_lenrek
@ 2016-07-29 11:49                         ` kokamoto
  2016-07-29 13:01                           ` cinap_lenrek
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-29 11:49 UTC (permalink / raw)
  To: 9front

Those may relate to the fact that DP port dosen't work
by my code, as I said before.   However, on Analog VGA display, it is
working now.  Now, I'm cocerned with VGA display, because I want
to use this machine on that environment.

Kenji

>> It sounds like the same as I did here.
> 
> no, it is not. you put your code *before* the ivy bridge
> fdi link code which works differently resulting in the
> exeuction of patterns 2 followed by auto-train mode.
> this enables the fdi with train pattern 2, not pattern 1
> which is invalid.
> 
> also you poll the wrong interrupt register. you poll the
> DEIIR (0x44008) which has bit definitions:
> 
> https://01.org/sites/default/files/documentation/snb_ihd_os_vol3_part2.pdf
> section 2.5.1 "Display Engine Interrupt Registers Bit Definition"
> 
> bit 9:	Pipe_B_CRC_error;		This is an active high pulse on the Pipe B CRC error. 
> bit 8:	Pipe_B_FIFO_underrun;	This is an active high level for the duration of the Pipe B FIFO underrun. 
> 
> 	/* TypeSNB or TypeIVB */
> 		/* enable fdi */
> 		loadreg(igfx, p->fdi->rxtu[1]);
> 		loadreg(igfx, p->fdi->rxtu[0]);
> 		loadreg(igfx, p->fdi->rxmisc);
> /* from here   K.Okamoto */
> 		if (igfx->type == TypeSNB){
> 			for(i=0;i<10;i++){	/* ensure Receive IIR, K.Okamoto */
> 				if(rr(igfx, 0x44008) & 1<<8)
> 				break;
> 			}
> 			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 1 enable */
> 			p->fdi->rxctl.v |= (1<<8);		/* link train pattern 2 enable */
> 			p->fdi->rxctl.v |= 1<<31;	/* enable FDI pll */
> 			loadreg(igfx, p->fdi->rxctl);
> 			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 1 enable */
> 			p->fdi->txctl.v |= (1<<8);		/* link train pattern 2 enable */
> 			p->fdi->txctl.v |= 1<<31;	/* enable FDI pll */
> 			loadreg(igfx, p->fdi->txctl);
> 			for(i=0;i<10;i++){
> 				if(rr(igfx, 0x44008) & 1<<9)	/* ensure Receive IIR, K.Okamoto */
> 					break;
> 			}
> /* to here  K.Okamoto */
> 		}
> 		p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 1 enable[default] */
> 		p->fdi->rxctl.v |= 1<<10;	/* auto train enable */
> 		p->fdi->rxctl.v |= 1<<31;	/* enable FDI pll */
> 		loadreg(igfx, p->fdi->rxctl);
> 
> 		p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 1 enable[default] */
> 		p->fdi->txctl.v |= 1<<10;	/* auto train enable */
> 		p->fdi->txctl.v |= 1<<31;	/* enable FDI pll */
> 		loadreg(igfx, p->fdi->txctl);
> 
> 		/* wait for link training done */
> 		for(i=0; i<200; i++){
> 			sleep(5);
> 			if(rr(igfx, p->fdi->txctl.a) & 2)	/* auto train done */
> 				break;
> 		}
> 	
>> I'm not interested now on it, because I have now another
>> problem of stability of high resolution(up to 1680x1050x32
> 
> i cannot help you then.
> 
>> Kenji
> 
> --
> cinap



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-29  9:00                         ` cinap_lenrek
@ 2016-07-29 11:42                           ` kokamoto
  0 siblings, 0 replies; 51+ messages in thread
From: kokamoto @ 2016-07-29 11:42 UTC (permalink / raw)
  To: 9front

> how do you know the freqency is the issue? 

The screen sitting more right hand side, but not all.
I can see the shape of mouse or opened rio terminal window etc,
but cannot read the character.  Such shiftness or line by line
dislocation seems like be explained by the difference of the
fitted frequency.   Probably, the m, n values are not good.

>you could setup
> that screen with vesa and then snarf the registers and see
> what it programs into the dpll regs.

AS I said before, the vesa bios of this machine works only for
Displayport.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-29  0:58                       ` kokamoto
@ 2016-07-29  9:00                         ` cinap_lenrek
  2016-07-29 11:42                           ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-07-29  9:00 UTC (permalink / raw)
  To: 9front

how do you know the freqency is the issue? you could setup
that screen with vesa and then snarf the registers and see
what it programs into the dpll regs.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 23:48                     ` kokamoto
  2016-07-29  0:58                       ` kokamoto
@ 2016-07-29  8:15                       ` cinap_lenrek
  2016-07-29 11:49                         ` kokamoto
  1 sibling, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-07-29  8:15 UTC (permalink / raw)
  To: 9front


> It sounds like the same as I did here.

no, it is not. you put your code *before* the ivy bridge
fdi link code which works differently resulting in the
exeuction of patterns 2 followed by auto-train mode.
this enables the fdi with train pattern 2, not pattern 1
which is invalid.

also you poll the wrong interrupt register. you poll the
DEIIR (0x44008) which has bit definitions:

https://01.org/sites/default/files/documentation/snb_ihd_os_vol3_part2.pdf
section 2.5.1 "Display Engine Interrupt Registers Bit Definition"

bit 9:	Pipe_B_CRC_error;		This is an active high pulse on the Pipe B CRC error. 
bit 8:	Pipe_B_FIFO_underrun;	This is an active high level for the duration of the Pipe B FIFO underrun. 

	/* TypeSNB or TypeIVB */
		/* enable fdi */
		loadreg(igfx, p->fdi->rxtu[1]);
		loadreg(igfx, p->fdi->rxtu[0]);
		loadreg(igfx, p->fdi->rxmisc);
/* from here   K.Okamoto */
		if (igfx->type == TypeSNB){
			for(i=0;i<10;i++){	/* ensure Receive IIR, K.Okamoto */
				if(rr(igfx, 0x44008) & 1<<8)
				break;
			}
			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 1 enable */
			p->fdi->rxctl.v |= (1<<8);		/* link train pattern 2 enable */
			p->fdi->rxctl.v |= 1<<31;	/* enable FDI pll */
			loadreg(igfx, p->fdi->rxctl);
			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 1 enable */
			p->fdi->txctl.v |= (1<<8);		/* link train pattern 2 enable */
			p->fdi->txctl.v |= 1<<31;	/* enable FDI pll */
			loadreg(igfx, p->fdi->txctl);
			for(i=0;i<10;i++){
				if(rr(igfx, 0x44008) & 1<<9)	/* ensure Receive IIR, K.Okamoto */
					break;
			}
/* to here  K.Okamoto */
		}
		p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 1 enable[default] */
		p->fdi->rxctl.v |= 1<<10;	/* auto train enable */
		p->fdi->rxctl.v |= 1<<31;	/* enable FDI pll */
		loadreg(igfx, p->fdi->rxctl);

		p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 1 enable[default] */
		p->fdi->txctl.v |= 1<<10;	/* auto train enable */
		p->fdi->txctl.v |= 1<<31;	/* enable FDI pll */
		loadreg(igfx, p->fdi->txctl);

		/* wait for link training done */
		for(i=0; i<200; i++){
			sleep(5);
			if(rr(igfx, p->fdi->txctl.a) & 2)	/* auto train done */
				break;
		}
	
> I'm not interested now on it, because I have now another
> problem of stability of high resolution(up to 1680x1050x32

i cannot help you then.

> Kenji

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 23:48                     ` kokamoto
@ 2016-07-29  0:58                       ` kokamoto
  2016-07-29  9:00                         ` cinap_lenrek
  2016-07-29  8:15                       ` cinap_lenrek
  1 sibling, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-29  0:58 UTC (permalink / raw)
  To: 9front

> I'm not interested now on it, because I have now another
> problem of stability of high resolution(up to 1680x1050x32).

Sorry, cinap.
This is my foundermental way to do anything.
My brain does not accept anything else when I have a serious problem.

I'll consider your mail after I solved my facing problem.

By the way, I'm trying to use 1680x1050x32 mode,
and genpll() calculates the fitted frequency as 146400000 Htz.
However, the desired one is 146250000, the difference is
150000 Htz, and m1=21, m2=5, n=3, p1=2, p2=10.
I tried several cases to change the initial values, or ranges,
but the diffrence of this case is the smallest.
It makes unstable screen.

Anyone can solve this?

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 13:31                   ` cinap_lenrek
@ 2016-07-28 23:48                     ` kokamoto
  2016-07-29  0:58                       ` kokamoto
  2016-07-29  8:15                       ` cinap_lenrek
  0 siblings, 2 replies; 51+ messages in thread
From: kokamoto @ 2016-07-28 23:48 UTC (permalink / raw)
  To: 9front

> its just two functions. gen6_fdi_link_train() is called frist, which
> exercises training pattern 1 and 2. after that, intel_fdi_normal_train()
> is called which switches to link train pattern normal mode.

It sounds like the same as I did here.
I'm not interested now on it, because I have now another
problem of stability of high resolution(up to 1680x1050x32).

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 11:34                 ` kokamoto
@ 2016-07-28 13:31                   ` cinap_lenrek
  2016-07-28 23:48                     ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-07-28 13:31 UTC (permalink / raw)
  To: 9front

>> theres what the linux driver does for SNB fdi link training, conforming to
>> the documentation:
>> 
>> http://lxr.free-electrons.com/source/drivers/gpu/drm/i915/intel_display.c#L3419
>
>It's very hard to me to read linux sources...
>abstruction, abstruction, abstruction, abstruction, abstruction
>
>Kenji

its just two functions. gen6_fdi_link_train() is called frist, which
exercises training pattern 1 and 2. after that, intel_fdi_normal_train()
is called which switches to link train pattern normal mode.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 11:31                 ` kokamoto
@ 2016-07-28 13:26                   ` cinap_lenrek
  2016-08-01  6:51                     ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-07-28 13:26 UTC (permalink / raw)
  To: 9front

> I had intended to follow those lines, because I had no other guides for this.
> Maybe I made something wrong?

i dont know that. all i see is your changes without
explaination and the intel documentation. if theres
a difference between these, i have to ask why they
differ. sometimes, documentation can be wrong. but
you only know that if you *tried* it the documented
way first... which i dont know if you did that or not.

now something we can test:

this is what i got for the fdi link training code for
SNB now which is based on the documentation, but cannot
test it.

i'm not sure rximr unmasking is actually needed, but
linux driver does it. (tho they handle interrupts
and we dont).

			/* unmask bit lock and symbol lock bits */
			csr(igfx, p->fdi->rximr.a, 3<<8, 0);

			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern1 */
			p->fdi->rxctl.v |= 1<<31;	/* enable */
			loadreg(igfx, p->fdi->rxctl);

			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern1 */
			p->fdi->txctl.v |= 1<<31;	/* enable */
			loadreg(igfx, p->fdi->txctl);

			/* wait for bit lock */
			for(i=0; i<10; i++){
				sleep(1);
				if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
					break;
			}
			csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
	
			/* switch to link train pattern2 */
			csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
			csr(igfx, p->fdi->txctl.a, 3<<8, 1<<8);

			/* wait for symbol lock */
			for(i=0; i<10; i++){
				sleep(1);
				if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
					break;
			}
			csr(igfx, p->fdi->rxiir.a, 0, 1<<9);

			/* switch to link train normal */
			csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
			csr(igfx, p->fdi->txctl.a, 0, 3<<8);

			/* wait idle pattern time */
			sleep(5);

full diff follows... note that i added rxiir and rximr softregs
to the Fdi structure. this is because there can be multiple fdi
links.

diff -r 7ecc3cd531be sys/src/cmd/aux/vga/igfx.c
--- a/sys/src/cmd/aux/vga/igfx.c	Sun Jul 24 15:13:14 2016 +0200
+++ b/sys/src/cmd/aux/vga/igfx.c	Thu Jul 28 14:57:05 2016 +0200
@@ -89,6 +89,8 @@
 
 	Reg	rxctl;		/* FDI_RX_CTL */
 	Reg	rxmisc;		/* FDI_RX_MISC */
+	Reg	rxiir;		/* FDI_RX_IIR */
+	Reg	rximr;		/* FDI_RX_IMR */
 	Reg	rxtu[2];	/* FDI_RX_TUSIZE */
 };
 
@@ -276,6 +278,10 @@
 
 		p->fdi->rxctl = snarfreg(igfx, o + 0x1000c);
 		p->fdi->rxmisc = snarfreg(igfx, o + 0x10010);
+
+		p->fdi->rxiir = snarfreg(igfx, o + 0x10014);
+		p->fdi->rximr = snarfreg(igfx, o + 0x10018);
+
 		p->fdi->rxtu[0] = snarfreg(igfx, o + 0x10030);
 		p->fdi->rxtu[1] = snarfreg(igfx, o + 0x10038);
 
@@ -297,7 +303,6 @@
 	/* cursor plane */
 	switch(igfx->type){
 	case TypeIVB:
-	case TypeSNB:
 		p->cur->cntr	= snarfreg(igfx, 0x70080 + x*0x1000);
 		p->cur->base	= snarfreg(igfx, 0x70084 + x*0x1000);
 		p->cur->pos	= snarfreg(igfx, 0x70088 + x*0x1000);
@@ -305,7 +310,8 @@
 	case TypeG45:
 		p->dsp->pos	= snarfreg(igfx, 0x7018C + x*0x1000);
 		p->dsp->size	= snarfreg(igfx, 0x70190 + x*0x1000);
-
+		/* wet floor */
+	case TypeSNB:
 		p->cur->cntr	= snarfreg(igfx, 0x70080 + x*0x40);
 		p->cur->base	= snarfreg(igfx, 0x70084 + x*0x40);
 		p->cur->pos	= snarfreg(igfx, 0x70088 + x*0x40);
@@ -320,10 +326,13 @@
 		return -1;
 	switch(igfx->pci->did){
 	case 0x0166:	/* 3rd Gen Core - ThinkPad X230 */
+	case 0x0152:	/* 2nd/3rd Gen Core - Core-i3 */
 		return TypeIVB;
+	case 0x0102:	/* Dell Optiplex 790 */
 	case 0x0126:	/* Thinkpad X220 */
 		return TypeSNB;
 	case 0x27a2:	/* GM945/82940GML - ThinkPad X60 Tablet */
+	case 0x29a2:	/* 82P965/G965 HECI desktop */
 	case 0x2a02:	/* GM965/GL960/X3100 - ThinkPad X61 Tablet */
 	case 0x2a42:	/* 4 Series Mobile - ThinkPad X200 */
 		return TypeG45;
@@ -858,10 +867,10 @@
 		break;
 
 	case PortVGA:
-		if(igfx->npipe > 2)
+		if(igfx->type == TypeG45)
+			x = (igfx->adpa.v >> 30) & 1;
+		else
 			x = (igfx->adpa.v >> 29) & 3;
-		else
-			x = (igfx->adpa.v >> 30) & 1;
 		igfx->adpa.v |= (1<<31);
 		if(igfx->type == TypeG45){
 			igfx->adpa.v &= ~(3<<10);	/* Monitor DPMS: on */
@@ -876,10 +885,10 @@
 		break;
 
 	case PortLCD:
-		if(igfx->npipe > 2)
+		if(igfx->type == TypeG45)
+			x = (igfx->lvds.v >> 30) & 1;
+		else
 			x = (igfx->lvds.v >> 29) & 3;
-		else
-			x = (igfx->lvds.v >> 30) & 1;
 		igfx->lvds.v |= (1<<31);
 		igfx->ppcontrol.v |= 5;
 
@@ -1053,8 +1062,8 @@
 		loadreg(igfx, p->fdi->rxctl);
 		sleep(5);
 		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
-		p->fdi->txctl.v &= ~(1<<31);
-		p->fdi->rxctl.v |= (1<<14);	/* enable pll */
+		p->fdi->txctl.v &= ~(1<<31);	/* disable */
+		p->fdi->txctl.v |= (1<<14);	/* enable pll */
 		loadreg(igfx, p->fdi->txctl);
 		sleep(5);
 	}
@@ -1102,21 +1111,61 @@
 		loadreg(igfx, p->fdi->rxtu[0]);
 		loadreg(igfx, p->fdi->rxmisc);
 
-		p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 00 */
-		p->fdi->rxctl.v |= 1<<10;	/* auto train enable */
-		p->fdi->rxctl.v |= 1<<31;	/* enable */
-		loadreg(igfx, p->fdi->rxctl);
+		if(igfx->type == TypeSNB){
+			/* unmask bit lock and symbol lock bits */
+			csr(igfx, p->fdi->rximr.a, 3<<8, 0);
 
-		p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 00 */
-		p->fdi->txctl.v |= 1<<10;	/* auto train enable */
-		p->fdi->txctl.v |= 1<<31;	/* enable */
-		loadreg(igfx, p->fdi->txctl);
+			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern1 */
+			p->fdi->rxctl.v |= 1<<31;	/* enable */
+			loadreg(igfx, p->fdi->rxctl);
 
-		/* wait for link training done */
-		for(i=0; i<200; i++){
+			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern1 */
+			p->fdi->txctl.v |= 1<<31;	/* enable */
+			loadreg(igfx, p->fdi->txctl);
+
+			/* wait for bit lock */
+			for(i=0; i<10; i++){
+				sleep(1);
+				if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
+					break;
+			}
+			csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
+	
+			/* switch to link train pattern2 */
+			csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
+			csr(igfx, p->fdi->txctl.a, 3<<8, 1<<8);
+
+			/* wait for symbol lock */
+			for(i=0; i<10; i++){
+				sleep(1);
+				if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
+					break;
+			}
+			csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
+
+			/* switch to link train normal */
+			csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
+			csr(igfx, p->fdi->txctl.a, 0, 3<<8);
+
+			/* wait idle pattern time */
 			sleep(5);
-			if(rr(igfx, p->fdi->txctl.a) & 2)
-				break;
+		} else {
+			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 00 */
+			p->fdi->rxctl.v |= 1<<10;	/* auto train enable */
+			p->fdi->rxctl.v |= 1<<31;	/* enable */
+			loadreg(igfx, p->fdi->rxctl);
+
+			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 00 */
+			p->fdi->txctl.v |= 1<<10;	/* auto train enable */
+			p->fdi->txctl.v |= 1<<31;	/* enable */
+			loadreg(igfx, p->fdi->txctl);
+
+			/* wait for link training done */
+			for(i=0; i<200; i++){
+				sleep(5);
+				if(rr(igfx, p->fdi->txctl.a) & 2)
+					break;
+			}
 		}
 	}
 


--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 10:20               ` cinap_lenrek
@ 2016-07-28 11:34                 ` kokamoto
  2016-07-28 13:31                   ` cinap_lenrek
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-28 11:34 UTC (permalink / raw)
  To: 9front

> theres what the linux driver does for SNB fdi link training, conforming to
> the documentation:
> 
> http://lxr.free-electrons.com/source/drivers/gpu/drm/i915/intel_display.c#L3419

It's very hard to me to read linux sources...
abstruction, abstruction, abstruction, abstruction, abstruction

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28 10:03               ` cinap_lenrek
@ 2016-07-28 11:31                 ` kokamoto
  2016-07-28 13:26                   ` cinap_lenrek
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-28 11:31 UTC (permalink / raw)
  To: 9front


> - Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled.
> - Wait for FDI training pattern 1 time
> - Read PCH FDI Receiver ISR for bit lock in bit 8 (retry at least once if no lock)
> - Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver
> - Wait for FDI training pattern 2 time
> - Read PCH FDI Receiver ISR for symbol lock in bit 9 (retry at least once if no lock)
> - Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver
> - Wait for FDI idle pattern time for link to become active

I had intended to follow those lines, because I had no other guides for this.
Maybe I made something wrong?

Kenji

PS.  I'm now facing a problem to have a stable 1680x1050x32.
At present I have no clue on this...



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28  0:39             ` kokamoto
  2016-07-28 10:03               ` cinap_lenrek
@ 2016-07-28 10:20               ` cinap_lenrek
  2016-07-28 11:34                 ` kokamoto
  1 sibling, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-07-28 10:20 UTC (permalink / raw)
  To: 9front

theres what the linux driver does for SNB fdi link training, conforming to
the documentation:

http://lxr.free-electrons.com/source/drivers/gpu/drm/i915/intel_display.c#L3419

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28  0:39             ` kokamoto
@ 2016-07-28 10:03               ` cinap_lenrek
  2016-07-28 11:31                 ` kokamoto
  2016-07-28 10:20               ` cinap_lenrek
  1 sibling, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-07-28 10:03 UTC (permalink / raw)
  To: 9front

>> given that we do normal link training afterwards, i wonder
>> if this code is needed. i'll check what the manual says
>> on this...
>
> without that code, SNB diesn't work,
>
> Kenji

can you still try implementing it according to the documentation?
the documentation says explicitely that we have to enable FDI
with training pattern 1. and the modeset sequence gives explicit
instructions on how todo it for sandy bridge.

from https://01.org/sites/default/files/documentation/snb_ihd_os_vol3_part3.pdf
page 117 FDI_RX_CTL:

Link_training_pattern_enable 
Project: All 
Default Value:                   0b                                 
These bits are used for link initialization.  Please 
note that the link must first be configured prior to 
sending training patterns 
When enabling the port, it must be turned on with pattern 1 enabled.
When retraining, the port must be disabled, then re-enabled with
pattern 1 enabled.

modset sequence for FDI:

- Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled.
- Wait for FDI training pattern 1 time
- Read PCH FDI Receiver ISR for bit lock in bit 8 (retry at least once if no lock)
- Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver
- Wait for FDI training pattern 2 time
- Read PCH FDI Receiver ISR for symbol lock in bit 9 (retry at least once if no lock)
- Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver
- Wait for FDI idle pattern time for link to become active

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-28  2:19             ` kokamoto
@ 2016-07-28  9:28               ` cinap_lenrek
  0 siblings, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-28  9:28 UTC (permalink / raw)
  To: 9front

>> i propose you change the code to:
>> 
>> 		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
>> 		p->fdi->txctl.v &= ~(1<<31);	/* disable */
>> 		p->fdi->txctl.v |= (1<<14);	/* DMI link reversal strap RO bit */
>> 		loadreg(igfx, p->fdi->txctl);
>> 		sleep(5);
>> 
>> and see if this still works. can you do that?
>
>I did it, and yes, it works.
>
>Kenji

ok, very good... this works on my ivy bridge machine as well :-)

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 19:30           ` cinap_lenrek
  2016-07-28  0:37             ` kokamoto
@ 2016-07-28  2:19             ` kokamoto
  2016-07-28  9:28               ` cinap_lenrek
  1 sibling, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-28  2:19 UTC (permalink / raw)
  To: 9front


> i propose you change the code to:
> 
> 		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
> 		p->fdi->txctl.v &= ~(1<<31);	/* disable */
> 		p->fdi->txctl.v |= (1<<14);	/* DMI link reversal strap RO bit */
> 		loadreg(igfx, p->fdi->txctl);
> 		sleep(5);
> 
> and see if this still works. can you do that?

I did it, and yes, it works.

Kenji

PS. s2231wA monitor(1680x1050x32) problem is vsync/hsync
polarity miss mach, probably.



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 21:41           ` cinap_lenrek
  2016-07-27 21:52             ` cinap_lenrek
@ 2016-07-28  0:44             ` kokamoto
  1 sibling, 0 replies; 51+ messages in thread
From: kokamoto @ 2016-07-28  0:44 UTC (permalink / raw)
  To: 9front

> 		if(igfx->pci->did == 0x0152)	/* 2nd/3rd Gen Core - Core-i3 */
> 			igfx->cdclk = 350;	/* MHz */
> 		else
> 			igfx->cdclk = 400;	/* MHz */
> 
> where did you got the 350 MHz cdclk value from? the documentation from
> https://01.org/sites/default/files/documentation/ivb_ihd_os_vol3_part3.pdf
> states: "On Ivybridge the core display clock frequency is 400 MHz".
> 
> also, where did you got the 667 MHz value for G45 from?
> 
> 		if(igfx->pci->did == 0x29a2)		/*  82P965/G965 HECI desktop  */
> 			igfx->cdclk = 667;	/* MHz */
> 		else
> 			igfx->cdclk = 200;	/* MHz */

Don't take those seriously.
I tried many aspects, and those are the remnants...
Please remember, this codes are personal one, not aimed to
show many others...

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 20:01           ` cinap_lenrek
  2016-07-27 22:37             ` cinap_lenrek
@ 2016-07-28  0:39             ` kokamoto
  2016-07-28 10:03               ` cinap_lenrek
  2016-07-28 10:20               ` cinap_lenrek
  1 sibling, 2 replies; 51+ messages in thread
From: kokamoto @ 2016-07-28  0:39 UTC (permalink / raw)
  To: 9front

> given that we do normal link training afterwards, i wonder
> if this code is needed. i'll check what the manual says
> on this...

without that code, SNB diesn't work,

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 19:30           ` cinap_lenrek
@ 2016-07-28  0:37             ` kokamoto
  2016-07-28  2:19             ` kokamoto
  1 sibling, 0 replies; 51+ messages in thread
From: kokamoto @ 2016-07-28  0:37 UTC (permalink / raw)
  To: 9front

> - 		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
> - 		p->fdi->txctl.v &= ~(1<<31);
> - 		p->fdi->rxctl.v |= (1<<14);	/* enable pll */
> - 		loadreg(igfx, p->fdi->txctl);
> - 		sleep(5);
> + 		if(igfx->type == TypeSNB){	/* K.Okamoto */	
> + 			p->fdi->txctl.v |= (1<<14);	/* enable FDI pll K.Okamoto */
> + 			loadreg(igfx, p->fdi->txctl);
> + 			sleep(5);
> + 		}else{
> + 			p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
> + 			p->fdi->txctl.v &= ~(1<<31);	/* disable */
> + 			p->fdi->rxctl.v |= (1<<14);	/* DMI link reversal strap RO bit */
> + 			loadreg(igfx, p->fdi->txctl);
> + 			sleep(5);
> + 		}
> 
> this is interesting... in SNB code, you set txtctl bit 14, but
> in my previous code i set *RX*ctl bit 14, which is not even used
> because it is never written to hardware afterwards. so i wonder
> if the special case for SNB is actually needed... given that this
> looks like a typo on my side but it apparently has no problems
> on my IVY bridge machine.

I'm now ignorant of TypeIVB(I have no haerware), so there may be some faults.
I just tried to use TypeSNB, because I still have no clear view of the igfx.c. :-)
So, I expect you can incorporate with my code, and write better one.

> i propose you change the code to:
> 
> 		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
> 		p->fdi->txctl.v &= ~(1<<31);	/* disable */
> 		p->fdi->txctl.v |= (1<<14);	/* DMI link reversal strap RO bit */
> 		loadreg(igfx, p->fdi->txctl);
> 		sleep(5);
> 
> and see if this still works. can you do that?

Before it, I noticed the my code doen't work for my another display
(s2231wA, 1680x1050x32), and I'm now working for it.
If it could finish, I will try it.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 20:01           ` cinap_lenrek
@ 2016-07-27 22:37             ` cinap_lenrek
  2016-07-28  0:39             ` kokamoto
  1 sibling, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-27 22:37 UTC (permalink / raw)
  To: 9front

ok, documentation says:

- Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled.
- Wait for FDI training pattern 1 time
- Read PCH FDI Receiver ISR for bit lock in bit 8 (retry at least once if no lock)
- Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver
- Wait for FDI training pattern 2 time
- Read PCH FDI Receiver ISR for symbol lock in bit 9 (retry at least once if no lock)
- Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver
- Wait for FDI idle pattern time for link to become active

but your change starts with training pattern 2 and then does training pattern 1
in auto train mode.

so it eigther works with auto training with pattern1 only or we change it to the
right sequence running pattern1 then pattern2 then idle pattern.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 21:41           ` cinap_lenrek
@ 2016-07-27 21:52             ` cinap_lenrek
  2016-07-28  0:44             ` kokamoto
  1 sibling, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-27 21:52 UTC (permalink / raw)
  To: 9front

hm, given that the cdclk is only used for dpauxctl, which
G45 does not have it does not matter at all. so that gets
rid of igfx->cdclk = 667;	/* MHz */

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 13:24         ` kokamoto
                             ` (3 preceding siblings ...)
  2016-07-27 21:18           ` cinap_lenrek
@ 2016-07-27 21:41           ` cinap_lenrek
  2016-07-27 21:52             ` cinap_lenrek
  2016-07-28  0:44             ` kokamoto
  4 siblings, 2 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-27 21:41 UTC (permalink / raw)
  To: 9front

		if(igfx->pci->did == 0x0152)	/* 2nd/3rd Gen Core - Core-i3 */
			igfx->cdclk = 350;	/* MHz */
		else
			igfx->cdclk = 400;	/* MHz */

where did you got the 350 MHz cdclk value from? the documentation from
https://01.org/sites/default/files/documentation/ivb_ihd_os_vol3_part3.pdf
states: "On Ivybridge the core display clock frequency is 400 MHz".

also, where did you got the 667 MHz value for G45 from?

		if(igfx->pci->did == 0x29a2)		/*  82P965/G965 HECI desktop  */
			igfx->cdclk = 667;	/* MHz */
		else
			igfx->cdclk = 200;	/* MHz */

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 13:24         ` kokamoto
                             ` (2 preceding siblings ...)
  2016-07-27 20:01           ` cinap_lenrek
@ 2016-07-27 21:18           ` cinap_lenrek
  2016-07-27 21:41           ` cinap_lenrek
  4 siblings, 0 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-27 21:18 UTC (permalink / raw)
  To: 9front

		if(igfx->type == TypeSNB) {
			csr(igfx, 0xC6200, 1<<11, 2);	/* pch ref souce & ssc enable */
			sleep(5);
		}

0xC6200 is drefctl - Diplsay Reference Clock Control Register

enablepipe() is the wrong place to play arround with
the reference clock as this function is called for each
pipe! the right place to set the value would be initdpll()
by setting igfx->drefctl.v.

the whole idea is that you program the *soft* registers
in init(), and have them only get loaded into *hardware*
from load() only.

snarf:	hardregs -> softregs
dump:	print softregs
init:	program softregs
load:	softregs -> hardregs

like:
		if(igfx->type == TypeSNB){	/* pch ref souce & ssc enable */
			igfx->drefctl.v &= ~(1<<11);
			igfx->drefctl.v |= 2;
		}

this effecively becomes igfx->drefctl.v |= 2; only because
bits 3<<11 are cleared before, so clearing 1<<11 is a non-op.

now bit 1 (1<<1) is 128MHz_SSC1(-0.5%) modulation_en, which is
not what the comment says. and it should not be enabled
unconditionally, but only when the SSC1 clock is actually used.

note that the SSC clocks are only used as a ref source for the dpll
for LVDS (PortLCD):

		/*
		 * PLL Reference Input Select:
		 * 000	DREFCLK		(default is 120 MHz) for DAC/HDMI/DVI/DP
		 * 001	Super SSC	120MHz super-spread clock
		 * 011	SSC		Spread spectrum input clock (120MHz default) for LVDS/DP
		 */
		dpll = igfx->pipe[x].fdi->dpll;
		dpll->ctrl.v &= ~(7<<13);
		dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;

the current code does the following:

- when LVDS (PortLCD) we set 120MHz_SSC_source_en to "Integrated source" (2<<11)
  and 128MHz_SSC4_modulation_en.
- for all other ports, we set 128MHz_nonspread_source_en to "Integrated source" (2<<9)
- set the reference clock input select on the dpll to the enabled reference source

the modeset sequence of SNB says just to enable the "PCH clock reference source",
which doesnt specify which clock (depends on what ports you are going to enable).

if you are interested:

https://01.org/sites/default/files/documentation/ivb_ihd_os_vol3_part4.pdf

has a diagram of the clocks on page 34. for SNB this should be similar as
the drefctl register shares many settings.

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 13:24         ` kokamoto
  2016-07-27 13:42           ` kokamoto
  2016-07-27 19:30           ` cinap_lenrek
@ 2016-07-27 20:01           ` cinap_lenrek
  2016-07-27 22:37             ` cinap_lenrek
  2016-07-28  0:39             ` kokamoto
  2016-07-27 21:18           ` cinap_lenrek
  2016-07-27 21:41           ` cinap_lenrek
  4 siblings, 2 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-27 20:01 UTC (permalink / raw)
  To: 9front

+ /* from here   K.Okamoto */
+ 		if (igfx->type == TypeSNB){
+ 			for(i=0;i<10;i++){	/* ensure Receive IIR, K.Okamoto */
+ 				if(rr(igfx, 0x44008) & 1<<8)
+ 				break;
+ 			}
+ 			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 1 enable */
+ 			p->fdi->rxctl.v |= (1<<8);		/* link train pattern 2 enable */
+ 			p->fdi->rxctl.v |= 1<<31;	/* enable FDI pll */
+ 			loadreg(igfx, p->fdi->rxctl);
+ 			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 1 enable */
+ 			p->fdi->txctl.v |= (1<<8);		/* link train pattern 2 enable */
+ 			p->fdi->txctl.v |= 1<<31;	/* enable FDI pll */
+ 			loadreg(igfx, p->fdi->txctl);
+ 			for(i=0;i<10;i++){
+ 				if(rr(igfx, 0x44008) & 1<<9)	/* ensure Receive IIR, K.Okamoto */
+ 					break;
+ 			}
+ /* to here  K.Okamoto */
+ 		}

you do this before the normal link training... the only
difference is that you use taining pattern 01 and witout
auto train enable.

given that we do normal link training afterwards, i wonder
if this code is needed. i'll check what the manual says
on this...

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 13:24         ` kokamoto
  2016-07-27 13:42           ` kokamoto
@ 2016-07-27 19:30           ` cinap_lenrek
  2016-07-28  0:37             ` kokamoto
  2016-07-28  2:19             ` kokamoto
  2016-07-27 20:01           ` cinap_lenrek
                             ` (2 subsequent siblings)
  4 siblings, 2 replies; 51+ messages in thread
From: cinap_lenrek @ 2016-07-27 19:30 UTC (permalink / raw)
  To: 9front

- 		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
- 		p->fdi->txctl.v &= ~(1<<31);
- 		p->fdi->rxctl.v |= (1<<14);	/* enable pll */
- 		loadreg(igfx, p->fdi->txctl);
- 		sleep(5);
+ 		if(igfx->type == TypeSNB){	/* K.Okamoto */	
+ 			p->fdi->txctl.v |= (1<<14);	/* enable FDI pll K.Okamoto */
+ 			loadreg(igfx, p->fdi->txctl);
+ 			sleep(5);
+ 		}else{
+ 			p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
+ 			p->fdi->txctl.v &= ~(1<<31);	/* disable */
+ 			p->fdi->rxctl.v |= (1<<14);	/* DMI link reversal strap RO bit */
+ 			loadreg(igfx, p->fdi->txctl);
+ 			sleep(5);
+ 		}

this is interesting... in SNB code, you set txtctl bit 14, but
in my previous code i set *RX*ctl bit 14, which is not even used
because it is never written to hardware afterwards. so i wonder
if the special case for SNB is actually needed... given that this
looks like a typo on my side but it apparently has no problems
on my IVY bridge machine.

i propose you change the code to:

		p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
		p->fdi->txctl.v &= ~(1<<31);	/* disable */
		p->fdi->txctl.v |= (1<<14);	/* DMI link reversal strap RO bit */
		loadreg(igfx, p->fdi->txctl);
		sleep(5);

and see if this still works. can you do that?

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27 13:24         ` kokamoto
@ 2016-07-27 13:42           ` kokamoto
  2016-07-27 19:30           ` cinap_lenrek
                             ` (3 subsequent siblings)
  4 siblings, 0 replies; 51+ messages in thread
From: kokamoto @ 2016-07-27 13:42 UTC (permalink / raw)
  To: 9front

addition.
my /lib/vgadb file is as follows:
ctlr
	vid=0x8086 did=0x0102	# Intel 2nd Gen Core		<=== here
	vid=0x8086 did=0x0166	# Intel 3rd Gen Core
	vid=0x8086 did=0x0152	# Intel 3rd Gen Core-i3 desktop
	vid=0x8086 did=0x2a42	# Intel 4 Series Mobile
	vid=0x8086 did=0x2a02	# Intel GM965/GL960/X3100
	vid=0x8086 did=0x29a2	# 82P965/G965 HECI desktop
	link=vga
	hwgc=igfxhwgc
	ctlr=igfx linear=1
		.....
#
# Iiyama E1780SD
#
E1780SD=1280x1024		# 60Hz
	clock=108
	shb=1328 ehb=1440 ht=1688
	vrs=1025 vre=1028 vt=1066
	hsync=+ vsync=+ 

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27  9:57       ` cinap_lenrek
@ 2016-07-27 13:24         ` kokamoto
  2016-07-27 13:42           ` kokamoto
                             ` (4 more replies)
  0 siblings, 5 replies; 51+ messages in thread
From: kokamoto @ 2016-07-27 13:24 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 752 bytes --]

Ok, I included /sys/src/cmd/aux/vga/jgfx.c and /sys/src/9/pc/vgaigfx.c.
Many pesonal comments, though some of them might be my miss-understasnding.
If so, please forget them.
Many A<<0xFF like lines might not be neccessary, however, some of them
are definitely important.

Present patch isn't aimed to use for DP connector, because I have
no DP input monitor here.  I tried DP->HDMI connector, but failed.
I have no motivation for it, sorry.

my /cfg/pxe/XXXXXX is as follows:
#Core-i5 Dell Optiflex 790 desktop (Sandy-bridge)
bootargs=tcp
bootfile=/386/9pcf
nobootprompt=tcp
mouseport=usb
monitor=E1780SD
display=1
vgasize=1280x1024x32

Kenji

PS. this mail is written on the new sandy-bridge machine, and
posted its sysinfo to the 9front's web site.

[-- Attachment #2: Type: text/plain, Size: 50981 bytes --]

#include <u.h>
#include <libc.h>
#include <bio.h>

#include "pci.h"
#include "vga.h"

typedef struct Reg Reg;
typedef struct Dpll Dpll;
typedef struct Hdmi Hdmi;
typedef struct Dp Dp;
typedef struct Fdi Fdi;
typedef struct Pfit Pfit;
typedef struct Curs Curs;
typedef struct Plane Plane;
typedef struct Trans Trans;
typedef struct Pipe Pipe;
typedef struct Igfx Igfx;

enum {
	MHz = 1000000,
};

enum {
	TypeG45,
	TypeIVB,		/* Ivy Bridge */
	TypeSNB,		/* Sandy Bridge (unfinished) */
};

enum {
	PortVGA	= 0,		/* adpa */
	PortLCD	= 1,		/* lvds */
	PortDPA	= 2,
	PortDPB	= 3,
	PortDPC	= 4,
	PortDPD	= 5,
};

struct Reg {
	u32int	a;		/* address or 0 when invalid */
	u32int	v;		/* value */
};

struct Dpll {
	Reg	ctrl;		/* DPLLx_CTRL */
	Reg	fp0;		/* FPx0 */
	Reg	fp1;		/* FPx1 */
};

struct Trans {
	Reg	dm[2];		/* pipe/trans DATAM */
	Reg	dn[2];		/* pipe/trans DATAN */
	Reg	lm[2];		/* pipe/trans LINKM */
	Reg	ln[2];		/* pipe/trans LINKN */

	Reg	ht;		/* pipe/trans HTOTAL_x */
	Reg	hb;		/* pipe/trans HBLANK_x */
	Reg	hs;		/* pipe/trans HSYNC_x */
	Reg	vt;		/* pipe/trans VTOTAL_x */
	Reg	vb;		/* pipe/trans VBLANK_x */
	Reg	vs;		/* pipe/trans VSYNC_x */
	Reg	vss;		/* pipe/trans VSYNCSHIFT_x */

	Reg	conf;		/* pipe/trans CONF_x */
	Reg	chicken;	/* workarround register */

	Reg	dpctl;		/* TRANS_DP_CTL_x */

	Dpll	*dpll;		/* this transcoders dpll */
};

struct Hdmi {
	Reg	ctl;
	Reg	bufctl[4];
};

struct Dp {
	Reg	ctl;
	Reg	auxctl;
	Reg	auxdat[5];

	uchar	dpcd[256];
};

struct Fdi {
	Trans;

	Reg	txctl;		/* FDI_TX_CTL */

	Reg	rxctl;		/* FDI_RX_CTL */
	Reg	rxmisc;		/* FDI_RX_MISC */
	Reg	rxtu[2];	/* FDI_RX_TUSIZE */
};

struct Pfit {
	Reg	ctrl;
	Reg	winpos;
	Reg	winsize;
	Reg	pwrgate;
};

struct Plane {
	Reg	cntr;		/* DSPxCNTR */
	Reg	linoff;		/* DSPxLINOFF */
	Reg	stride;		/* DSPxSTRIDE */
	Reg	surf;		/* DSPxSURF */
	Reg	tileoff;	/* DSPxTILEOFF */

	Reg	pos;
	Reg	size;
};

struct Curs {
	Reg	cntr;
	Reg	base;
	Reg	pos;
};

struct Pipe {
	Trans;

	Reg	src;		/* PIPExSRC */

	Fdi	fdi[1];		/* fdi/dp transcoder */

	Plane	dsp[1];		/* display plane */
	Curs	cur[1];		/* hardware cursor */

	Pfit	*pfit;		/* selected panel fitter */
};

struct Igfx {
	Ctlr	*ctlr;
	Pcidev	*pci;

	u32int	pio;
	u32int	*mmio;

	int	type;
	int	cdclk;		/* core display clock in mhz */

	int	npipe;
	Pipe	pipe[4];

	Dpll	dpll[2];
	Pfit	pfit[3];

	/* IVB */
	Reg	dpllsel;	/* DPLL_SEL */
	Reg	drefctl;	/* DREF_CTL */
	Reg	rawclkfreq;	/* RAWCLK_FREQ */
	Reg	ssc4params;	/* SSC4_PARAMS */

	Dp	dp[4];
	Hdmi	hdmi[4];

	Reg	ppcontrol;
	Reg	ppstatus;

	/* G45 */
	Reg	gmbus[6];	/* GMBUSx */

	Reg	sdvoc;
	Reg	sdvob;

	/* common */
	Reg	adpa;
	Reg	lvds;

	Reg	vgacntrl;
};

static u32int
rr(Igfx *igfx, u32int a)
{
	if(a == 0)
		return 0;
	assert((a & 3) == 0);
	if(igfx->mmio != nil)
		return igfx->mmio[a/4];
	outportl(igfx->pio, a);
	return inportl(igfx->pio + 4);
}
static void
wr(Igfx *igfx, u32int a, u32int v)
{
	if(a == 0)	/* invalid */
		return;
	assert((a & 3) == 0);
	if(igfx->mmio != nil){
		igfx->mmio[a/4] = v;
		return;
	}
	outportl(igfx->pio, a);
	outportl(igfx->pio + 4, v);
}
static void
csr(Igfx *igfx, u32int reg, u32int clr, u32int set)
{
	wr(igfx, reg, (rr(igfx, reg) & ~clr) | set);
}

static void
loadreg(Igfx *igfx, Reg r)
{
	wr(igfx, r.a, r.v);
}

static Reg
snarfreg(Igfx *igfx, u32int a)
{
	Reg r;

	r.a = a;
	r.v = rr(igfx, a);
	return r;
}


/* South Display Engine */
static void
snarftrans(Igfx *igfx, Trans *t, u32int o)
{
	/* pipe timing */
	/* for TypeG45 o=0x60000+x*0x1000
		for TypeSNB, TypeIVB o=0xE0000+x*0x1000 */
	t->ht	= snarfreg(igfx, o + 0x00000);		/* HTOTAL */
	t->hb	= snarfreg(igfx, o + 0x00004);		/* HBLANK */
	t->hs	= snarfreg(igfx, o + 0x00008);		/* HSYNC */
	t->vt	= snarfreg(igfx, o + 0x0000C);		/* VTOTAL */
	t->vb	= snarfreg(igfx, o + 0x00010);		/* VBLANK */
	t->vs	= snarfreg(igfx, o + 0x00014);		/* VSYNC */
	t->vss	= snarfreg(igfx, o + 0x00028);		/* VSYNCSHIFT for interlaced */

	/* copy PIPEA_CONF for G45[70008], TRANS_CONF[F0008] for Sandy Ivy Bridge */
	t->conf	= snarfreg(igfx, o + 0x10008);

	switch(igfx->type){
	case TypeG45:
		if(t == &igfx->pipe[0]){			/* PIPEA */
			t->dm[0] = snarfreg(igfx, 0x70050);	/* GMCHDataM */
			t->dn[0] = snarfreg(igfx, 0x70054);	/* GMCHDataN */
			t->lm[0] = snarfreg(igfx, 0x70060);	/* DPLinkM */
			t->ln[0] = snarfreg(igfx, 0x70064);	/* DPLinkN */
		}
		break;
	case TypeIVB:
	case TypeSNB:
		t->dm[0] = snarfreg(igfx, o + 0x30);		/* Data M1 value (transcoder A) */
		t->dn[0] = snarfreg(igfx, o + 0x34);		/* Data N value (transcoder A) */
		t->dm[1] = snarfreg(igfx, o + 0x38);		/* Data M2 value (transcoder A) */
//		t->dn[1] = snarfreg(igfx, o + 0x3c);		/* Data N2 value (transcoder A */
		t->dn[1] = snarfreg(igfx, o + 0x3C);		/* Data N2 value (transcoder A */
		t->lm[0] = snarfreg(igfx, o + 0x40);		/* Data Link M1 value (transcoder A) */
		t->ln[0] = snarfreg(igfx, o + 0x44);		/* Data Link N1 value (transcoder A) */
		t->lm[1] = snarfreg(igfx, o + 0x48);		/* Data Link M2 value (transcoder A) */
//		t->ln[1] = snarfreg(igfx, o + 0x4c);		/* Data Link N2 value (transcoder A) */
		t->ln[1] = snarfreg(igfx, o + 0x4C);		/* Data Link N2 value (transcoder A) */
		break;
	}
}

/* North Display pipe to CPU */
static void
snarfpipe(Igfx *igfx, int x)
{
	u32int o;
	Pipe *p;

	p = &igfx->pipe[x];

	o = 0x60000 + x*0x1000;
	snarftrans(igfx, p, o);	/* HTOTAL Horizontal Total */

	p->src = snarfreg(igfx, o + 0x0001C);	/* SRCSZ source image size */

	if(igfx->type == TypeIVB || igfx->type == TypeSNB) {
		p->fdi->txctl = snarfreg(igfx, o + 0x100);	/* FDI_TX_CTL */

//		/* pipe config for TypeSNB and TypeIVB added by K.Okamoto*/
//		p->conf	= snarfreg(igfx, 0x70008+x*0x1000);
		o = 0xE0000 | x*0x1000;
		snarftrans(igfx, p->fdi, o);

		/* display port control */
		p->fdi->dpctl = snarfreg(igfx, o + 0x300);	/* TRANS_DP_CTL[AB..]

//		p->fdi->rxctl = snarfreg(igfx, o + 0x1000c);	/* FDI_RX[AB..]_CTL */
		p->fdi->rxctl = snarfreg(igfx, o + 0x1000C);	/* FDI_RX[AB..]_CTL */
		p->fdi->rxmisc = snarfreg(igfx, o + 0x10010);	/* FDI_RX[AB..]_MISC */
		p->fdi->rxtu[0] = snarfreg(igfx, o + 0x10030);	/* FDI_RX[AB..]_TUSIZE1 */
		p->fdi->rxtu[1] = snarfreg(igfx, o + 0x10038);	/* FDI_RX[AB..]_TUSIZE2 */

		p->fdi->chicken = snarfreg(igfx, o + 0x10064);	/* TRANS[AB..]_CHIKEN2 */

		p->fdi->dpll = &igfx->dpll[(igfx->dpllsel.v>>(x*4)) & 1];		/* DPLL_A(0) or B(1) */
		p->dpll = nil;
	} else {
		p->dpll = &igfx->dpll[x & 1];
	}

	/* display plane */
	p->dsp->cntr		= snarfreg(igfx, 0x70180 + x*0x1000);	/* dsp [AB] cntrl */
	p->dsp->linoff		= snarfreg(igfx, 0x70184 + x*0x1000);	/* dsp [AB] address */
	p->dsp->stride	= snarfreg(igfx, 0x70188 + x*0x1000);
	p->dsp->tileoff	= snarfreg(igfx, 0x701A4 + x*0x1000);	/* 965+ only */
	p->dsp->surf		= snarfreg(igfx, 0x7019C + x*0x1000);	/* 965+ only */

	/* cursor plane */
	switch(igfx->type){
//	case TypeSNB:		/* K.Okamoto */
	case TypeIVB:
		p->cur->cntr	= snarfreg(igfx, 0x70080 + x*0x1000);
		p->cur->base	= snarfreg(igfx, 0x70084 + x*0x1000);
		p->cur->pos	= snarfreg(igfx, 0x70088 + x*0x1000);
		break;
	case TypeSNB:		/* K.Okamoto */
		p->cur->cntr	= snarfreg(igfx, 0x70080 + x*0x40);	/* cursol control */
		p->cur->base	= snarfreg(igfx, 0x70084 + x*0x40);	/* cursol base address */
		p->cur->pos	= snarfreg(igfx, 0x70088 + x*0x40);	/* Cursol Position */
		break;
	case TypeG45:
		p->dsp->pos	= snarfreg(igfx, 0x7018C + x*0x1000);
		p->dsp->size	= snarfreg(igfx, 0x70190 + x*0x1000);

		p->cur->cntr	= snarfreg(igfx, 0x70080 + x*0x40);
		p->cur->base	= snarfreg(igfx, 0x70084 + x*0x40);
		p->cur->pos	= snarfreg(igfx, 0x70088 + x*0x40);
		break;
	}
}

static int
devtype(Igfx *igfx)
{
	if(igfx->pci->vid != 0x8086)
		return -1;
	switch(igfx->pci->did){
	case 0x0166:	/* 3rd Gen Core - ThinkPad X230 */
	case 0x0152:	/* 2nd/3rd Gen Core - Core-i3 */
		return TypeIVB;
	case 0x0102:	/* Dell Optiplex 790 */
	case 0x0126:	/* Thinkpad X220 */
		return TypeSNB;
	case 0x27a2:	/* GM945/82940GML - ThinkPad X60 Tablet */
	case 0x29a2:	/* 82P965/G965 HECI desktop */
	case 0x2a02:	/* GM965/GL960/X3100 - ThinkPad X61 Tablet */
	case 0x2a42:	/* 4 Series Mobile - ThinkPad X200 */
		return TypeG45;
	}
	return -1;
}

static Edid* snarfgmedid(Igfx*, int port, int addr);
static Edid* snarfdpedid(Igfx*, Dp *dp, int addr);

static int enabledp(Igfx*, Dp*);

static void
snarf(Vga* vga, Ctlr* ctlr)
{
	Igfx *igfx;
	int x, y;

	igfx = vga->private;
	if(igfx == nil) {
		igfx = alloc(sizeof(Igfx));
		igfx->ctlr = ctlr;
		igfx->pci = vga->pci;
		if(igfx->pci == nil){
			error("%s: no pci device\n", ctlr->name);
			return;
		}
		igfx->type = devtype(igfx);
		if(igfx->type < 0){
			error("%s: unrecognized device\n", ctlr->name);
			return;
		}
		vgactlpci(igfx->pci);
		if(1){
			vgactlw("type", ctlr->name);
			igfx->mmio = segattach(0, "igfxmmio", 0, igfx->pci->mem[0].size);
			if(igfx->mmio == (u32int*)-1)
				error("%s: attaching mmio: %r\n", ctlr->name);
		} else {
			if((igfx->pci->mem[4].bar & 1) == 0)
				error("%s: no pio bar\n", ctlr->name);
			igfx->pio = igfx->pci->mem[4].bar & ~1;
		}
		vga->private = igfx;
	}

	switch(igfx->type){
	case TypeG45:
		igfx->npipe = 2;	/* A,B */
		if(igfx->pci->did ==0x29a2)		/* K.Okamoto */
			igfx->cdclk = 667;	/* MHz */
		else
			igfx->cdclk = 200;	/* MHz */
		igfx->dpll[0].ctrl	= snarfreg(igfx, 0x06014);
		igfx->dpll[0].fp0	= snarfreg(igfx, 0x06040);
		igfx->dpll[0].fp1	= snarfreg(igfx, 0x06044);
		igfx->dpll[1].ctrl	= snarfreg(igfx, 0x06018);
		igfx->dpll[1].fp0	= snarfreg(igfx, 0x06048);
		igfx->dpll[1].fp1	= snarfreg(igfx, 0x0604c);

		igfx->adpa		= snarfreg(igfx, 0x061100);
		igfx->lvds		= snarfreg(igfx, 0x061180);
		igfx->sdvob		= snarfreg(igfx, 0x061140);
		igfx->sdvoc		= snarfreg(igfx, 0x061160);

		for(x=0; x<5; x++)
			igfx->gmbus[x]	= snarfreg(igfx, 0x5100 + x*4);
		igfx->gmbus[x]	= snarfreg(igfx, 0x5120);		/* 2-byte INDEX reg */

		igfx->pfit[0].ctrl	= snarfreg(igfx, 0x061230);
		y = (igfx->pfit[0].ctrl.v >> 29) & 3;	/* select pipe to be fitted */
		if(igfx->pipe[y].pfit == nil)
			igfx->pipe[y].pfit = &igfx->pfit[0];

		igfx->ppstatus		= snarfreg(igfx, 0x61200);	/* DevCL only */
		igfx->ppcontrol	= snarfreg(igfx, 0x61204);	/* DevCL only */

		igfx->vgacntrl		= snarfreg(igfx, 0x071400);
		break;

	case TypeSNB:
		igfx->npipe = 2;	/* A,B */
		igfx->cdclk = 300;	/* Core Display Clock MHz */
		goto PCHcommon;

	case TypeIVB:
		igfx->npipe = 3;	/* A,B,C */
		if(igfx->pci->did ==0x0152)		/* K.Okamoto */
			igfx->cdclk = 350;	/* MHz */
		else
			igfx->cdclk = 400;	/* MHz */

	PCHcommon:
		igfx->dpll[0].ctrl	= snarfreg(igfx, 0xC6014);	/* DPLL_CTL_A */
		igfx->dpll[0].fp0	= snarfreg(igfx, 0xC6040);	/* DPLL_FP0_A */
		igfx->dpll[0].fp1	= snarfreg(igfx, 0xC6044);	/* DPLL_FP1_A */
		igfx->dpll[1].ctrl	= snarfreg(igfx, 0xC6018);	/* DPLL_CTL */
		igfx->dpll[1].fp0	= snarfreg(igfx, 0xC6048);	/* DPLL_FP0_B */
//		igfx->dpll[1].fp1	= snarfreg(igfx, 0xC604c);	/* DPLL_FP1_B */
		igfx->dpll[1].fp1	= snarfreg(igfx, 0xC604C);	/* DPLL_FP1_B */

		igfx->dpllsel		= snarfreg(igfx, 0xC7000);	/* DPLL_SEL */

		igfx->drefctl		= snarfreg(igfx, 0xC6200);	/* DREF_CTL */
		igfx->rawclkfreq	= snarfreg(igfx, 0xC6204);	/* RAWCLK_FREQ */
		igfx->ssc4params	= snarfreg(igfx, 0xC6210);	/* SSC4_PARNS */

		/* cpu displayport A */
		igfx->dp[0].ctl		= snarfreg(igfx, 0x64000);	/* DP_CTL */
		igfx->dp[0].auxctl	= snarfreg(igfx, 0x64010);	/* DP_AUX_CTL */
		igfx->dp[0].auxdat[0]	= snarfreg(igfx, 0x64014);	/* DP_AUX_DATA1 */
		igfx->dp[0].auxdat[1]	= snarfreg(igfx, 0x64018);	/* DP_AUX_DATA2 */
		igfx->dp[0].auxdat[2]	= snarfreg(igfx, 0x6401C);	/* DP_AUX_DATA3 */
		igfx->dp[0].auxdat[3]	= snarfreg(igfx, 0x64020);	/* DP_AUX_DATA4 */
		igfx->dp[0].auxdat[4]	= snarfreg(igfx, 0x64024);	/* DP_AUX_DATA5 */

		/* pch displayport B,C,D */
		for(x=1; x<4; x++){
			igfx->dp[x].ctl		= snarfreg(igfx, 0xE4000 + 0x100*x);	/* DP_CTL_[BCD] */
			igfx->dp[x].auxctl	= snarfreg(igfx, 0xE4010 + 0x100*x);	/* DP_AUX_CTL_[BCD] */
			igfx->dp[x].auxdat[0]	= snarfreg(igfx, 0xE4014 + 0x100*x);	/* DP_AUX_DATA1_[BCD] */
			igfx->dp[x].auxdat[1]	= snarfreg(igfx, 0xE4018 + 0x100*x);	/* DP_AUX_DATA2_[BCD] */
			igfx->dp[x].auxdat[2]	= snarfreg(igfx, 0xE401C + 0x100*x);	/* DP_AUX_DATA3_[BCD] */
			igfx->dp[x].auxdat[3]	= snarfreg(igfx, 0xE4020 + 0x100*x);	/* DP_AUX_DATA4_[BCD] */
			igfx->dp[x].auxdat[4]	= snarfreg(igfx, 0xE4024 + 0x100*x);	/* DP_AUX_DATA5_[BCD] */
		}

		for(x=0; x<igfx->npipe; x++){
			igfx->pfit[x].pwrgate	= snarfreg(igfx, 0x68060 + 0x800*x);	/* PF_PWR_GATE */
			igfx->pfit[x].winpos	= snarfreg(igfx, 0x68070 + 0x800*x);	/* PF_WIN_POS */
			igfx->pfit[x].winsize	= snarfreg(igfx, 0x68074 + 0x800*x);	/* PF_WIN_SIZE */
			igfx->pfit[x].ctrl	= snarfreg(igfx, 0x68080 + 0x800*x);	/* PF_CTRL */

			y = (igfx->pfit[x].ctrl.v >> 29) & 3;	/* y=0: pipe select A, 1: B, 2: C */
			if(igfx->pipe[y].pfit == nil)
				igfx->pipe[y].pfit = &igfx->pfit[x];
		}
		igfx->ppstatus		= snarfreg(igfx, 0xC7200);	/* PP_STATUS(PanelPower) no */
		igfx->ppcontrol		= snarfreg(igfx, 0xC7204);	/* PP_CONTROL(PanelPower) 0 */

		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[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[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 */

		for(x=0; x<5; x++)
			igfx->gmbus[x]	= snarfreg(igfx, 0xC5100 + x*4);	/* GMBUS0~4 */
		igfx->gmbus[x]	= snarfreg(igfx, 0xC5120);	/* GMBUS5 0 */

		igfx->adpa		= snarfreg(igfx, 0x0E1100);	/* DAC_CTL Analog Port CRT */
		igfx->lvds		= snarfreg(igfx, 0x0E1180);	/* LVDS_CTL */

		igfx->vgacntrl		= snarfreg(igfx, 0x041000);	/* VGA_CONTROL */
		break;
	}
	for(x=0; x<igfx->npipe; x++)
		snarfpipe(igfx, x);

	for(x=0; x<nelem(vga->edid); x++){
		Modelist *l;

		switch(x){
		case PortVGA:
			vga->edid[x] = snarfgmedid(igfx, 2, 0x50);
			break;
		case PortLCD:
			vga->edid[x] = snarfgmedid(igfx, 3, 0x50);
			if(vga->edid[x] == nil)
				continue;
			for(l = vga->edid[x]->modelist; l != nil; l = l->next)
				l->attr = mkattr(l->attr, "lcd", "1");
			break;
		case PortDPA:
		case PortDPB:
		case PortDPC:
		case PortDPD:
			vga->edid[x] = snarfdpedid(igfx, &igfx->dp[x-PortDPA], 0x50);
			break;
		}
		if(vga->edid[x] == nil)
			continue;
		for(l = vga->edid[x]->modelist; l != nil; l = l->next)
			l->attr = mkattr(l->attr, "display", "%d", x+1);
	}

	ctlr->flag |= Fsnarf;
}

static void
options(Vga* vga, Ctlr* ctlr)
{
	USED(vga);
	ctlr->flag |= Hlinear|Ulinear|Foptions;
}

//  freq = (cref * 5 * (m1+2)+(m2+2))/(n + 2)/(p1*p2)
static int
genpll(int freq, int cref, int P2, int *m1, int *m2, int *n, int *p1)
{
	int M1, M2, M, N, P, P1;
	int best, error;
	vlong a;

	best = -1;
	for(N=3; N<=8; N++)
	for(M2=5; M2<=9; M2++)
//	for(M1=10; M1<=20; M1++){
	for(M1=12; M1<=22; M1++){
		M = 5*(M1+2) + (M2+2);
		if(M < 79 || M > 127)
//		if(M < 70 || M > 120)
			continue;
		for(P1=1; P1<=8; P1++){
			P = P1 * P2;
			if(P < 5 || P > 98)
//			if(P < 4 || P > 98)
				continue;
			a = cref;
			a *= M;
			a /= N+2;
			a /= P;
			if(a < 20*MHz || a > 400*MHz)
				continue;
			error = a;
			error -= freq;
			if(error < 0)
				error = -error;
			if(best < 0 || error < best){
				best = error;
				*m1 = M1;
				*m2 = M2;
				*n = N;
				*p1 = P1;
			}
		}
	}

//print("freq=%lld, cref=%d, m1=%ud, m2=%ud, n=%ud,p1=%ud,p2=%ud\n", a, cref, *m1,*m2,*n,*p1,P2);	/* K.Okamoto */
//print("fitted frequncy = %d\n", (uvlong)cref*(5*(*m1+2)+(*m2+2))/(*n+2)/(*p1*P2));

	return best;
}

static int
getcref(Igfx *igfx, int x)
{
	Dpll *dpll;

	dpll = &igfx->dpll[x];
	if(igfx->type == TypeG45){
		if(((dpll->ctrl.v >> 13) & 3) == 3)
			return 100*MHz;
		return 96*MHz;
	}
	return 120*MHz;
}

static int
initdpll(Igfx *igfx, int x, int freq, int port)
{
	int cref, m1, m2, n, p1, p2;
	Dpll *dpll;

	switch(igfx->type){
	case TypeG45:
		/* PLL Reference Input Select */
		dpll = igfx->pipe[x].dpll;
		dpll->ctrl.v &= ~(3<<13);
		dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
		break;
	case TypeSNB:
	case TypeIVB:
		/* transcoder dpll enable */
		igfx->dpllsel.v |= 8<<(x*4);	/* Transcorder A(x=0)->B(x=1)->C(x=2) enable */
		/* program rawclock to 125MHz */
		igfx->rawclkfreq.v = 125;

		igfx->drefctl.v &= ~(3<<13);	/* Source output to CPU disabled */
		igfx->drefctl.v &= ~(3<<11);	/* 120MHz ssc source disabled */
		igfx->drefctl.v &= ~(3<<9);	/* 120MHz nonspread source disabled */
		igfx->drefctl.v &= ~(3<<7);	/* 120MHz superspread source disabled */
		igfx->drefctl.v &= ~3;		/* 120MHz ssc4,ssc1 modulation disabled */

		if(port == PortLCD){
			igfx->drefctl.v |= 2<<11;	/* 120MHz ssc source = integrated source enabled */
			igfx->drefctl.v |= 1;	/* 120MHz ssc1 modulation enabled */
		} else {
			igfx->drefctl.v |= 2<<9;	/* 120MHz nonspread source = integrated source enabled */
		}

		/*
		 * PLL Reference Input Select:
		 * 000	DREFCLK		(default is 120 MHz) for DAC/HDMI/DVI/DP
		 * 001	Super SSC	120MHz super-spread clock
		 * 011	SSC		Spread spectrum input clock (120MHz default) for LVDS/DP
		 */
		dpll = igfx->pipe[x].fdi->dpll;
		dpll->ctrl.v &= ~(7<<13);		/* reset reference clock input to drefclk */
		dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;	/* for LVDS ref clock input=SSC, other: drefclk */
		break;
	default:
		return -1;
	}
	cref = getcref(igfx, x);	/* cref=120MHz for TypeSNB, 96MHz for TypeG45 */

	/* Dpll Mode select */
	dpll->ctrl.v &= ~(3<<26);		/* reset DPLL Mode select */
	dpll->ctrl.v |= (port == PortLCD ? 2 : 1)<<26;	/* for LCD LVDS Mode, others: Non-LVDS */

	/* P2 Clock Divide */
	dpll->ctrl.v &= ~(3<<24);		/* reset FP1 P2 divide */
	if(port == PortLCD){
		p2 = 14;
		if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
			return -1;
	} else {
		/* generate 270MHz clock for displayport */
		if(port >= PortDPA)
			freq = 270*MHz;

		p2 = 10;
		if(freq > 270*MHz){
//		if(freq > 225*MHz){		/* K.Okamoto */
			p2 >>= 1;		/* p2 = 5 */
			dpll->ctrl.v |= (1<<24);
		}
		if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
			return -1;
	}

	/* Dpll VCO Enable */
	dpll->ctrl.v |= (1<<31);

	/* Dpll Serial DVO High Speed IO clock Enable */
	if(port >= PortDPA)
		dpll->ctrl.v |= (1<<30);
	else
		dpll->ctrl.v &= ~(1<<30);

	/* VGA Mode Disable */
	dpll->ctrl.v |= (1<<28);

//m1=14, m2=8, n=3, p1=2  K.Okamoto
// ctrl.a=c6014, dpll->fp0.a=c6048 K.Okamoto
//print("m1=%d, m2=%d, n=%d, p1=%d, p2=%d\n", m1, m2, n, p1, p2);

//	dpll->fp0.v &= ~(0x3f<<16);	/* fp0 N divisor=0 */
	dpll->fp0.v &= ~(0x3F<<16);	/* fp0 N divisor=0 */
	dpll->fp0.v |= n << 16;		/* set N divisor=3 */
//	dpll->fp0.v &= ~(0x3f<<8);	/* fp0 M1 divisor=0 */
	dpll->fp0.v &= ~(0x3F<<8);	/* fp0 M1 divisor=0 */
	dpll->fp0.v |= m1 << 8;		/* set fp0 M1 divisor=14 */
//	dpll->fp0.v &= ~(0x3f<<0);	/* fp0 M2 divisor=0 */
	dpll->fp0.v &= ~(0x3F<<0);	/* fp0 M2 divisor=0 */
	dpll->fp0.v |= m2 << 0;		/* set fp0 M2 divisor=8 */

	/* FP0 P1 Post Divisor */
	dpll->ctrl.v &= ~0xFF0000;
	dpll->ctrl.v |=  0x010000<<(p1-1);

	/* FP1 P1 Post divisor */
	if(igfx->pci->did != 0x27a2){
		dpll->ctrl.v &= ~0xFF;
		dpll->ctrl.v |=  0x01<<(p1-1);
		dpll->fp1.v = dpll->fp0.v;
	}

	return 0;
}

static void
initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
{
	u32int m, n;

	n = 0x800000;		/* 8388608 */
	m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
/* 			lsclk = 270*MHz, bpp=3*bpc, tu=64	original */
//	m = n * (((uvlong)freq * bpp/8) / ((uvlong)lsclk) * lanes);	/* following manual K.Okamoto Don't work */
/* 			lsclk = 270*MHz, bpp=4*bpc, tu=64	K.Okamoto */
	t->dm[0].v = (tu-1)<<25 | m;
	t->dn[0].v = n;

	n = 0x80000;		/* 524288 */
	m = ((uvlong)n * freq) / lsclk;

	t->lm[0].v = m;
	t->ln[0].v = n;

	t->dm[1].v = t->dm[0].v;
	t->dn[1].v = t->dn[0].v;
	t->lm[1].v = t->lm[0].v;
	t->ln[1].v = t->ln[0].v;
}

static void
inittrans(Trans *t, Mode *m)
{
	/* clear all but 27:28 frame start delay (initialized by bios) */
	t->conf.v &= 3<<27;

	/* tans/pipe enable */
	t->conf.v |= 1<<31;		/* [70008] = 0xc0000000 or [F0008] = 0xc0000000 */

	/* trans/pipe timing */
	t->ht.v = (m->ht - 1)<<16 | (m->x - 1);		/* (Htotal)xxx(Hactive) */
	t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);	/* (End of hsync)xxx(Start of hsync) */
	t->vt.v = (m->vt - 1)<<16 | (m->y - 1);		/* (Vtotal)xxx(Vactive) */
	t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);	/* (End of vsync)xxx(Start of vsync) */

	t->hb.v = t->ht.v;
//	t->hb.v = (m->ehb - 1)<<16 | (m->shb - 1);	/* K.Okamoto */
	t->vb.v = t->vt.v;
//	t->vb.v = t->vs.v;						/* K.Okamoto */
	t->vss.v = 0;
}

static void
initpipe(Pipe *p, Mode *m)
{
	static uchar bpctab[4] = { 8, 10, 6, 12 };
	int i, tu, bpc, lanes;
	Fdi *fdi;

	/* source image size */
	p->src.v = (m->x - 1)<<16 | (m->y - 1);

	if(p->pfit != nil){
		/* panel fitter off */
		p->pfit->ctrl.v &= ~(1<<31);
		p->pfit->winpos.v = 0;
		p->pfit->winsize.v = 0;
	}

	/* enable and set monitor timings for cpu pipe */
	inittrans(p, m);

	/* default for displayport */
	tu = 64;
	bpc = 6;	/* why */
//	bpc = 8;	/* for CRT K.Okamoto Don't work! */
	lanes = 1;

	fdi = p->fdi;
	if(fdi->rxctl.a != 0){		/* TypeSNB or TypeIVB */
		/* enable and set monitor timings for transcoder */
		inittrans(fdi, m);

		/* tx port width selection */
		fdi->txctl.v &= ~(7<<19);		/* x1[default] */
		fdi->txctl.v |= (lanes-1)<<19;	/* lanes=1: x1 lanes=2: x2->x3->x4 mode */

		/* rx port width selection */
		fdi->rxctl.v &= ~(7<<19);		/* port width = x1 */
		fdi->rxctl.v |= (lanes-1)<<19;	/* lanes=1: x1 mode, lanes=2: x2, lanes=3: x3, lanes=4: x4 */
		/* bits per color for transcoder */
		for(i=0; i<nelem(bpctab); i++){
			if(bpctab[i] == bpc){
				fdi->rxctl.v &= ~(7<<16);	/* 8 bpc [default] */
				fdi->rxctl.v |= i<<16;	/* change to 8->10->6->12 bps */
				fdi->dpctl.v &= ~(7<<9);	/* */
				fdi->dpctl.v |= i<<9;
				break;
			}
		}

		/* enhanced framing on */
		fdi->rxctl.v |= (1<<6);	/* enhanced framing enable */
		fdi->txctl.v |= (1<<18);	/* enhanced framing enable */

		/* tusize 1 and 2 */
		fdi->rxtu[0].v = (tu-1)<<25;	/* set tusize=tu-1 */
		fdi->rxtu[1].v = (tu-1)<<25;
		initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
//		initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 4*bpc);	/* K.Okamoto */
	}

	/* bits per color for cpu pipe */
	for(i=0; i<nelem(bpctab); i++){
		if(bpctab[i] == bpc){
			p->conf.v &= ~(7<<5);	/* set 8 bpc */
			p->conf.v |= i<<5;		/* 8->10->6->12 bpc */
			break;
		}
	}
	initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
//	initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 4*bpc);		/* K.Okamoto */
}

static void
init(Vga* vga, Ctlr* ctlr)
{
	int x, port;
	char *val;
	Igfx *igfx;
	Pipe *p;
	Mode *m;
	Reg *r;

	m = vga->mode;
	if(m->z != 32)
		error("%s: unsupported color depth %d\n", ctlr->name, m->z);

	igfx = vga->private;

	/* disable vga compatibility */
	igfx->vgacntrl.v |= (1<<31);

	/* disable all pipes and ports */
	igfx->ppcontrol.v &= 0xFFFF;
	igfx->ppcontrol.v &= ~5;
	igfx->lvds.v &= ~(1<<31);
	igfx->adpa.v &= ~(1<<31);	/* disable ADPA */
	if(igfx->type == TypeG45)
		igfx->adpa.v |= (3<<10);	/* Monitor DPMS: off disable hsync/vsync */
	for(x=0; x<nelem(igfx->dp); x++)
		igfx->dp[x].ctl.v &= ~(1<<31);
	for(x=0; x<nelem(igfx->hdmi); x++)
		igfx->hdmi[x].ctl.v &= ~(1<<31);
	for(x=0; x<igfx->npipe; x++){
		/* disable displayport transcoders */
		igfx->pipe[x].dpctl.v &= ~(1<<31);
		igfx->pipe[x].dpctl.v |= (3<<29);
		igfx->pipe[x].fdi->dpctl.v &= ~(1<<31);
		igfx->pipe[x].fdi->dpctl.v |= (3<<29);
		/* disable transcoder/pipe */
		igfx->pipe[x].conf.v &= ~(1<<31);
	}

	if((val = dbattr(m->attr, "display")) != nil)
		port = atoi(val)-1;
	else if(dbattr(m->attr, "lcd") != nil)
		port = PortLCD;
	else
		port = PortVGA;

	trace("%s: display #%d\n", ctlr->name, port+1);

	switch(port){
	default:
	Badport:
		error("%s: display #%d not supported\n", ctlr->name, port+1);
		break;

	case PortVGA:
		if(igfx->type == TypeG45)	/* K.Okamoto */
			x = (igfx->adpa.v >> 30) & 1;	/* pipe select o/1 */
		if(igfx->type == TypeSNB || igfx->type == TypeIVB)	/* K.Okamoto */
			x = (igfx->adpa.v >> 29) & 3;	/* transcoder A or B or C */
		igfx->adpa.v |= (1<<31);			/* ADPA enable */
		if(igfx->type == TypeG45){	/* set DPMS VSYNC, HSYNC */
 			igfx->adpa.v &= ~(3<<10);	/* Monitor DPMS: on */
			igfx->adpa.v &= ~(1<<15);	/* ADPA Polarity Select use bit 3 and 4 */
			igfx->adpa.v |= 3<<3;
			if(m->hsync == '-')
				igfx->adpa.v ^= 1<<3;
			if(m->vsync == '-')
				igfx->adpa.v ^= 1<<4;
		}
//		if(igfx->type == TypeSNB){	/* set DPMS VSYNC, HSYNC added K.Okamoto */
//			igfx->adpa.v |= 3<<3;
//			if(m->hsync == '-')
//				igfx->adpa.v ^= 1<<3;
//			if(m->vsync == '-')
//				igfx->adpa.v ^= 1<<4;
//		}
//print("vsync = %d, hsync = %d\n", igfx->adpa.v >>3 &2, igfx->adpa.v >>3 &1);
		break;

	case PortLCD:
		if(igfx->type == TypeG45)
			x = (igfx->lvds.v >> 30) & 1;	/* pipe select o/1 */
		if(igfx->type == TypeSNB || igfx->type == TypeIVB)	/* K.Okamoto */
			x = (igfx->lvds.v >> 29) & 3;	/* transcoder A or B or C */
		igfx->lvds.v |= (1<<31);
		igfx->ppcontrol.v |= 5;

		if(igfx->type == TypeG45){
			igfx->lvds.v &= ~(1<<24);	/* data format select 18/24bpc */

			igfx->lvds.v &= ~(3<<20);
			if(m->hsync == '-')
				igfx->lvds.v ^= 1<<20;
			if(m->vsync == '-')
				igfx->lvds.v ^= 1<<21;

			igfx->lvds.v |= (1<<15);	/* border enable */
		}
		break;

	case PortDPA:
	case PortDPB:
	case PortDPC:
	case PortDPD:
		r = &igfx->dp[port - PortDPA].ctl;
//print("Passing case PortDPX\n");
		if(r->a == 0)
			goto Badport;
		/* port enable */
		r->v |= 1<<31;
		/* port width selection: x1 Mode */
		r->v &= ~(7<<19);

		/* port reversal: off */
		r->v &= ~(1<<15);
		/* reserved MBZ */
		r->v &= ~(15<<11);
		/* use PIPE_A for displayport */
		x = 0;
		/* displayport transcoder */
		if(port == PortDPA){
			/* pll frequency: 270mhz */
			r->v &= ~(3<<16);
			/* pll enable */
			r->v |= 1<<14;
			/* pipe select */
			r->v &= ~(3<<29);
			r->v |= x<<29;
		} else if(igfx->pipe[x].fdi->dpctl.a != 0){
			/* audio output: disable */
			r->v &= ~(1<<6);
			/* transcoder displayport configuration */
			r = &igfx->pipe[x].fdi->dpctl;
			/* transcoder enable */
			r->v |= 1<<31;
			/* port select: B,C,D */
			r->v &= ~(3<<29);
			r->v |= (port-PortDPB)<<29;
		}
		/* sync polarity */
		r->v |= 3<<3;
		if(m->hsync == '-')
			r->v ^= 1<<3;
		if(m->vsync == '-')
			r->v ^= 1<<4;
		break;
	}
	p = &igfx->pipe[x];

	/* plane enable, 32bpp */
	p->dsp->cntr.v = (1<<31) | (6<<26);
	if(igfx->type == TypeG45)
		p->dsp->cntr.v |= x<<24;	/* pipe assign bit24,25=00 cannot be changed*/

	/* stride must be 64 byte aligned */
	p->dsp->stride.v = m->x * (m->z / 8);
	p->dsp->stride.v += 63;
	p->dsp->stride.v &= ~63;

	/* virtual width in pixels */
	vga->virtx = p->dsp->stride.v / (m->z / 8);

	/* plane position and size */
	p->dsp->pos.v = 0;
	p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1);	/* sic */

	p->dsp->surf.v = 0;
	p->dsp->linoff.v = 0;
	p->dsp->tileoff.v = 0;

	/* cursor plane off */
	p->cur->cntr.v = 0;
	if(igfx->type == TypeG45)
		p->cur->cntr.v |= x<<28;	/* pipe assign */
	p->cur->pos.v = 0;
	p->cur->base.v = 0;

	if(initdpll(igfx, x, m->frequency, port) < 0)
		error("%s: frequency %d out of range\n", ctlr->name, m->frequency);

	initpipe(p, m);

	ctlr->flag |= Finit;
}

static void
loadtrans(Igfx *igfx, Trans *t)
{
	int i;

	/* program trans/pipe timings */
	loadreg(igfx, t->ht);
	loadreg(igfx, t->hb);
	loadreg(igfx, t->hs);
	loadreg(igfx, t->vt);
	loadreg(igfx, t->vb);
	loadreg(igfx, t->vs);
	loadreg(igfx, t->vss);

	loadreg(igfx, t->dm[0]);
	loadreg(igfx, t->dn[0]);
	loadreg(igfx, t->lm[0]);
	loadreg(igfx, t->ln[0]);
	loadreg(igfx, t->dm[1]);
	loadreg(igfx, t->dn[1]);
	loadreg(igfx, t->lm[1]);
	loadreg(igfx, t->ln[1]);

	if(t->dpll != nil){
		/* program dpll */
		t->dpll->ctrl.v &= ~(1<<31);
		loadreg(igfx, t->dpll->ctrl);
		loadreg(igfx, t->dpll->fp0);
		loadreg(igfx, t->dpll->fp1);

		/* enable dpll */
		t->dpll->ctrl.v |= (1<<31);
		loadreg(igfx, t->dpll->ctrl);
		sleep(10);
	}

	/* workarround: set timing override bit */
	csr(igfx, t->chicken.a, 0, 1<<31);

	/* enable displayport transcoder */
	loadreg(igfx, t->dpctl);

	/* enable trans/pipe */
	t->conf.v |= (1<<31);
	t->conf.v &= ~(1<<30);
	loadreg(igfx, t->conf);
	for(i=0; i<100; i++){
		sleep(10);
		if(rr(igfx, t->conf.a) & (1<<30))
			break;
	}
}

static void
enablepipe(Igfx *igfx, int x)
{
	int i;
	Pipe *p;

	p = &igfx->pipe[x];
	if((p->conf.v & (1<<31)) == 0)
		return;	/* pipe is disabled, done */

	if(p->fdi->rxctl.a != 0){		/* TypeSNB or TypeIVB */
		if(igfx->type == TypeSNB){	/* K.Okamoto */
			csr(igfx, 0xC6200, 1<<11, 2);	/* pch ref souce & ssc enable */
			sleep(5);
		}
		p->fdi->rxctl.v &= ~(1<<31);	/* disable */
		p->fdi->rxctl.v &= ~(1<<4);	/* rawclk(not pcdclk) */
		p->fdi->rxctl.v |= (1<<13);	/* enable pll */
		loadreg(igfx, p->fdi->rxctl);
		sleep(5);
		p->fdi->rxctl.v |= (1<<4);	/* pcdclk */
		loadreg(igfx, p->fdi->rxctl);
		sleep(5);
		if(igfx->type == TypeSNB){	/* K.Okamoto */	
			p->fdi->txctl.v |= (1<<14);	/* enable FDI pll K.Okamoto */
			loadreg(igfx, p->fdi->txctl);
			sleep(5);
		}else{
			p->fdi->txctl.v &= ~(7<<8 | 1);	/* clear auto training bits */
			p->fdi->txctl.v &= ~(1<<31);	/* disable */
			p->fdi->rxctl.v |= (1<<14);	/* DMI link reversal strap RO bit */
			loadreg(igfx, p->fdi->txctl);
			sleep(5);
		}
	}

	/* image size (vga needs to be off) */
	loadreg(igfx, p->src);

	/* set panel fitter as needed */
	if(p->pfit != nil){
		loadreg(igfx, p->pfit->ctrl);
		loadreg(igfx, p->pfit->winpos);
		loadreg(igfx, p->pfit->winsize);	/* arm */
	}

	/* keep planes disabled while pipe comes up */
	if(igfx->type == TypeG45)
		p->conf.v |= 3<<18;

	/* enable cpu pipe */
	loadtrans(igfx, p);

	/* program plane */
	loadreg(igfx, p->dsp->cntr);
	loadreg(igfx, p->dsp->linoff);
	loadreg(igfx, p->dsp->stride);
	loadreg(igfx, p->dsp->tileoff);
	loadreg(igfx, p->dsp->size);
	loadreg(igfx, p->dsp->pos);
	loadreg(igfx, p->dsp->surf);	/* arm */

	/* program cursor */
	loadreg(igfx, p->cur->cntr);
	loadreg(igfx, p->cur->pos);
	loadreg(igfx, p->cur->base);	/* arm */

	/* enable planes */
	if(igfx->type == TypeG45) {
		p->conf.v &= ~(3<<18);
		loadreg(igfx, p->conf);
	}

	if(p->fdi->rxctl.a != 0){	/* TypeSNB or TypeIVB */
		/* enable fdi */
		loadreg(igfx, p->fdi->rxtu[1]);
		loadreg(igfx, p->fdi->rxtu[0]);
//		p->fdi->rxmisc.v |= 0x200000;	/* added by K.Okamoto tose #of link clock=48 */
		loadreg(igfx, p->fdi->rxmisc);
/* from here   K.Okamoto */
		if (igfx->type == TypeSNB){
			for(i=0;i<10;i++){	/* ensure Receive IIR, K.Okamoto */
				if(rr(igfx, 0x44008) & 1<<8)
				break;
			}
			p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 1 enable */
			p->fdi->rxctl.v |= (1<<8);		/* link train pattern 2 enable */
			p->fdi->rxctl.v |= 1<<31;	/* enable FDI pll */
			loadreg(igfx, p->fdi->rxctl);
			p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 1 enable */
			p->fdi->txctl.v |= (1<<8);		/* link train pattern 2 enable */
			p->fdi->txctl.v |= 1<<31;	/* enable FDI pll */
			loadreg(igfx, p->fdi->txctl);
			for(i=0;i<10;i++){
				if(rr(igfx, 0x44008) & 1<<9)	/* ensure Receive IIR, K.Okamoto */
					break;
			}
/* to here  K.Okamoto */
		}
		p->fdi->rxctl.v &= ~(3<<8);	/* link train pattern 1 enable[default] */
		p->fdi->rxctl.v |= 1<<10;	/* auto train enable */
		p->fdi->rxctl.v |= 1<<31;	/* enable FDI pll */
		loadreg(igfx, p->fdi->rxctl);

		p->fdi->txctl.v &= ~(3<<8);	/* link train pattern 1 enable[default] */
		p->fdi->txctl.v |= 1<<10;	/* auto train enable */
		p->fdi->txctl.v |= 1<<31;	/* enable FDI pll */
		loadreg(igfx, p->fdi->txctl);

		/* wait for link training done */
		for(i=0; i<200; i++){
			sleep(5);
			if(rr(igfx, p->fdi->txctl.a) & 2)	/* auto train done */
				break;
		}
	}

	/* enable the transcoder */
	loadtrans(igfx, p->fdi);
}

static void
disabletrans(Igfx *igfx, Trans *t)
{
	int i;

	/* disable displayport transcoder */
	csr(igfx, t->dpctl.a, 1<<31, 3<<29);

	/* disable transcoder / pipe */
	csr(igfx, t->conf.a, 1<<31, 0);
	for(i=0; i<100; i++){
		sleep(10);
		if((rr(igfx, t->conf.a) & (1<<30)) == 0)
			break;
	}
	/* workarround: clear timing override bit */
	csr(igfx, t->chicken.a, 1<<31, 0);

	/* disable dpll  */
	if(t->dpll != nil)
		csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
}

static void
disablepipe(Igfx *igfx, int x)
{
	Pipe *p;

	p = &igfx->pipe[x];

	/* planes off */
	csr(igfx, p->dsp->cntr.a, 1<<31, 0);
	wr(igfx, p->dsp->surf.a, 0);	/* arm */
	/* cursor off */
	csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
	wr(igfx, p->cur->base.a, 0);	/* arm */

	/* display/overlay/cursor planes off */
	if(igfx->type == TypeG45)
		csr(igfx, p->conf.a, 0, 3<<18);

	/* disable cpu pipe */
	disabletrans(igfx, p);

	/* disable panel fitter */
	if(p->pfit != nil)
		csr(igfx, p->pfit->ctrl.a, 1<<31, 0);

	/* disable fdi transmitter and receiver */
	csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
	csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);

	/* disable pch transcoder */
	disabletrans(igfx, p->fdi);

	/* disable pch dpll enable bit */
	csr(igfx, igfx->dpllsel.a, 8<<(x*4), 0);
}

static void
load(Vga* vga, Ctlr* ctlr)
{
	Igfx *igfx;
	int x;

	igfx = vga->private;

	/* power lcd off */
	if(igfx->ppcontrol.a != 0){
		csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
		for(x=0; x<5000; x++){
			sleep(10);
			if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
				break;
		}
	}

	/* disable ports */
	csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
	csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
	csr(igfx, igfx->adpa.a, 1<<31, 0);	/* disable adpa */
	csr(igfx, igfx->lvds.a, 1<<31, 0);
	for(x = 0; x < nelem(igfx->dp); x++)
		csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
	for(x = 0; x < nelem(igfx->hdmi); x++)
		csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);

	/* disable vga plane */
	csr(igfx, igfx->vgacntrl.a, 0, 1<<31);

	/* turn off all pipes */
	for(x = 0; x < igfx->npipe; x++)
		disablepipe(igfx, x);

	if(igfx->type == TypeG45){
		/* toggle dsp a on and off (from enable sequence) */
		csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);
		csr(igfx, igfx->pipe[0].dsp->cntr.a, 0, 1<<31);
		wr(igfx, igfx->pipe[0].dsp->surf.a, 0);		/* arm */
		csr(igfx, igfx->pipe[0].dsp->cntr.a, 1<<31, 0);
		wr(igfx, igfx->pipe[0].dsp->surf.a, 0);		/* arm */
		csr(igfx, igfx->pipe[0].conf.a, 0, 3<<18);
	}

	/* program new clock sources */
	loadreg(igfx, igfx->rawclkfreq);
	loadreg(igfx, igfx->drefctl);
	sleep(10);

	/* set lvds before enabling dpll */
	loadreg(igfx, igfx->lvds);

	/* new dpll setting */
	loadreg(igfx, igfx->dpllsel);

	/* program all pipes */
	for(x = 0; x < igfx->npipe; x++)
		enablepipe(igfx, x);

	/* program vga plane */
	loadreg(igfx, igfx->vgacntrl);

	/* program ports */
	if(igfx->pci->did == 0x29a2){		/* K.Okamoto */
//		f = open("/usr/sys/ken", ORDWR);
//		fprint(f, "adpa = 0x%ux\n", igfx->adpa.v);
		igfx->adpa.v |= 1<<31;		/* enable adpa */
		wr(igfx, igfx->adpa.a, igfx->adpa.v);
		igfx->adpa.v |= 3<<10;		/* disable hsync/vsync */
		wr(igfx, igfx->adpa.a, igfx->adpa.v);
//		fprint(f, "adpa = 0x%ux\n", rr(igfx, igfx->adpa.a));
		wr(igfx, 0x070024, 0x207);
		while((rr(igfx, 0x070024) & 1<<9) == 0)
			{/* wait for VBLANK */
//				fprint(f, "Vblank = 0x%x\n", rr(igfx, 0x70024));
		}
//		fprint(f, "Vblank = 0x%x\n", rr(igfx, 0x70024));
//		fprint(f, "detect second Vblank\n");
		wr(igfx, 0x070024, 0x207);
		while((rr(igfx, 0x070024) & 1<<9) == 0)
			{/* wait for VBLANK */
//				fprint(f, "Vblank = 0x%x\n", rr(igfx, 0x70024));
		}
//		fprint(f, "Vblank = 0x%x\n", rr(igfx, 0x70024));
	}
//		fprint(f, "adpa = 0x%ux\n", rr(igfx, igfx->adpa.a));
//	igfx->adpa.v &= ~(3<<10);	/* Monitor DPMS: on */

	loadreg(igfx, igfx->adpa);
	loadreg(igfx, igfx->sdvob);
	loadreg(igfx, igfx->sdvoc);
	for(x = 0; x < nelem(igfx->dp); x++){
		if(enabledp(igfx, &igfx->dp[x]) < 0)
			ctlr->flag |= Ferror;
	}

	/* program lcd power */
	loadreg(igfx, igfx->ppcontrol);

	ctlr->flag |= Fload;
}

static void
dumpreg(char *name, char *item, Reg r)
{
	if(r.a == 0)
		return;

	printitem(name, item);
	Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
}

static void
dumphex(char *name, char *item, uchar *data, int len)
{
	int i;

	for(i=0; i<len; i++){
		if((i & 15) == 0){
			if(i > 0)
				Bprint(&stdout, "\n");
			printitem(name, item);
			Bprint(&stdout, " [%.2x] =", i);
		}
		Bprint(&stdout, " %.2X", data[i]);
	}
	Bprint(&stdout, "\n");
}

static void
dumptiming(char *name, Trans *t)
{
	int tu, m, n;

	if(t->dm[0].a != 0 && t->dm[0].v != 0){
//		tu = 1+((t->dm[0].v >> 25) & 0x3f);
		tu = 1+((t->dm[0].v >> 25) & 0x3F);
		printitem(name, "dm1 tu");
		Bprint(&stdout, " %d\n", tu);

		m = t->dm[0].v & 0xffffff;
		n = t->dn[0].v;
		if(n > 0){
			printitem(name, "dm1/dn1");
			Bprint(&stdout, " %f\n", (double)m / (double)n);
		}

		m = t->lm[0].v;
		n = t->ln[0].v;
		if(n > 0){
			printitem(name, "lm1/ln1");
			Bprint(&stdout, " %f\n", (double)m / (double)n);
		}
	}
}

static void
dumptrans(char *name, Trans *t)
{
	dumpreg(name, "conf", t->conf);

	dumpreg(name, "dm1", t->dm[0]);
	dumpreg(name, "dn1", t->dn[0]);
	dumpreg(name, "lm1", t->lm[0]);
	dumpreg(name, "ln1", t->ln[0]);
	dumpreg(name, "dm2", t->dm[1]);
	dumpreg(name, "dn2", t->dn[1]);
	dumpreg(name, "lm2", t->lm[1]);
	dumpreg(name, "ln2", t->ln[1]);

	dumptiming(name, t);

	dumpreg(name, "ht", t->ht);
	dumpreg(name, "hb", t->hb);
	dumpreg(name, "hs", t->hs);

	dumpreg(name, "vt", t->vt);
	dumpreg(name, "vb", t->vb);
	dumpreg(name, "vs", t->vs);
	dumpreg(name, "vss", t->vss);

	dumpreg(name, "dpctl", t->dpctl);
}

static void
dumppipe(Igfx *igfx, int x)
{
	char name[32];
	Pipe *p;

	p = &igfx->pipe[x];

	snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
	dumpreg(name, "src", p->src);
	dumptrans(name, p);

	snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
	dumptrans(name, p->fdi);
	dumpreg(name, "txctl", p->fdi->txctl);
	dumpreg(name, "rxctl", p->fdi->rxctl);
	dumpreg(name, "rxmisc", p->fdi->rxmisc);
	dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
	dumpreg(name, "rxtu2", p->fdi->rxtu[1]);

	snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
	dumpreg(name, "cntr", p->dsp->cntr);
	dumpreg(name, "linoff", p->dsp->linoff);
	dumpreg(name, "stride", p->dsp->stride);
	dumpreg(name, "surf", p->dsp->surf);
	dumpreg(name, "tileoff", p->dsp->tileoff);
	dumpreg(name, "pos", p->dsp->pos);
	dumpreg(name, "size", p->dsp->size);

	snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
	dumpreg(name, "cntr", p->cur->cntr);
	dumpreg(name, "base", p->cur->base);
	dumpreg(name, "pos", p->cur->pos);
}

static void
dumpdpll(Igfx *igfx, int x)
{
	int cref, m1, m2, n, p1, p2;
	uvlong freq;
	char name[32];
	Dpll *dpll;
	u32int m;

	dpll = &igfx->dpll[x];
	snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);

	dumpreg(name, "ctrl", dpll->ctrl);
	dumpreg(name, "fp0", dpll->fp0);
	dumpreg(name, "fp1", dpll->fp1);

	p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
	if(((dpll->ctrl.v >> 24) & 3) == 1)
		p2 >>= 1;
	m = (dpll->ctrl.v >> 16) & 0xFF;
	for(p1 = 1; p1 <= 8; p1++)
		if(m & (1<<(p1-1)))
			break;
	printitem(name, "ctrl p1");
	Bprint(&stdout, " %d\n", p1);
	printitem(name, "ctrl p2");
	Bprint(&stdout, " %d\n", p2);

//	n = (dpll->fp0.v >> 16) & 0x3f;
//	m1 = (dpll->fp0.v >> 8) & 0x3f;
//	m2 = (dpll->fp0.v >> 0) & 0x3f;
	n = (dpll->fp0.v >> 16) & 0x3F;
	m1 = (dpll->fp0.v >> 8) & 0x3F;
	m2 = (dpll->fp0.v >> 0) & 0x3F;

	cref = getcref(igfx, x);
	freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);

	printitem(name, "fp0 m1");
	Bprint(&stdout, " %d\n", m1);
	printitem(name, "fp0 m2");
	Bprint(&stdout, " %d\n", m2);
	printitem(name, "fp0 n");
	Bprint(&stdout, " %d\n", n);

	printitem(name, "cref");
	Bprint(&stdout, " %d\n", cref);
	printitem(name, "fp0 freq");
	Bprint(&stdout, " %lld\n", freq);
}

static void
dump(Vga* vga, Ctlr* ctlr)
{
	char name[32];
	Igfx *igfx;
	int x;

	if((igfx = vga->private) == nil)
		return;

	for(x=0; x<igfx->npipe; x++)
		dumppipe(igfx, x);

	for(x=0; x<nelem(igfx->dpll); x++)
		dumpdpll(igfx, x);

	dumpreg(ctlr->name, "dpllsel", igfx->dpllsel);

	dumpreg(ctlr->name, "drefctl", igfx->drefctl);
	dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
	dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);

	for(x=0; x<nelem(igfx->dp); x++){
		if(igfx->dp[x].ctl.a == 0)
			continue;
		snprint(name, sizeof(name), "%s dp %c", ctlr->name, 'a'+x);
		dumpreg(name, "ctl", igfx->dp[x].ctl);
		dumphex(name, "dpcd", igfx->dp[x].dpcd, sizeof(igfx->dp[x].dpcd));
	}
	for(x=0; x<nelem(igfx->hdmi); x++){
		snprint(name, sizeof(name), "%s hdmi %c", ctlr->name, 'a'+x);
		dumpreg(name, "ctl", igfx->hdmi[x].ctl);
	}

	for(x=0; x<nelem(igfx->pfit); x++){
		snprint(name, sizeof(name), "%s pfit %c", ctlr->name, 'a'+x);
		dumpreg(name, "ctrl", igfx->pfit[x].ctrl);
		dumpreg(name, "winpos", igfx->pfit[x].winpos);
		dumpreg(name, "winsize", igfx->pfit[x].winsize);
		dumpreg(name, "pwrgate", igfx->pfit[x].pwrgate);
	}

	dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
	dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);

	dumpreg(ctlr->name, "adpa", igfx->adpa);
	dumpreg(ctlr->name, "lvds", igfx->lvds);
	dumpreg(ctlr->name, "sdvob", igfx->sdvob);
	dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);

	dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
}

static int
dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
{
	int t, i;
	u32int w;

	if(dp->auxctl.a == 0){
		werrstr("not present");
		return -1;
	}

	t = 0;
	while(rr(igfx, dp->auxctl.a) & (1<<31)){
		if(++t >= 10){
			werrstr("busy");
			return -1;
		}
		sleep(5);
	}

	/* clear sticky bits */
	wr(igfx, dp->auxctl.a, (1<<28) | (1<<25) | (1<<30));

	for(i=0; i<nelem(dp->auxdat); i++){
		w  = buf[i*4+0]<<24;
		w |= buf[i*4+1]<<16;
		w |= buf[i*4+2]<<8;
		w |= buf[i*4+3];
		wr(igfx, dp->auxdat[i].a, w);
	}

	/* 2X Bit Clock divider */
//	w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3ff)) >> 1;
	w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3FF)) >> 1;
//	if(w < 1 || w > 0x3fd){
	if(w < 1 || w > 0x3FD){
		werrstr("bad clock");
		return -1;
	}

	/* hack: slow down a bit */
	w += 2;

	w |= 1<<31;	/* SendBusy */
	w |= 1<<29;	/* interrupt disabled */
	w |= 3<<26;	/* timeout 1600µs */
	w |= len<<20;	/* send bytes */
	w |= 5<<16;	/* precharge time (5*2 = 10µs) */
	wr(igfx, dp->auxctl.a, w);

	t = 0;
	for(;;){
		w = rr(igfx, dp->auxctl.a);
		if((w & (1<<30)) != 0)
			break;
		if(++t >= 10){
			werrstr("busy");
			return -1;
		}
		sleep(5);
	}
	if(w & (1<<28)){
		werrstr("receive timeout");
		return -1;
	}
	if(w & (1<<25)){
		werrstr("receive error");
		return -1;
	}

	len = (w >> 20) & 0x1f;
	for(i=0; i<nelem(dp->auxdat); i++){
		w = rr(igfx, dp->auxdat[i].a);
		buf[i*4+0] = w>>24;
		buf[i*4+1] = w>>16;
		buf[i*4+2] = w>>8;
		buf[i*4+3] = w;
	}

	return len;
}

enum {
	CmdNative	= 8,
	CmdMot		= 4,
	CmdRead		= 1,
	CmdWrite	= 0,
};

static int
dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
{
	uchar buf[20];
	int r;

	assert(len <= 16);

	memset(buf, 0, sizeof(buf));
	buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
	buf[1] = addr >> 8;
	buf[2] = addr;
	buf[3] = len-1;
	r = 3;	
	if(data != nil && len > 0){
		if((cmd & CmdRead) == 0)
			memmove(buf+4, data, len);
		r = 4 + len;
	}
	if((r = dpauxio(igfx, dp, buf, r)) < 0){
		trace("%s: dpauxio: dp %c, cmd %x, addr %x, len %d: %r\n",
			igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]), cmd, addr, len);
		return -1;
	}
	if(r == 0 || data == nil || len == 0)
		return 0;
	if((cmd & CmdRead) != 0){
		if(--r < len)
			len = r;
		memmove(data, buf+1, len);
	}
	return len;
}

static int
rdpaux(Igfx *igfx, Dp *dp, int addr)
{
	uchar buf[1];
	if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
		return -1;
	return buf[0];
}
static int
wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
{
	if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
		return -1;
	return 0;
}

static int
enabledp(Igfx *igfx, Dp *dp)
{
	int try, r;

	if(dp->ctl.a == 0)
		return 0;
	if((dp->ctl.v & (1<<31)) == 0)
		return 0;

	/* Link configuration */
	wdpaux(igfx, dp, 0x100, 0x0A);	/* 270Mhz */
	wdpaux(igfx, dp, 0x101, 0x01);	/* one lane */

	r = 0;

	/* Link training pattern 1 */
	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);

	/* Link training pattern 2 */
	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);

	/* stop training */
	dp->ctl.v &= ~(7<<8);
	dp->ctl.v |= 3<<8;
	loadreg(igfx, dp->ctl);
	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)
{
	uchar buf[256];
	int i;

	for(i=0; i<sizeof(dp->dpcd); i+=16)
		if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
			return nil;
	if(dp->dpcd[0] == 0)	/* nothing there, dont try to get edid */
		return nil;
	if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
		return nil;

	for(i=0; i<sizeof(buf); i+=16){
		if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
			continue;
		if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
			continue;
		if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
			continue;
		if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
			continue;
		if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
			continue;
		return nil;
	}

	dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
	return parseedid128(edidshift(buf));
}

enum {
	GMBUSCP = 0,	/* Clock/Port selection */
	GMBUSCS = 1,	/* Command/Status */
	GMBUSST = 2,	/* Status Register */
	GMBUSDB	= 3,	/* Data Buffer Register */
	GMBUSIM = 4,	/* Interrupt Mask */
	GMBUSIX = 5,	/* Index Register */
};
	
static int
gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
{
	u32int x, y;
	int n, t;

	if(igfx->gmbus[GMBUSCP].a == 0)
		return -1;

	wr(igfx, igfx->gmbus[GMBUSCP].a, port);		/* set out device by port# */
// 0: none
//1: dedicated control/gmbus pins
//2: dedicated analog monitor
//3: LVDS or DP D
//4: reserved
//5: sDVO/HDMI
//6: reserved
//7: D connector control reg
	wr(igfx, igfx->gmbus[GMBUSIX].a, 0);

	/* bus cycle without index and stop, byte count, slave address, read */
	wr(igfx, igfx->gmbus[GMBUSCS].a, 1<<30 | 5<<25 | len<<16 | addr<<1 | 1);

	n = 0;
	while(len > 0){
		x = 0;
		for(t=0; t<100; t++){
			x = rr(igfx, igfx->gmbus[GMBUSST].a);
			if(x & (1<<11))
				break;
			sleep(5);
		}
		if((x & (1<<11)) == 0)
			return -1;

		t = 4 - (x & 3);
		if(t > len)
			t = len;
		len -= t;

		y = rr(igfx, igfx->gmbus[GMBUSDB].a);
		switch(t){
		case 4:
//			data[n++] = y & 0xff, y >>= 8;
			data[n++] = y & 0xFF, y >>= 8;
		case 3:
//			data[n++] = y & 0xff, y >>= 8;
			data[n++] = y & 0xFF, y >>= 8;
		case 2:
//			data[n++] = y & 0xff, y >>= 8;
			data[n++] = y & 0xFF, y >>= 8;
		case 1:
//			data[n++] = y & 0xff;
			data[n++] = y & 0xFF;
		}
	}

	return n;
}

static Edid*
snarfgmedid(Igfx *igfx, int port, int addr)
{
	uchar buf[256];

	/* read twice */
	if(gmbusread(igfx, port, addr, buf, 128) != 128)
		return nil;
if(igfx->pci->did != 0x0152)		/* K.Okamoto */
	if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
		return nil;

	return parseedid128(edidshift(buf));
}

Ctlr igfx = {
	"igfx",			/* name */
	snarf,			/* snarf */
	options,		/* options */
	init,			/* init */
	load,			/* load */
	dump,			/* dump */
};

Ctlr igfxhwgc = {
	"igfxhwgc",
};

[-- Attachment #3: Type: text/plain, Size: 4423 bytes --]

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"

static ulong
stolenmb(Pcidev *p)
{
	switch(p->did){
	case 0x0166:	/* Ivy Bridge */
	case 0x0102:	/* Core-5 Sandy Bridge */
	case 0x0152:	/* Core-i3 */
		switch((pcicfgr16(p, 0x50) >> 3) & 0x1f){
		case 0x01:	return 32  - 2;
		case 0x02:	return 64  - 2;		/* 0102 Dell machine here */
		case 0x03:	return 96  - 2;
		case 0x04:	return 128 - 2;
		case 0x05:	return 32  - 2;
		case 0x06:	return 48  - 2;
		case 0x07:	return 64  - 2;
		case 0x08:	return 128 - 2;
		case 0x09:	return 256 - 2;
		case 0x0A:	return 96  - 2;
		case 0x0B:	return 160 - 2;
		case 0x0C:	return 224 - 2;
		case 0x0D:	return 352 - 2;
		case 0x0E:	return 448 - 2;
		case 0x0F:	return 480 - 2;
		case 0x10:	return 512 - 2;
		}
		break;
	case 0x2a42:	/* X200 */
	case 0x29a2:	/* 82P965/G965 HECI desktop */
	case 0x2a02:	/* CF-R7 */
		switch((pcicfgr16(p, 0x52) >> 4) & 7){
		case 0x01:	return 1;
		case 0x02:	return 4;
		case 0x03:	return 8;
		case 0x04:	return 16;
		case 0x05:	return 32;
		case 0x06:	return 48;
		case 0x07:	return 64;
		}
		break;
	}
	return 0;
}

static uintptr
gmsize(Pcidev *pci, void *mmio)
{
	u32int x, i, npg, *gtt;

	npg = stolenmb(pci)<<(20-12);
	if(npg == 0)
		return 0;
	gtt = (u32int*)((uchar*)mmio + pci->mem[0].size/2);
	if((gtt[0]&1) == 0)
		return 0;
	x = (gtt[0]>>12)+1;
	for(i=1; i<npg; i++){
		if((gtt[i]&1) == 0 || (gtt[i]>>12) != x)
			break;
		x++;
	}
	if(0) print("igfx: graphics memory at %p-%p (%ud MB)\n", 
		(uintptr)(x-i)<<12, (uintptr)x<<12, (i>>(20-12)));
	return (uintptr)i<<12;
}

static void
igfxenable(VGAscr* scr)
{
	Pcidev *p;
	
	if(scr->mmio != nil)
		return;
	p = scr->pci;
	if(p == nil)
		return;
	scr->mmio = vmap(p->mem[0].bar&~0x0F, p->mem[0].size);
	if(scr->mmio == nil)
		return;
	addvgaseg("igfxmmio", p->mem[0].bar&~0x0F, p->mem[0].size);
	if(scr->paddr == 0)
		vgalinearpci(scr);
	if(scr->apsize){
		addvgaseg("igfxscreen", scr->paddr, scr->apsize);
		scr->storage = gmsize(p, scr->mmio);
		if(scr->storage < MB)
			scr->storage = 0;
		else if(scr->storage > scr->apsize)
			scr->storage = scr->apsize;
		if(scr->storage != 0)
			scr->storage -= PGROUND(64*64*4);
	}
}

VGAdev vgaigfxdev = {
	"igfx",
	igfxenable,
};

static void
igfxcurload(VGAscr* scr, Cursor* curs)
{
	uchar set, clr;
	u32int *p;
	int i, j;

	if(scr->storage == 0)
		return;
	p = (u32int*)((uchar*)scr->vaddr + scr->storage);
	memset(p, 0, 64*64*4);
	for(i=0;i<32;i++) {
		set = curs->set[i];
		clr = curs->clr[i];
		for(j=0x80; j; j>>=1){
			if((set|clr)&j)
				*p++ = (0xFF<<24) | (set&j ? 0x000000 : 0xFFFFFF);
			else
				*p++ = 0;
		}
		if(i & 1)
			p += 64-16;
	}
	scr->offset = curs->offset;
}

enum {
	CURCTL = 0,
	CURBASE,
	CURPOS,

	NPIPE = 3,
};

static u32int*
igfxcurregs(VGAscr* scr, int pipe)
{
	u32int o;

	if(scr->mmio == nil || scr->storage == 0)
		return nil;
	o = pipe*0x1000;
	/* check PIPExCONF if enabled */
	if((scr->mmio[(0x70008 | o)/4] & (1<<31)) == 0)
		return nil;
	switch(scr->pci->did){
	case 0x0166:	/* Ivy Bridge */
	case 0x0152:	/* Core-i3 */
		if(pipe > 2)
			return nil;
		break;
	case 0x2a42:	/* X200 */
	case 0x29a2:	/* 82P965/G965 HECI desktop */
	case 0x2a02:	/* CF-R7 */
	case 0x0102:	/* Sndy Bridge */
		if(pipe > 1)
			return nil;
		o = pipe*0x40;
		break;
	default:
		if(pipe > 0)
			return nil;
	}
	return (u32int*)((uchar*)scr->mmio + (0x70080 + o));
}

static int
igfxcurmove(VGAscr* scr, Point p)
{
	int i, x, y;
	u32int *r;

	for(i=0; i<NPIPE; i++){
		if((r = igfxcurregs(scr, i)) != nil){
			x = p.x + scr->offset.x;
			if(x < 0) x = -x | 0x8000;
			y = p.y + scr->offset.y;
			if(y < 0) y = -y | 0x8000;
			r[CURPOS] = (y << 16) | x;
		}
	}
	return 0;
}

static void
igfxcurenable(VGAscr* scr)
{
	u32int *r;
	int i;

	igfxenable(scr);
	igfxcurload(scr, &arrow);
	igfxcurmove(scr, ZP);

	for(i=0; i<NPIPE; i++){
		if((r = igfxcurregs(scr, i)) != nil){
			r[CURCTL] = (r[CURCTL] & ~(3<<28 | 1<<5)) | (i<<28) | 7;
			r[CURBASE] = scr->storage;
		}
	}
}

static void
igfxcurdisable(VGAscr* scr)
{
	u32int *r;
	int i;

	for(i=0; i<NPIPE; i++){
		if((r = igfxcurregs(scr, i)) != nil){
			r[CURCTL] &= ~(1<<5 | 7);
			r[CURBASE] = 0;
		}
	}
}

VGAcur vgaigfxcur = {
	"igfxhwgc",
	igfxcurenable,
	igfxcurdisable,
	igfxcurload,
	igfxcurmove,
};

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-27  0:12     ` kokamoto
@ 2016-07-27  9:57       ` cinap_lenrek
  2016-07-27 13:24         ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: cinap_lenrek @ 2016-07-27  9:57 UTC (permalink / raw)
  To: 9front

great news, thank you!

the plain igfx.c and vgaigfx.c files would be good or provide a patch
(hg diff)...

--
cinap


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-25  4:19   ` [9front] core-i5(TypeSNB) " kokamoto
@ 2016-07-27  0:12     ` kokamoto
  2016-07-27  9:57       ` cinap_lenrek
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-27  0:12 UTC (permalink / raw)
  To: 9front

I got success to display onto VGA on this Sandy-Bridge machine.
The problem was in the process of initializing.
I'll post the difference here later, because I have duty 
in afternoon today.

I'm writing this mail from did=0102 machine
Dell Optiplex-970 ultrasmall desktop.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [9front] core-i5(TypeSNB) and vesa mode
  2016-07-23 23:50 ` kokamoto
@ 2016-07-25  4:19   ` kokamoto
  2016-07-27  0:12     ` kokamoto
  0 siblings, 1 reply; 51+ messages in thread
From: kokamoto @ 2016-07-25  4:19 UTC (permalink / raw)
  To: 9front

I changed the subject to fit the present problem.

> The vesa vios does not work on this machine.
> Just blank screen can be seen.

It was true only for VGA connector.
Now, I got a DP->HDMI connector, and tried again, 
and got success.

My /cfg/pxe/xxxxxxxx file is as follows:
---from here---
#Core-i5 Dell Optiflex 790 desktop (Sandy-bridge)
bootargs=tcp
bootfile=/386/9pcf
nobootprompt=tcp
mouseport=usb
monitor=vesa
vgasize=1920x1080x32
---to here----

Other modes include 1280x1024x32, 1444x900x32
1024x768x32 etc.

Kenji



^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2016-08-20 17:11 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-06 15:08 [9front] core-i5(TypeSNB) and vesa mode kokamoto
  -- strict thread matches above, loose matches on Subject: below --
2016-07-23 12:27 [9front] core-i3 " cinap_lenrek
2016-07-23 23:50 ` kokamoto
2016-07-25  4:19   ` [9front] core-i5(TypeSNB) " kokamoto
2016-07-27  0:12     ` kokamoto
2016-07-27  9:57       ` cinap_lenrek
2016-07-27 13:24         ` kokamoto
2016-07-27 13:42           ` kokamoto
2016-07-27 19:30           ` cinap_lenrek
2016-07-28  0:37             ` kokamoto
2016-07-28  2:19             ` kokamoto
2016-07-28  9:28               ` cinap_lenrek
2016-07-27 20:01           ` cinap_lenrek
2016-07-27 22:37             ` cinap_lenrek
2016-07-28  0:39             ` kokamoto
2016-07-28 10:03               ` cinap_lenrek
2016-07-28 11:31                 ` kokamoto
2016-07-28 13:26                   ` cinap_lenrek
2016-08-01  6:51                     ` kokamoto
2016-07-28 10:20               ` cinap_lenrek
2016-07-28 11:34                 ` kokamoto
2016-07-28 13:31                   ` cinap_lenrek
2016-07-28 23:48                     ` kokamoto
2016-07-29  0:58                       ` kokamoto
2016-07-29  9:00                         ` cinap_lenrek
2016-07-29 11:42                           ` kokamoto
2016-07-29  8:15                       ` cinap_lenrek
2016-07-29 11:49                         ` kokamoto
2016-07-29 13:01                           ` cinap_lenrek
2016-07-29 23:41                             ` kokamoto
2016-07-29 23:43                               ` cinap_lenrek
2016-08-05 23:58                             ` kokamoto
2016-08-06  5:51                               ` kokamoto
2016-08-06 12:55                                 ` kokamoto
2016-08-06 13:05                                   ` cinap_lenrek
2016-08-06 13:58                                   ` cinap_lenrek
2016-08-07  0:08                                   ` kokamoto
2016-08-07  0:38                                     ` cinap_lenrek
2016-08-09  1:29                                       ` kokamoto
2016-08-09  8:47                                         ` cinap_lenrek
2016-08-13  4:21                                           ` kokamoto
2016-08-09  9:40                                         ` cinap_lenrek
2016-08-12 23:27                                           ` kokamoto
2016-08-13  1:32                                             ` cinap_lenrek
2016-08-13  4:14                                               ` kokamoto
2016-08-13  5:57                                                 ` kokamoto
2016-08-13 23:02                                                   ` kokamoto
2016-08-19 23:01                                                     ` kokamoto
2016-08-20 17:11                                                       ` cinap_lenrek
2016-07-27 21:18           ` cinap_lenrek
2016-07-27 21:41           ` cinap_lenrek
2016-07-27 21:52             ` cinap_lenrek
2016-07-28  0:44             ` kokamoto

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).