8 typedef struct Reg Reg;
9 typedef struct Dpll Dpll;
10 typedef struct Hdmi Hdmi;
12 typedef struct Fdi Fdi;
13 typedef struct Pfit Pfit;
14 typedef struct Curs Curs;
15 typedef struct Plane Plane;
16 typedef struct Trans Trans;
17 typedef struct Pipe Pipe;
18 typedef struct Igfx Igfx;
26 TypeIVB, /* Ivy Bridge */
27 TypeSNB, /* Sandy Bridge (unfinished) */
28 TypeHSW, /* Haswell */
32 PortVGA = 0, /* adpa */
33 PortLCD = 1, /* lvds */
42 u32int a; /* address or 0 when invalid */
47 Reg ctrl; /* DPLLx_CTRL */
53 Reg dm[2]; /* pipe/trans DATAM */
54 Reg dn[2]; /* pipe/trans DATAN */
55 Reg lm[2]; /* pipe/trans LINKM */
56 Reg ln[2]; /* pipe/trans LINKN */
58 Reg ht; /* pipe/trans HTOTAL_x */
59 Reg hb; /* pipe/trans HBLANK_x */
60 Reg hs; /* pipe/trans HSYNC_x */
61 Reg vt; /* pipe/trans VTOTAL_x */
62 Reg vb; /* pipe/trans VBLANK_x */
63 Reg vs; /* pipe/trans VSYNC_x */
64 Reg vss; /* pipe/trans VSYNCSHIFT_x */
66 Reg conf; /* pipe/trans CONF_x */
67 Reg chicken; /* workarround register */
69 Reg dpctl; /* TRANS_DP_CTL_x */
71 Dpll *dpll; /* this transcoders dpll */
72 Reg clksel; /* HSW: PIPE_CLK_SEL_x: transcoder clock select */
84 Reg bufctl; /* DDI_BUF_CTL_x */
85 Reg buftrans[20]; /* DDI_BUF_TRANS */
87 Reg ctl; /* HSW: DP_TP_CTL_x */
97 Reg txctl; /* FDI_TX_CTL */
99 Reg rxctl; /* FDI_RX_CTL */
100 Reg rxmisc; /* FDI_RX_MISC */
101 Reg rxiir; /* FDI_RX_IIR */
102 Reg rximr; /* FDI_RX_IMR */
103 Reg rxtu[2]; /* FDI_RX_TUSIZE */
114 Reg cntr; /* DSPxCNTR */
115 Reg linoff; /* DSPxLINOFF */
116 Reg stride; /* DSPxSTRIDE */
117 Reg surf; /* DSPxSURF */
118 Reg tileoff; /* DSPxTILEOFF */
119 Reg leftsurf; /* HSW: PRI_LEFT_SURF_x */
132 Trans; /* cpu transcoder */
134 Reg src; /* PIPExSRC */
136 Fdi fdi[1]; /* fdi/dp transcoder */
138 Plane dsp[1]; /* display plane */
139 Curs cur[1]; /* hardware cursor */
141 Pfit *pfit; /* selected panel fitter */
152 int cdclk; /* core display clock in mhz */
163 Reg dpllsel[5]; /* DPLL_SEL (IVB), PORT_CLK_SEL_DDIx (HSW) */
166 Reg drefctl; /* DREF_CTL */
167 Reg rawclkfreq; /* RAWCLK_FREQ */
168 Reg ssc4params; /* SSC4_PARAMS */
177 Reg gmbus[6]; /* GMBUSx */
190 rr(Igfx *igfx, u32int a)
194 assert((a & 3) == 0);
195 if(igfx->mmio != nil)
196 return igfx->mmio[a/4];
197 outportl(igfx->pio, a);
198 return inportl(igfx->pio + 4);
201 wr(Igfx *igfx, u32int a, u32int v)
203 if(a == 0) /* invalid */
205 assert((a & 3) == 0);
206 if(igfx->mmio != nil){
210 outportl(igfx->pio, a);
211 outportl(igfx->pio + 4, v);
214 csr(Igfx *igfx, u32int reg, u32int clr, u32int set)
216 wr(igfx, reg, (rr(igfx, reg) & ~clr) | set);
220 loadreg(Igfx *igfx, Reg r)
226 snarfreg(Igfx *igfx, u32int a)
236 snarftrans(Igfx *igfx, Trans *t, u32int o)
239 t->ht = snarfreg(igfx, o + 0x00000);
240 t->hb = snarfreg(igfx, o + 0x00004);
241 t->hs = snarfreg(igfx, o + 0x00008);
242 t->vt = snarfreg(igfx, o + 0x0000C);
243 t->vb = snarfreg(igfx, o + 0x00010);
244 t->vs = snarfreg(igfx, o + 0x00014);
245 t->vss = snarfreg(igfx, o + 0x00028);
247 t->conf = snarfreg(igfx, o + 0x10008);
251 if(t == &igfx->pipe[0]){ /* PIPEA */
252 t->dm[0] = snarfreg(igfx, 0x70050); /* GMCHDataM */
253 t->dn[0] = snarfreg(igfx, 0x70054); /* GMCHDataN */
254 t->lm[0] = snarfreg(igfx, 0x70060); /* DPLinkM */
255 t->ln[0] = snarfreg(igfx, 0x70064); /* DPLinkN */
260 t->dm[0] = snarfreg(igfx, o + 0x30);
261 t->dn[0] = snarfreg(igfx, o + 0x34);
262 t->dm[1] = snarfreg(igfx, o + 0x38);
263 t->dn[1] = snarfreg(igfx, o + 0x3c);
264 t->lm[0] = snarfreg(igfx, o + 0x40);
265 t->ln[0] = snarfreg(igfx, o + 0x44);
266 t->lm[1] = snarfreg(igfx, o + 0x48);
267 t->ln[1] = snarfreg(igfx, o + 0x4c);
270 t->dm[0] = snarfreg(igfx, o + 0x30);
271 t->dn[0] = snarfreg(igfx, o + 0x34);
272 t->lm[0] = snarfreg(igfx, o + 0x40);
273 t->ln[0] = snarfreg(igfx, o + 0x44);
274 if(t == &igfx->pipe[3]){ /* eDP pipe */
275 t->dm[1] = snarfreg(igfx, o + 0x38);
276 t->dn[1] = snarfreg(igfx, o + 0x3C);
277 t->lm[1] = snarfreg(igfx, o + 0x48);
278 t->ln[1] = snarfreg(igfx, o + 0x4C);
285 snarfpipe(Igfx *igfx, int x)
292 o = x == 3 ? 0x6F000 : 0x60000 + x*0x1000;
293 snarftrans(igfx, p, o);
295 if(igfx->type != TypeHSW || x != 3)
296 p->src = snarfreg(igfx, o + 0x0001C);
298 if(igfx->type == TypeHSW) {
299 p->dpctl = snarfreg(igfx, o + 0x400); /* PIPE_DDI_FUNC_CTL_x */
300 p->dpll = &igfx->dpll[0];
302 x = 0; /* use plane/cursor a */
303 p->src = snarfreg(igfx, 0x6001C);
305 p->clksel = snarfreg(igfx, 0x46140 + x*4);
306 } else if(igfx->type == TypeIVB || igfx->type == TypeSNB) {
307 p->fdi->txctl = snarfreg(igfx, o + 0x100);
309 o = 0xE0000 | x*0x1000;
310 snarftrans(igfx, p->fdi, o);
312 p->fdi->dpctl = snarfreg(igfx, o + 0x300);
314 p->fdi->rxctl = snarfreg(igfx, o + 0x1000c);
315 p->fdi->rxmisc = snarfreg(igfx, o + 0x10010);
317 p->fdi->rxiir = snarfreg(igfx, o + 0x10014);
318 p->fdi->rximr = snarfreg(igfx, o + 0x10018);
320 p->fdi->rxtu[0] = snarfreg(igfx, o + 0x10030);
321 p->fdi->rxtu[1] = snarfreg(igfx, o + 0x10038);
323 p->fdi->chicken = snarfreg(igfx, o + 0x10064);
325 p->fdi->dpll = &igfx->dpll[(igfx->dpllsel[0].v>>(x*4)) & 1];
328 p->dpll = &igfx->dpll[x & 1];
332 p->dsp->cntr = snarfreg(igfx, 0x70180 + x*0x1000);
333 p->dsp->linoff = snarfreg(igfx, 0x70184 + x*0x1000);
334 p->dsp->stride = snarfreg(igfx, 0x70188 + x*0x1000);
335 p->dsp->tileoff = snarfreg(igfx, 0x701A4 + x*0x1000);
336 p->dsp->surf = snarfreg(igfx, 0x7019C + x*0x1000);
337 if(igfx->type == TypeHSW)
338 p->dsp->leftsurf = snarfreg(igfx, 0x701B0 + x*0x1000);
344 p->cur->cntr = snarfreg(igfx, 0x70080 + x*0x1000);
345 p->cur->base = snarfreg(igfx, 0x70084 + x*0x1000);
346 p->cur->pos = snarfreg(igfx, 0x70088 + x*0x1000);
349 p->dsp->pos = snarfreg(igfx, 0x7018C + x*0x1000);
350 p->dsp->size = snarfreg(igfx, 0x70190 + x*0x1000);
353 p->cur->cntr = snarfreg(igfx, 0x70080 + x*0x40);
354 p->cur->base = snarfreg(igfx, 0x70084 + x*0x40);
355 p->cur->pos = snarfreg(igfx, 0x70088 + x*0x40);
363 if(igfx->pci->vid != 0x8086)
365 switch(igfx->pci->did){
366 case 0x0a16: /* HD 4400 - 4th Gen Core (ULT) */
369 case 0x0412: /* HD 4600 - 4th Gen Core */
371 case 0x0166: /* 3rd Gen Core - ThinkPad X230 */
372 case 0x0152: /* 2nd/3rd Gen Core - Core-i3 */
374 case 0x0102: /* Dell Optiplex 790 */
375 case 0x0126: /* Thinkpad X220 */
377 case 0x27a2: /* GM945/82940GML - ThinkPad X60 Tablet */
378 case 0x29a2: /* 82P965/G965 HECI desktop */
379 case 0x2a02: /* GM965/GL960/X3100 - ThinkPad X61 Tablet */
380 case 0x2a42: /* 4 Series Mobile - ThinkPad X200 */
386 static Edid* snarfgmedid(Igfx*, int port, int addr);
387 static Edid* snarfdpedid(Igfx*, Dp *dp, int addr);
389 static int enabledp(Igfx*, Dp*);
392 snarf(Vga* vga, Ctlr* ctlr)
399 igfx = alloc(sizeof(Igfx));
401 igfx->pci = vga->pci;
402 if(igfx->pci == nil){
403 error("%s: no pci device\n", ctlr->name);
406 igfx->type = devtype(igfx);
408 error("%s: unrecognized device\n", ctlr->name);
411 vgactlpci(igfx->pci);
413 vgactlw("type", ctlr->name);
414 igfx->mmio = segattach(0, "igfxmmio", 0, igfx->pci->mem[0].size);
415 if(igfx->mmio == (u32int*)-1)
416 error("%s: attaching mmio: %r\n", ctlr->name);
418 if((igfx->pci->mem[4].bar & 1) == 0)
419 error("%s: no pio bar\n", ctlr->name);
420 igfx->pio = igfx->pci->mem[4].bar & ~1;
427 igfx->npipe = 2; /* A,B */
428 igfx->cdclk = 200; /* MHz */
430 igfx->dpll[0].ctrl = snarfreg(igfx, 0x06014);
431 igfx->dpll[0].fp0 = snarfreg(igfx, 0x06040);
432 igfx->dpll[0].fp1 = snarfreg(igfx, 0x06044);
433 igfx->dpll[1].ctrl = snarfreg(igfx, 0x06018);
434 igfx->dpll[1].fp0 = snarfreg(igfx, 0x06048);
435 igfx->dpll[1].fp1 = snarfreg(igfx, 0x0604c);
437 igfx->adpa = snarfreg(igfx, 0x061100);
438 igfx->lvds = snarfreg(igfx, 0x061180);
439 igfx->sdvob = snarfreg(igfx, 0x061140);
440 igfx->sdvoc = snarfreg(igfx, 0x061160);
443 igfx->gmbus[x] = snarfreg(igfx, 0x5100 + x*4);
444 igfx->gmbus[x] = snarfreg(igfx, 0x5120);
446 igfx->pfit[0].ctrl = snarfreg(igfx, 0x061230);
447 y = (igfx->pfit[0].ctrl.v >> 29) & 3;
448 if(igfx->pipe[y].pfit == nil)
449 igfx->pipe[y].pfit = &igfx->pfit[0];
451 igfx->ppstatus = snarfreg(igfx, 0x61200);
452 igfx->ppcontrol = snarfreg(igfx, 0x61204);
454 igfx->vgacntrl = snarfreg(igfx, 0x071400);
458 igfx->npipe = 2; /* A,B */
459 igfx->cdclk = 300; /* MHz */
463 igfx->npipe = 3; /* A,B,C */
464 igfx->cdclk = 400; /* MHz */
468 igfx->dpll[0].ctrl = snarfreg(igfx, 0xC6014);
469 igfx->dpll[0].fp0 = snarfreg(igfx, 0xC6040);
470 igfx->dpll[0].fp1 = snarfreg(igfx, 0xC6044);
471 igfx->dpll[1].ctrl = snarfreg(igfx, 0xC6018);
472 igfx->dpll[1].fp0 = snarfreg(igfx, 0xC6048);
473 igfx->dpll[1].fp1 = snarfreg(igfx, 0xC604c);
475 igfx->dpllsel[0] = snarfreg(igfx, 0xC7000);
477 igfx->drefctl = snarfreg(igfx, 0xC6200);
478 igfx->ssc4params = snarfreg(igfx, 0xC6210);
480 igfx->dp[0].ctl = snarfreg(igfx, 0x64000);
482 igfx->dp[x].ctl = snarfreg(igfx, 0xE4000 + 0x100*x);
484 igfx->hdmi[1].ctl = snarfreg(igfx, 0x0E1140); /* HDMI_CTL_B */
485 igfx->hdmi[1].bufctl[0] = snarfreg(igfx, 0x0FC810); /* HTMI_BUF_CTL_0 */
486 igfx->hdmi[1].bufctl[1] = snarfreg(igfx, 0x0FC81C); /* HTMI_BUF_CTL_1 */
487 igfx->hdmi[1].bufctl[2] = snarfreg(igfx, 0x0FC828); /* HTMI_BUF_CTL_2 */
488 igfx->hdmi[1].bufctl[3] = snarfreg(igfx, 0x0FC834); /* HTMI_BUF_CTL_3 */
490 igfx->hdmi[2].ctl = snarfreg(igfx, 0x0E1150); /* HDMI_CTL_C */
491 igfx->hdmi[2].bufctl[0] = snarfreg(igfx, 0x0FCC00); /* HTMI_BUF_CTL_4 */
492 igfx->hdmi[2].bufctl[1] = snarfreg(igfx, 0x0FCC0C); /* HTMI_BUF_CTL_5 */
493 igfx->hdmi[2].bufctl[2] = snarfreg(igfx, 0x0FCC18); /* HTMI_BUF_CTL_6 */
494 igfx->hdmi[2].bufctl[3] = snarfreg(igfx, 0x0FCC24); /* HTMI_BUF_CTL_7 */
496 igfx->hdmi[3].ctl = snarfreg(igfx, 0x0E1160); /* HDMI_CTL_D */
497 igfx->hdmi[3].bufctl[0] = snarfreg(igfx, 0x0FD000); /* HTMI_BUF_CTL_8 */
498 igfx->hdmi[3].bufctl[1] = snarfreg(igfx, 0x0FD00C); /* HTMI_BUF_CTL_9 */
499 igfx->hdmi[3].bufctl[2] = snarfreg(igfx, 0x0FD018); /* HTMI_BUF_CTL_10 */
500 igfx->hdmi[3].bufctl[3] = snarfreg(igfx, 0x0FD024); /* HTMI_BUF_CTL_11 */
502 igfx->lvds = snarfreg(igfx, 0x0E1180); /* LVDS_CTL */
506 igfx->npipe = 4; /* A,B,C,eDP */
507 igfx->cdclk = igfx->isult ? 450 : 540; /* MHz */
509 igfx->dpll[0].ctrl = snarfreg(igfx, 0x130040); /* LCPLL_CTL */
510 igfx->dpll[1].ctrl = snarfreg(igfx, 0x46040); /* WRPLL_CTL1 */
511 igfx->dpll[2].ctrl = snarfreg(igfx, 0x46060); /* WRPLL_CTL2 */
512 igfx->dpll[3].ctrl = snarfreg(igfx, 0x46020); /* SPLL_CTL */
514 for(x=0; x<nelem(igfx->dp); x++){
515 if(x == 3 && igfx->isult) /* no DDI D */
517 igfx->dp[x].bufctl = snarfreg(igfx, 0x64000 + 0x100*x);
518 igfx->dp[x].ctl = snarfreg(igfx, 0x64040 + 0x100*x);
520 igfx->dp[x].stat = snarfreg(igfx, 0x64044 + 0x100*x);
521 for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
522 igfx->dp[x].buftrans[y] = snarfreg(igfx, 0x64E00 + 0x60*x + 4*y);
523 igfx->dpllsel[x] = snarfreg(igfx, 0x46100 + 4*x);
529 igfx->rawclkfreq = snarfreg(igfx, 0xC6204);
531 /* cpu displayport A */
532 igfx->dp[0].auxctl = snarfreg(igfx, 0x64010);
533 igfx->dp[0].auxdat[0] = snarfreg(igfx, 0x64014);
534 igfx->dp[0].auxdat[1] = snarfreg(igfx, 0x64018);
535 igfx->dp[0].auxdat[2] = snarfreg(igfx, 0x6401C);
536 igfx->dp[0].auxdat[3] = snarfreg(igfx, 0x64020);
537 igfx->dp[0].auxdat[4] = snarfreg(igfx, 0x64024);
539 /* pch displayport B,C,D */
541 igfx->dp[x].auxctl = snarfreg(igfx, 0xE4010 + 0x100*x);
542 igfx->dp[x].auxdat[0] = snarfreg(igfx, 0xE4014 + 0x100*x);
543 igfx->dp[x].auxdat[1] = snarfreg(igfx, 0xE4018 + 0x100*x);
544 igfx->dp[x].auxdat[2] = snarfreg(igfx, 0xE401C + 0x100*x);
545 igfx->dp[x].auxdat[3] = snarfreg(igfx, 0xE4020 + 0x100*x);
546 igfx->dp[x].auxdat[4] = snarfreg(igfx, 0xE4024 + 0x100*x);
549 for(x=0; x<igfx->npipe; x++){
550 if(igfx->type == TypeHSW && x == 3){
551 igfx->pipe[x].pfit = &igfx->pfit[0];
554 igfx->pfit[x].pwrgate = snarfreg(igfx, 0x68060 + 0x800*x);
555 igfx->pfit[x].winpos = snarfreg(igfx, 0x68070 + 0x800*x);
556 igfx->pfit[x].winsize = snarfreg(igfx, 0x68074 + 0x800*x);
557 igfx->pfit[x].ctrl = snarfreg(igfx, 0x68080 + 0x800*x);
559 y = (igfx->pfit[x].ctrl.v >> 29) & 3;
560 if(igfx->pipe[y].pfit == nil)
561 igfx->pipe[y].pfit = &igfx->pfit[x];
564 igfx->ppstatus = snarfreg(igfx, 0xC7200);
565 igfx->ppcontrol = snarfreg(igfx, 0xC7204);
568 igfx->gmbus[x] = snarfreg(igfx, 0xC5100 + x*4);
569 igfx->gmbus[x] = snarfreg(igfx, 0xC5120);
571 igfx->adpa = snarfreg(igfx, 0x0E1100); /* DAC_CTL */
572 igfx->vgacntrl = snarfreg(igfx, 0x041000);
576 for(x=0; x<igfx->npipe; x++)
579 for(x=0; x<nelem(vga->edid); x++){
584 vga->edid[x] = snarfgmedid(igfx, 2, 0x50);
587 vga->edid[x] = snarfgmedid(igfx, 3, 0x50);
588 if(vga->edid[x] == nil)
590 for(l = vga->edid[x]->modelist; l != nil; l = l->next)
591 l->attr = mkattr(l->attr, "lcd", "1");
594 if(igfx->type == TypeHSW && igfx->isult)
599 vga->edid[x] = snarfdpedid(igfx, &igfx->dp[x-PortDPA], 0x50);
605 if(vga->edid[x] == nil){
608 vga->edid[x] = snarfgmedid(igfx, x + 1 & ~1 | x >> 1 & 1, 0x50);
609 if(vga->edid[x] == nil)
611 igfx->dp[x-PortDPA].hdmi = 1;
613 for(l = vga->edid[x]->modelist; l != nil; l = l->next)
614 l->attr = mkattr(l->attr, "display", "%d", x+1);
617 ctlr->flag |= Fsnarf;
621 options(Vga* vga, Ctlr* ctlr)
624 ctlr->flag |= Hlinear|Ulinear|Foptions;
629 Lcpll2k = Lcpll * 2000,
636 25175000,0, 25200000,0, 27000000,0, 27027000,0,
637 37762500,0, 37800000,0, 40500000,0, 40541000,0,
638 54000000,0, 54054000,0, 59341000,0, 59400000,0,
639 72000000,0, 74176000,0, 74250000,0, 81000000,0,
640 81081000,0, 89012000,0, 89100000,0, 108000000,0,
641 108108000,0, 111264000,0, 111375000,0, 148352000,0,
642 148500000,0, 162000000,0, 162162000,0, 222525000,0,
643 222750000,0, 296703000,0, 297000000,0, 233500000,1500,
644 245250000,1500, 247750000,1500, 253250000,1500, 298000000,1500,
645 169128000,2000, 169500000,2000, 179500000,2000, 202000000,2000,
646 256250000,4000, 262500000,4000, 270000000,4000, 272500000,4000,
647 273750000,4000, 280750000,4000, 281250000,4000, 286000000,4000,
648 291750000,4000, 267250000,5000, 268500000,5000
652 for(i=b; i<b+nelem(b); i+=2)
659 genwrpll(int freq, int *n2, int *p, int *r2)
661 int budget, N2, P, R2;
662 vlong f2k, a, b, c, d, Δ, bestΔ;
665 if(f2k == Lcpll2k){ /* bypass wrpll entirely and use lcpll */
671 budget = wrbudget(freq);
673 for(R2=Lcpll*2/400+1; R2<=Lcpll*2/48; R2++)
674 for(N2=2400*R2/Lcpll+1; N2<=4800*R2/Lcpll; N2++)
675 for(P=2; P<=64; P+=2){
686 bestΔ = f2k * *p * *r2;
687 bestΔ -= *n2 * Lcpll2k;
696 if(a < c && b < d && *p * *r2 * Δ < P * R2 * bestΔ
698 || a >= c && b >= d && N2 * *r2 * *r2 > *n2 * R2 * R2){
707 genpll(int freq, int cref, int P2, int *m1, int *m2, int *n, int *p1)
709 int M1, M2, M, N, P, P1;
715 for(M2=5; M2<=9; M2++)
716 // for(M1=10; M1<=20; M1++){
717 for(M1=12; M1<=22; M1++){
718 M = 5*(M1+2) + (M2+2);
719 if(M < 79 || M > 127)
720 // if(M < 70 || M > 120)
722 for(P1=1; P1<=8; P1++){
725 // if(P < 4 || P > 98)
731 if(a < 20*MHz || a > 400*MHz)
737 if(best < 0 || error < best){
750 getcref(Igfx *igfx, int x)
754 dpll = &igfx->dpll[x];
755 if(igfx->type == TypeG45){
756 if(((dpll->ctrl.v >> 13) & 3) == 3)
764 initdpll(Igfx *igfx, int x, int freq, int port)
766 int cref, m1, m2, n, n2, p1, p2, r2;
771 /* PLL Reference Input Select */
772 dpll = igfx->pipe[x].dpll;
773 dpll->ctrl.v &= ~(3<<13);
774 dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
778 /* transcoder dpll enable */
779 igfx->dpllsel[0].v |= 8<<(x*4);
780 /* program rawclock to 125MHz */
781 igfx->rawclkfreq.v = 125;
783 igfx->drefctl.v &= ~(3<<13);
784 igfx->drefctl.v &= ~(3<<11);
785 igfx->drefctl.v &= ~(3<<9);
786 igfx->drefctl.v &= ~(3<<7);
787 igfx->drefctl.v &= ~3;
790 igfx->drefctl.v |= 2<<11;
791 igfx->drefctl.v |= 1;
793 igfx->drefctl.v |= 2<<9;
797 * PLL Reference Input Select:
798 * 000 DREFCLK (default is 120 MHz) for DAC/HDMI/DVI/DP
799 * 001 Super SSC 120MHz super-spread clock
800 * 011 SSC Spread spectrum input clock (120MHz default) for LVDS/DP
802 dpll = igfx->pipe[x].fdi->dpll;
803 dpll->ctrl.v &= ~(7<<13);
804 dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
807 /* select port clock to pipe */
808 igfx->pipe[x].clksel.v = port+1-PortDPA<<29;
810 if(igfx->dp[port-PortDPA].hdmi){
811 /* select port clock */
812 igfx->dpllsel[port-PortDPA].v = 1<<31; /* WRPLL1 */
813 igfx->pipe[x].dpll = &igfx->dpll[1];
815 dpll = igfx->pipe[x].dpll;
817 dpll->ctrl.v = 1<<31;
818 /* LCPLL 2700 (non scc) reference */
819 dpll->ctrl.v |= 3<<28;
821 genwrpll(freq, &n2, &p1, &r2);
822 dpll->ctrl.v |= n2 << 16;
823 dpll->ctrl.v |= p1 << 8;
826 /* select port clock */
827 igfx->dpllsel[port-PortDPA].v = 1<<29; /* LCPLL 1350 */
828 /* keep preconfigured frequency settings, keep cdclk */
829 dpll = igfx->pipe[x].dpll;
830 dpll->ctrl.v &= ~(1<<31) & ~(1<<28) & ~(1<<26);
836 cref = getcref(igfx, x);
838 /* Dpll Mode select */
839 dpll->ctrl.v &= ~(3<<26);
840 dpll->ctrl.v |= (port == PortLCD ? 2 : 1)<<26;
842 /* P2 Clock Divide */
843 dpll->ctrl.v &= ~(3<<24);
846 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
849 /* generate 270MHz clock for displayport */
856 dpll->ctrl.v |= (1<<24);
858 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
862 /* Dpll VCO Enable */
863 dpll->ctrl.v |= (1<<31);
865 /* Dpll Serial DVO High Speed IO clock Enable */
867 dpll->ctrl.v |= (1<<30);
869 dpll->ctrl.v &= ~(1<<30);
871 /* VGA Mode Disable */
872 dpll->ctrl.v |= (1<<28);
874 dpll->fp0.v &= ~(0x3f<<16);
875 dpll->fp0.v |= n << 16;
876 dpll->fp0.v &= ~(0x3f<<8);
877 dpll->fp0.v |= m1 << 8;
878 dpll->fp0.v &= ~(0x3f<<0);
879 dpll->fp0.v |= m2 << 0;
881 /* FP0 P1 Post Divisor */
882 dpll->ctrl.v &= ~0xFF0000;
883 dpll->ctrl.v |= 0x010000<<(p1-1);
885 /* FP1 P1 Post divisor */
886 if(igfx->pci->did != 0x27a2){
887 dpll->ctrl.v &= ~0xFF;
888 dpll->ctrl.v |= 0x01<<(p1-1);
889 dpll->fp1.v = dpll->fp0.v;
896 needlanes(int freq, int lsclk, int bpp)
901 v = ((vlong)freq * bpp) / 8;
902 for(n=1; n<4 && v>lsclk; n<<=1, v>>=1)
908 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
913 m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
915 t->dm[0].v = (tu-1)<<25 | m;
919 m = ((uvlong)n * freq) / lsclk;
924 t->dm[1].v = t->dm[0].v;
925 t->dn[1].v = t->dn[0].v;
926 t->lm[1].v = t->lm[0].v;
927 t->ln[1].v = t->ln[0].v;
931 inittrans(Trans *t, Mode *m)
933 /* clear all but 27:28 frame start delay (initialized by bios) */
936 /* tans/pipe enable */
939 /* trans/pipe timing */
940 t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
941 t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);
942 t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
943 t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
952 initpipe(Igfx *igfx, Pipe *p, Mode *m, int bpc, int port)
954 static uchar bpctab[4] = { 8, 10, 6, 12 };
958 /* source image size */
959 p->src.v = (m->x - 1)<<16 | (m->y - 1);
962 /* panel fitter off */
963 p->pfit->ctrl.v &= ~(1<<31);
964 p->pfit->winpos.v = 0;
965 p->pfit->winsize.v = 0;
968 /* enable and set monitor timings for cpu pipe */
971 /* default for displayport */
972 lanes = needlanes(m->frequency, 270*MHz, 3*bpc);
976 if(fdi->rxctl.a != 0){
977 /* enable and set monitor timings for transcoder */
980 /* tx port width selection */
981 fdi->txctl.v &= ~(7<<19);
982 fdi->txctl.v |= (lanes-1)<<19;
984 /* rx port width selection */
985 fdi->rxctl.v &= ~(7<<19);
986 fdi->rxctl.v |= (lanes-1)<<19;
987 /* bits per color for transcoder */
988 for(i=0; i<nelem(bpctab); i++){
989 if(bpctab[i] == bpc){
990 fdi->rxctl.v &= ~(7<<16);
991 fdi->rxctl.v |= i<<16;
992 fdi->dpctl.v &= ~(7<<9);
993 fdi->dpctl.v |= i<<9;
998 /* enhanced framing on */
999 fdi->rxctl.v |= (1<<6);
1000 fdi->txctl.v |= (1<<18);
1002 /* tusize 1 and 2 */
1003 fdi->rxtu[0].v = (tu-1)<<25;
1004 fdi->rxtu[1].v = (tu-1)<<25;
1005 initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1006 }else if(igfx->type == TypeHSW){
1007 p->dpctl.v &= 0xf773733e; /* mbz */
1008 /* transcoder enable */
1009 p->dpctl.v |= 1<<31;
1010 /* DDI select (ignored by eDP) */
1011 p->dpctl.v &= ~(7<<28);
1012 p->dpctl.v |= (port-PortDPA)<<28;
1013 /* displayport SST or hdmi mode */
1014 p->dpctl.v &= ~(7<<24);
1015 if(!igfx->dp[port-PortDPA].hdmi)
1016 p->dpctl.v |= 2<<24;
1018 p->dpctl.v |= 3<<16;
1020 p->dpctl.v ^= 1<<16;
1022 p->dpctl.v ^= 1<<17;
1023 /* eDP input select: always on power well */
1024 p->dpctl.v &= ~(7<<12);
1026 if(igfx->dp[port-PortDPA].hdmi)
1029 p->dpctl.v &= ~(7<<1);
1030 p->dpctl.v |= lanes-1 << 1;
1034 /* bits per color for cpu pipe */
1035 for(i=0; i<nelem(bpctab); i++){
1036 if(bpctab[i] == bpc){
1037 if(igfx->type == TypeHSW){
1038 p->dpctl.v &= ~(7<<20);
1039 p->dpctl.v |= i<<20;
1041 p->conf.v &= ~(7<<5);
1047 initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1051 init(Vga* vga, Ctlr* ctlr)
1053 int x, nl, port, bpc;
1062 error("%s: unsupported color depth %d\n", ctlr->name, m->z);
1064 bpc = 8; /* bits per color channel */
1066 igfx = vga->private;
1069 igfx->vgacntrl.v |= (1<<31);
1071 /* disable all pipes and ports */
1072 igfx->ppcontrol.v &= 10; /* 15:4 mbz; unset 5<<0 */
1073 igfx->lvds.v &= ~(1<<31);
1074 igfx->adpa.v &= ~(1<<31);
1075 if(igfx->type == TypeG45)
1076 igfx->adpa.v |= (3<<10); /* Monitor DPMS: off */
1077 if(igfx->type == TypeHSW){
1078 for(x=1; x<nelem(igfx->dpll); x++)
1079 igfx->dpll[x].ctrl.v &= ~(1<<31);
1080 for(x=0; x<nelem(igfx->dpllsel); x++)
1081 igfx->dpllsel[x].v = 7<<29;
1083 for(x=0; x<nelem(igfx->dp); x++){
1084 igfx->dp[x].ctl.v &= ~(1<<31);
1085 igfx->dp[x].bufctl.v &= ~(1<<31);
1087 for(x=0; x<nelem(igfx->hdmi); x++)
1088 igfx->hdmi[x].ctl.v &= ~(1<<31);
1089 for(x=0; x<igfx->npipe; x++){
1090 /* disable displayport transcoders */
1091 igfx->pipe[x].dpctl.v &= ~(1<<31);
1092 igfx->pipe[x].fdi->dpctl.v &= ~(1<<31);
1093 if(igfx->type == TypeHSW){
1094 igfx->pipe[x].dpctl.v &= ~(7<<28);
1095 igfx->pipe[x].fdi->dpctl.v &= ~(7<<28);
1097 igfx->pipe[x].dpctl.v |= (3<<29);
1098 igfx->pipe[x].fdi->dpctl.v |= (3<<29);
1100 /* disable transcoder/pipe */
1101 igfx->pipe[x].conf.v &= ~(1<<31);
1102 igfx->pipe[x].fdi->conf.v &= ~(1<<31);
1105 if((val = dbattr(m->attr, "display")) != nil){
1107 if(igfx->type == TypeHSW && !igfx->dp[port-PortDPA].hdmi)
1109 }else if(dbattr(m->attr, "lcd") != nil)
1114 trace("%s: display #%d\n", ctlr->name, port+1);
1119 error("%s: display #%d not supported\n", ctlr->name, port+1);
1123 if(igfx->type == TypeHSW) /* unimplemented */
1125 if(igfx->type == TypeG45)
1126 x = (igfx->adpa.v >> 30) & 1;
1128 x = (igfx->adpa.v >> 29) & 3;
1129 igfx->adpa.v |= (1<<31);
1130 if(igfx->type == TypeG45){
1131 igfx->adpa.v &= ~(3<<10); /* Monitor DPMS: on */
1133 igfx->adpa.v &= ~(1<<15); /* ADPA Polarity Select */
1134 igfx->adpa.v |= 3<<3;
1136 igfx->adpa.v ^= 1<<3;
1138 igfx->adpa.v ^= 1<<4;
1143 if(igfx->type == TypeHSW)
1145 if(igfx->type == TypeG45)
1146 x = (igfx->lvds.v >> 30) & 1;
1148 x = (igfx->lvds.v >> 29) & 3;
1149 igfx->lvds.v |= (1<<31);
1150 igfx->ppcontrol.v |= 5;
1152 if(igfx->type == TypeG45){
1153 igfx->lvds.v &= ~(1<<24); /* data format select 18/24bpc */
1155 igfx->lvds.v &= ~(3<<20);
1157 igfx->lvds.v ^= 1<<20;
1159 igfx->lvds.v ^= 1<<21;
1161 igfx->lvds.v |= (1<<15); /* border enable */
1170 r = &igfx->dp[port - PortDPA].ctl;
1175 /* use PIPE_A for displayport */
1178 if(igfx->type == TypeHSW){
1179 if(port == PortDPA){
1180 /* only enable panel for eDP */
1181 igfx->ppcontrol.v |= 5;
1187 r->v &= ~(7<<28) & ~(1<<26) & ~(63<<19) & ~(3<<16) & ~(15<<11) & ~(1<<7) & ~31;
1188 /* displayport SST mode */
1190 /* link not in training, send normal pixels */
1192 if(igfx->dp[port-PortDPA].hdmi){
1193 /* hdmi: do not configure displayport */
1198 r = &igfx->dp[port - PortDPA].bufctl;
1202 r->v &= ~(7<<28) & ~(127<<17) & ~(255<<8) & ~(3<<5);
1203 /* grab lanes shared with port e when using port a */
1206 else if(port == PortDPE)
1207 igfx->dp[0].bufctl.v &= ~(1<<4);
1210 if(!igfx->dp[port-PortDPA].hdmi){
1211 nl = needlanes(m->frequency, 270*MHz, 3*bpc);
1212 /* x4 unsupported on port e */
1213 if(nl > 2 && port == PortDPE)
1217 /* port reversal: off */
1220 /* buffer translation (vsl/pel) */
1221 r = igfx->dp[port - PortDPA].buftrans;
1222 r[1].v = 0x0006000E; r[0].v = 0x00FFFFFF;
1223 r[3].v = 0x0005000A; r[2].v = 0x00D75FFF;
1224 r[5].v = 0x00040006; r[4].v = 0x00C30FFF;
1225 r[7].v = 0x000B0000; r[6].v = 0x80AAAFFF;
1226 r[9].v = 0x0005000A; r[8].v = 0x00FFFFFF;
1227 r[11].v = 0x000C0004; r[10].v = 0x00D75FFF;
1228 r[13].v = 0x000B0000; r[12].v = 0x80C30FFF;
1229 r[15].v = 0x00040006; r[14].v = 0x00FFFFFF;
1230 r[17].v = 0x000B0000; r[16].v = 0x80D75FFF;
1231 r[19].v = 0x00040006; r[18].v = 0x00FFFFFF;
1238 /* port width selection */
1240 r->v |= needlanes(m->frequency, 270*MHz, 3*bpc)-1 << 19;
1242 /* port reversal: off */
1246 /* displayport transcoder */
1247 if(port == PortDPA){
1250 /* pll frequency: 270mhz */
1257 } else if(igfx->pipe[x].fdi->dpctl.a != 0){
1260 /* audio output: disable */
1262 /* transcoder displayport configuration */
1263 r = &igfx->pipe[x].fdi->dpctl;
1264 /* transcoder enable */
1266 /* port select: B,C,D */
1268 r->v |= (port-PortDPB)<<29;
1280 /* plane enable, 32bpp */
1281 p->dsp->cntr.v = (1<<31) | (6<<26);
1282 if(igfx->type == TypeG45)
1283 p->dsp->cntr.v |= x<<24; /* pipe assign */
1285 p->dsp->cntr.v &= ~511; /* mbz */
1287 /* stride must be 64 byte aligned */
1288 p->dsp->stride.v = m->x * (m->z / 8);
1289 p->dsp->stride.v += 63;
1290 p->dsp->stride.v &= ~63;
1292 /* virtual width in pixels */
1293 vga->virtx = p->dsp->stride.v / (m->z / 8);
1295 /* plane position and size */
1297 p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1); /* sic */
1300 p->dsp->linoff.v = 0;
1301 p->dsp->tileoff.v = 0;
1302 p->dsp->leftsurf.v = 0;
1304 /* cursor plane off */
1306 if(igfx->type == TypeG45)
1307 p->cur->cntr.v |= x<<28; /* pipe assign */
1311 if(initdpll(igfx, x, m->frequency, port) < 0)
1312 error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
1314 initpipe(igfx, p, m, bpc, port);
1316 ctlr->flag |= Finit;
1320 loadtrans(Igfx *igfx, Trans *t)
1327 /* program trans/pipe timings */
1328 loadreg(igfx, t->ht);
1329 loadreg(igfx, t->hb);
1330 loadreg(igfx, t->hs);
1331 loadreg(igfx, t->vt);
1332 loadreg(igfx, t->vb);
1333 loadreg(igfx, t->vs);
1334 loadreg(igfx, t->vss);
1336 loadreg(igfx, t->dm[0]);
1337 loadreg(igfx, t->dn[0]);
1338 loadreg(igfx, t->lm[0]);
1339 loadreg(igfx, t->ln[0]);
1340 loadreg(igfx, t->dm[1]);
1341 loadreg(igfx, t->dn[1]);
1342 loadreg(igfx, t->lm[1]);
1343 loadreg(igfx, t->ln[1]);
1345 if(t->dpll != nil && igfx->type != TypeHSW){
1347 t->dpll->ctrl.v &= ~(1<<31);
1348 loadreg(igfx, t->dpll->ctrl);
1349 loadreg(igfx, t->dpll->fp0);
1350 loadreg(igfx, t->dpll->fp1);
1353 t->dpll->ctrl.v |= (1<<31);
1354 loadreg(igfx, t->dpll->ctrl);
1358 /* workarround: set timing override bit */
1359 csr(igfx, t->chicken.a, 0, 1<<31);
1361 /* enable displayport transcoder */
1362 loadreg(igfx, t->dpctl);
1364 /* enable trans/pipe */
1365 t->conf.v |= (1<<31);
1366 t->conf.v &= ~(1<<30);
1367 loadreg(igfx, t->conf);
1368 for(i=0; i<100; i++){
1370 if(rr(igfx, t->conf.a) & (1<<30))
1376 enablepipe(Igfx *igfx, int x)
1382 if((p->conf.v & (1<<31)) == 0)
1383 return; /* pipe is disabled, done */
1385 /* select pipe clock */
1386 loadreg(igfx, p->clksel);
1388 if(p->fdi->rxctl.a != 0){
1389 p->fdi->rxctl.v &= ~(1<<31);
1390 p->fdi->rxctl.v &= ~(1<<4); /* rawclk */
1391 p->fdi->rxctl.v |= (1<<13); /* enable pll */
1392 loadreg(igfx, p->fdi->rxctl);
1394 p->fdi->rxctl.v |= (1<<4); /* pcdclk */
1395 loadreg(igfx, p->fdi->rxctl);
1397 p->fdi->txctl.v &= ~(7<<8 | 1); /* clear auto training bits */
1398 p->fdi->txctl.v &= ~(1<<31); /* disable */
1399 p->fdi->txctl.v |= (1<<14); /* enable pll */
1400 loadreg(igfx, p->fdi->txctl);
1404 /* image size (vga needs to be off) */
1405 loadreg(igfx, p->src);
1407 /* set panel fitter as needed */
1409 loadreg(igfx, p->pfit->ctrl);
1410 loadreg(igfx, p->pfit->winpos);
1411 loadreg(igfx, p->pfit->winsize); /* arm */
1414 /* keep planes disabled while pipe comes up */
1415 if(igfx->type == TypeG45)
1418 /* enable cpu pipe */
1422 loadreg(igfx, p->dsp->cntr);
1423 loadreg(igfx, p->dsp->linoff);
1424 loadreg(igfx, p->dsp->stride);
1425 loadreg(igfx, p->dsp->tileoff);
1426 loadreg(igfx, p->dsp->size);
1427 loadreg(igfx, p->dsp->pos);
1428 loadreg(igfx, p->dsp->surf); /* arm */
1429 loadreg(igfx, p->dsp->leftsurf);
1431 /* program cursor */
1432 loadreg(igfx, p->cur->cntr);
1433 loadreg(igfx, p->cur->pos);
1434 loadreg(igfx, p->cur->base); /* arm */
1437 if(igfx->type == TypeG45) {
1438 p->conf.v &= ~(3<<18);
1439 loadreg(igfx, p->conf);
1442 if(p->fdi->rxctl.a != 0){
1444 loadreg(igfx, p->fdi->rxtu[1]);
1445 loadreg(igfx, p->fdi->rxtu[0]);
1446 loadreg(igfx, p->fdi->rxmisc);
1448 if(igfx->type == TypeSNB){
1449 /* unmask bit lock and symbol lock bits */
1450 csr(igfx, p->fdi->rximr.a, 3<<8, 0);
1452 p->fdi->rxctl.v &= ~(3<<8); /* link train pattern1 */
1453 p->fdi->rxctl.v |= 1<<31; /* enable */
1454 loadreg(igfx, p->fdi->rxctl);
1456 p->fdi->txctl.v &= ~(3<<8); /* link train pattern1 */
1457 p->fdi->txctl.v |= 1<<31; /* enable */
1458 loadreg(igfx, p->fdi->txctl);
1460 /* wait for bit lock */
1461 for(i=0; i<10; i++){
1463 if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
1466 csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
1468 /* switch to link train pattern2 */
1469 csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
1470 csr(igfx, p->fdi->txctl.a, 3<<8, 1<<8);
1472 /* wait for symbol lock */
1473 for(i=0; i<10; i++){
1475 if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
1478 csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
1480 /* switch to link train normal */
1481 csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
1482 csr(igfx, p->fdi->txctl.a, 0, 3<<8);
1484 /* wait idle pattern time */
1487 p->fdi->rxctl.v &= ~(3<<8); /* link train pattern 00 */
1488 p->fdi->rxctl.v |= 1<<10; /* auto train enable */
1489 p->fdi->rxctl.v |= 1<<31; /* enable */
1490 loadreg(igfx, p->fdi->rxctl);
1492 p->fdi->txctl.v &= ~(3<<8); /* link train pattern 00 */
1493 p->fdi->txctl.v |= 1<<10; /* auto train enable */
1494 p->fdi->txctl.v |= 1<<31; /* enable */
1495 loadreg(igfx, p->fdi->txctl);
1497 /* wait for link training done */
1498 for(i=0; i<200; i++){
1500 if(rr(igfx, p->fdi->txctl.a) & 2)
1506 /* enable the transcoder */
1507 loadtrans(igfx, p->fdi);
1511 disabletrans(Igfx *igfx, Trans *t)
1515 /* deselect pipe clock */
1516 csr(igfx, t->clksel.a, 7<<29, 0);
1518 /* disable displayport transcoder */
1519 if(igfx->type == TypeHSW){
1520 csr(igfx, t->dpctl.a, 15<<28, 0);
1521 csr(igfx, t->ht.a, ~0, 0);
1522 csr(igfx, t->hb.a, ~0, 0);
1523 csr(igfx, t->hs.a, ~0, 0);
1524 csr(igfx, t->vt.a, ~0, 0);
1525 csr(igfx, t->vb.a, ~0, 0);
1526 csr(igfx, t->vs.a, ~0, 0);
1527 csr(igfx, t->vss.a, ~0, 0);
1529 csr(igfx, t->dpctl.a, 1<<31, 3<<29);
1531 /* disable transcoder / pipe */
1532 csr(igfx, t->conf.a, 1<<31, 0);
1533 for(i=0; i<100; i++){
1535 if((rr(igfx, t->conf.a) & (1<<30)) == 0)
1538 /* workarround: clear timing override bit */
1539 csr(igfx, t->chicken.a, 1<<31, 0);
1542 if(igfx->type != TypeHSW && t->dpll != nil)
1543 csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
1547 disablepipe(Igfx *igfx, int x)
1554 csr(igfx, p->dsp->cntr.a, 1<<31, 0);
1555 wr(igfx, p->dsp->surf.a, 0); /* arm */
1557 if(igfx->type == TypeHSW)
1558 csr(igfx, p->cur->cntr.a, 0x3F, 0);
1560 csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
1561 wr(igfx, p->cur->base.a, 0); /* arm */
1563 /* display/overlay/cursor planes off */
1564 if(igfx->type == TypeG45)
1565 csr(igfx, p->conf.a, 0, 3<<18);
1566 csr(igfx, p->src.a, ~0, 0);
1568 /* disable cpu pipe */
1569 disabletrans(igfx, p);
1571 /* disable panel fitter */
1573 csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
1575 /* disable fdi transmitter and receiver */
1576 csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
1577 csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
1579 /* disable pch transcoder */
1580 disabletrans(igfx, p->fdi);
1582 /* disable pch dpll enable bit */
1583 if(igfx->type != TypeHSW)
1584 csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
1588 load(Vga* vga, Ctlr* ctlr)
1593 igfx = vga->private;
1596 if(igfx->ppcontrol.a != 0){
1597 csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
1598 for(x=0; x<5000; x++){
1600 if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
1606 csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
1607 csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
1608 csr(igfx, igfx->adpa.a, 1<<31, 0);
1609 csr(igfx, igfx->lvds.a, 1<<31, 0);
1610 for(x = 0; x < nelem(igfx->dp); x++){
1611 csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
1612 if(igfx->dp[x].bufctl.a != 0){
1613 csr(igfx, igfx->dp[x].bufctl.a, 1<<31, 0);
1614 /* wait for buffers to return to idle */
1617 if(rr(igfx, igfx->dp[x].bufctl.a) & 1<<7)
1622 for(x = 0; x < nelem(igfx->hdmi); x++)
1623 csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
1625 /* disable vga plane */
1626 csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
1628 /* turn off all pipes */
1629 for(x = 0; x < igfx->npipe; x++)
1630 disablepipe(igfx, x);
1632 if(igfx->type == TypeG45){
1633 /* toggle dsp a on and off (from enable sequence) */
1634 csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);
1635 csr(igfx, igfx->pipe[0].dsp->cntr.a, 0, 1<<31);
1636 wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1637 csr(igfx, igfx->pipe[0].dsp->cntr.a, 1<<31, 0);
1638 wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1639 csr(igfx, igfx->pipe[0].conf.a, 0, 3<<18);
1642 if(igfx->type == TypeHSW){
1643 /* deselect port clock */
1644 for(x=0; x<nelem(igfx->dpllsel); x++)
1645 csr(igfx, igfx->dpllsel[x].a, 0, 7<<29);
1647 /* disable dpll's other than LCPLL */
1648 for(x=1; x<nelem(igfx->dpll); x++)
1649 csr(igfx, igfx->dpll[x].ctrl.a, 1<<31, 0);
1652 /* program new clock sources */
1653 loadreg(igfx, igfx->rawclkfreq);
1654 loadreg(igfx, igfx->drefctl);
1655 /* program cpu pll */
1656 if(igfx->type == TypeHSW)
1657 for(x=0; x<nelem(igfx->dpll); x++)
1658 loadreg(igfx, igfx->dpll[x].ctrl);
1661 /* set lvds before enabling dpll */
1662 loadreg(igfx, igfx->lvds);
1664 /* new dpll setting */
1665 for(x=0; x<nelem(igfx->dpllsel); x++)
1666 loadreg(igfx, igfx->dpllsel[x]);
1668 /* program all pipes */
1669 for(x = 0; x < igfx->npipe; x++)
1670 enablepipe(igfx, x);
1672 /* program vga plane */
1673 loadreg(igfx, igfx->vgacntrl);
1676 loadreg(igfx, igfx->adpa);
1677 loadreg(igfx, igfx->sdvob);
1678 loadreg(igfx, igfx->sdvoc);
1679 for(x = 0; x < nelem(igfx->dp); x++){
1680 for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
1681 loadreg(igfx, igfx->dp[x].buftrans[y]);
1682 loadreg(igfx, igfx->dp[x].bufctl);
1683 if(enabledp(igfx, &igfx->dp[x]) < 0)
1684 ctlr->flag |= Ferror;
1687 /* program lcd power */
1688 loadreg(igfx, igfx->ppcontrol);
1690 ctlr->flag |= Fload;
1694 dumpreg(char *name, char *item, Reg r)
1699 printitem(name, item);
1700 Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
1704 dumphex(char *name, char *item, uchar *data, int len)
1708 for(i=0; i<len; i++){
1711 Bprint(&stdout, "\n");
1712 printitem(name, item);
1713 Bprint(&stdout, " [%.2x] =", i);
1715 Bprint(&stdout, " %.2X", data[i]);
1717 Bprint(&stdout, "\n");
1721 dumptiming(char *name, Trans *t)
1725 if(t->dm[0].a != 0 && t->dm[0].v != 0){
1726 tu = 1+((t->dm[0].v >> 25) & 0x3f);
1727 printitem(name, "dm1 tu");
1728 Bprint(&stdout, " %d\n", tu);
1730 m = t->dm[0].v & 0xffffff;
1733 printitem(name, "dm1/dn1");
1734 Bprint(&stdout, " %f\n", (double)m / (double)n);
1740 printitem(name, "lm1/ln1");
1741 Bprint(&stdout, " %f\n", (double)m / (double)n);
1747 dumptrans(char *name, Trans *t)
1749 dumpreg(name, "conf", t->conf);
1751 dumpreg(name, "dm1", t->dm[0]);
1752 dumpreg(name, "dn1", t->dn[0]);
1753 dumpreg(name, "lm1", t->lm[0]);
1754 dumpreg(name, "ln1", t->ln[0]);
1755 dumpreg(name, "dm2", t->dm[1]);
1756 dumpreg(name, "dn2", t->dn[1]);
1757 dumpreg(name, "lm2", t->lm[1]);
1758 dumpreg(name, "ln2", t->ln[1]);
1760 dumptiming(name, t);
1762 dumpreg(name, "ht", t->ht);
1763 dumpreg(name, "hb", t->hb);
1764 dumpreg(name, "hs", t->hs);
1766 dumpreg(name, "vt", t->vt);
1767 dumpreg(name, "vb", t->vb);
1768 dumpreg(name, "vs", t->vs);
1769 dumpreg(name, "vss", t->vss);
1771 dumpreg(name, "dpctl", t->dpctl);
1772 dumpreg(name, "clksel", t->clksel);
1776 dumppipe(Igfx *igfx, int x)
1783 snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
1784 dumpreg(name, "src", p->src);
1787 snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
1788 dumptrans(name, p->fdi);
1789 dumpreg(name, "txctl", p->fdi->txctl);
1790 dumpreg(name, "rxctl", p->fdi->rxctl);
1791 dumpreg(name, "rxmisc", p->fdi->rxmisc);
1792 dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
1793 dumpreg(name, "rxtu2", p->fdi->rxtu[1]);
1795 snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
1796 dumpreg(name, "cntr", p->dsp->cntr);
1797 dumpreg(name, "linoff", p->dsp->linoff);
1798 dumpreg(name, "stride", p->dsp->stride);
1799 dumpreg(name, "surf", p->dsp->surf);
1800 dumpreg(name, "tileoff", p->dsp->tileoff);
1801 dumpreg(name, "leftsurf", p->dsp->leftsurf);
1802 dumpreg(name, "pos", p->dsp->pos);
1803 dumpreg(name, "size", p->dsp->size);
1805 snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
1806 dumpreg(name, "cntr", p->cur->cntr);
1807 dumpreg(name, "base", p->cur->base);
1808 dumpreg(name, "pos", p->cur->pos);
1812 dumpdpll(Igfx *igfx, int x)
1814 int cref, m1, m2, n, p1, p2;
1820 dpll = &igfx->dpll[x];
1821 snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
1823 dumpreg(name, "ctrl", dpll->ctrl);
1824 dumpreg(name, "fp0", dpll->fp0);
1825 dumpreg(name, "fp1", dpll->fp1);
1827 if(igfx->type == TypeHSW)
1830 p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
1831 if(((dpll->ctrl.v >> 24) & 3) == 1)
1833 m = (dpll->ctrl.v >> 16) & 0xFF;
1834 for(p1 = 1; p1 <= 8; p1++)
1837 printitem(name, "ctrl p1");
1838 Bprint(&stdout, " %d\n", p1);
1839 printitem(name, "ctrl p2");
1840 Bprint(&stdout, " %d\n", p2);
1842 n = (dpll->fp0.v >> 16) & 0x3f;
1843 m1 = (dpll->fp0.v >> 8) & 0x3f;
1844 m2 = (dpll->fp0.v >> 0) & 0x3f;
1846 cref = getcref(igfx, x);
1847 freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
1849 printitem(name, "fp0 m1");
1850 Bprint(&stdout, " %d\n", m1);
1851 printitem(name, "fp0 m2");
1852 Bprint(&stdout, " %d\n", m2);
1853 printitem(name, "fp0 n");
1854 Bprint(&stdout, " %d\n", n);
1856 printitem(name, "cref");
1857 Bprint(&stdout, " %d\n", cref);
1858 printitem(name, "fp0 freq");
1859 Bprint(&stdout, " %lld\n", freq);
1863 dump(Vga* vga, Ctlr* ctlr)
1869 if((igfx = vga->private) == nil)
1872 for(x=0; x<igfx->npipe; x++)
1875 for(x=0; x<nelem(igfx->dpll); x++)
1878 for(x=0; x<nelem(igfx->dpllsel); x++){
1879 snprint(name, sizeof(name), "%s dpllsel %c", ctlr->name, 'a'+x);
1880 dumpreg(name, "dpllsel", igfx->dpllsel[x]);
1883 dumpreg(ctlr->name, "drefctl", igfx->drefctl);
1884 dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
1885 dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
1887 for(x=0; x<nelem(igfx->dp); x++){
1888 if(igfx->dp[x].ctl.a == 0)
1890 snprint(name, sizeof(name), "%s dp %c", ctlr->name, 'a'+x);
1891 dumpreg(name, "ctl", igfx->dp[x].ctl);
1892 dumpreg(name, "bufctl", igfx->dp[x].bufctl);
1893 dumpreg(name, "stat", igfx->dp[x].stat);
1894 dumphex(name, "dpcd", igfx->dp[x].dpcd, sizeof(igfx->dp[x].dpcd));
1895 for(y=0; y<nelem(igfx->dp[x].buftrans); y++){
1896 snprint(name, sizeof(name), "%s buftrans %c %d", ctlr->name, 'a'+x, y);
1897 dumpreg(name, "ctl", igfx->dp[x].buftrans[y]);
1900 for(x=0; x<nelem(igfx->hdmi); x++){
1901 snprint(name, sizeof(name), "%s hdmi %c", ctlr->name, 'a'+x);
1902 dumpreg(name, "ctl", igfx->hdmi[x].ctl);
1905 for(x=0; x<nelem(igfx->pfit); x++){
1906 snprint(name, sizeof(name), "%s pfit %c", ctlr->name, 'a'+x);
1907 dumpreg(name, "ctrl", igfx->pfit[x].ctrl);
1908 dumpreg(name, "winpos", igfx->pfit[x].winpos);
1909 dumpreg(name, "winsize", igfx->pfit[x].winsize);
1910 dumpreg(name, "pwrgate", igfx->pfit[x].pwrgate);
1913 dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
1914 dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);
1916 dumpreg(ctlr->name, "adpa", igfx->adpa);
1917 dumpreg(ctlr->name, "lvds", igfx->lvds);
1918 dumpreg(ctlr->name, "sdvob", igfx->sdvob);
1919 dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
1921 dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
1925 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
1930 if(dp->auxctl.a == 0){
1931 werrstr("not present");
1936 while(rr(igfx, dp->auxctl.a) & (1<<31)){
1944 /* clear sticky bits */
1945 wr(igfx, dp->auxctl.a, (1<<28) | (1<<25) | (1<<30));
1947 for(i=0; i<nelem(dp->auxdat); i++){
1949 w |= buf[i*4+1]<<16;
1952 wr(igfx, dp->auxdat[i].a, w);
1955 /* 2X Bit Clock divider */
1956 w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3ff)) >> 1;
1957 if(w < 1 || w > 0x3fd){
1958 werrstr("bad clock");
1962 /* hack: slow down a bit */
1965 w |= 1<<31; /* SendBusy */
1966 w |= 1<<29; /* interrupt disabled */
1967 w |= 3<<26; /* timeout 1600µs */
1968 w |= len<<20; /* send bytes */
1969 w |= 5<<16; /* precharge time (5*2 = 10µs) */
1970 wr(igfx, dp->auxctl.a, w);
1974 w = rr(igfx, dp->auxctl.a);
1975 if((w & (1<<30)) != 0)
1984 werrstr("receive timeout");
1988 werrstr("receive error");
1992 len = (w >> 20) & 0x1f;
1993 for(i=0; i<nelem(dp->auxdat); i++){
1994 w = rr(igfx, dp->auxdat[i].a);
2012 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
2019 memset(buf, 0, sizeof(buf));
2020 buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
2025 if(data != nil && len > 0){
2026 if((cmd & CmdRead) == 0)
2027 memmove(buf+4, data, len);
2029 if((cmd & CmdRead) == 0)
2032 if((r = dpauxio(igfx, dp, buf, r)) < 0){
2033 trace("%s: dpauxio: dp %c, cmd %x, addr %x, len %d: %r\n",
2034 igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]), cmd, addr, len);
2037 if(r == 0 || data == nil || len == 0)
2039 if((cmd & CmdRead) != 0){
2042 memmove(data, buf+1, len);
2048 rdpaux(Igfx *igfx, Dp *dp, int addr)
2051 if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
2056 wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
2058 if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
2064 enabledp(Igfx *igfx, Dp *dp)
2071 if((dp->ctl.v & (1<<31)) == 0)
2074 /* FIXME: always times out */
2075 if(igfx->type == TypeHSW && dp == &igfx->dp[0])
2078 /* Link configuration */
2079 wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000);
2080 w = dp->ctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
2081 wdpaux(igfx, dp, 0x101, w+1);
2085 /* Link training pattern 1 */
2086 dp->ctl.v &= ~(7<<8);
2087 loadreg(igfx, dp->ctl);
2088 for(try = 0;;try++){
2091 /* Link training pattern 1 */
2092 wdpaux(igfx, dp, 0x102, 0x01);
2094 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2096 if(r & 1) /* LANE0_CR_DONE */
2099 trace("pattern1 finished: %x\n", r);
2101 /* Link training pattern 2 */
2102 dp->ctl.v &= ~(7<<8);
2104 loadreg(igfx, dp->ctl);
2105 for(try = 0;;try++){
2108 /* Link training pattern 2 */
2109 wdpaux(igfx, dp, 0x102, 0x02);
2111 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2116 trace("pattern2 finished: %x\n", r);
2118 if(igfx->type == TypeHSW){
2119 /* set link training to idle pattern and wait for 5 idle
2121 dp->ctl.v &= ~(7<<8);
2123 loadreg(igfx, dp->ctl);
2124 for(try=0; try<10; try++){
2126 if(rr(igfx, dp->stat.a) & (1<<25))
2132 dp->ctl.v &= ~(7<<8);
2134 loadreg(igfx, dp->ctl);
2135 wdpaux(igfx, dp, 0x102, 0x00);
2139 trace("training failed: %x\n", r);
2142 dp->ctl.v &= ~(1<<31);
2143 loadreg(igfx, dp->ctl);
2144 wdpaux(igfx, dp, 0x102, 0x00);
2149 edidshift(uchar buf[256])
2154 /* shift if neccesary so edid block is at the start */
2155 for(i=0; i<256-8; i++){
2156 if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
2157 && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
2158 memmove(tmp, buf, i);
2159 memmove(buf, buf + i, 256 - i);
2160 memmove(buf + (256 - i), tmp, i);
2168 snarfdpedid(Igfx *igfx, Dp *dp, int addr)
2174 for(i=0; i<sizeof(dp->dpcd); i+=16)
2175 if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
2178 if(dp->dpcd[0] == 0) /* nothing there, dont try to get edid */
2181 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
2184 for(i=0; i<sizeof(buf); i+=16){
2185 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2187 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2189 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2191 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2193 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2198 dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
2200 if((e = parseedid128(edidshift(buf))) == nil)
2201 trace("%s: snarfdpedid: dp %c: %r\n", igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]));
2206 GMBUSCP = 0, /* Clock/Port selection */
2207 GMBUSCS = 1, /* Command/Status */
2208 GMBUSST = 2, /* Status Register */
2209 GMBUSDB = 3, /* Data Buffer Register */
2210 GMBUSIM = 4, /* Interrupt Mask */
2211 GMBUSIX = 5, /* Index Register */
2215 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
2220 if(igfx->gmbus[GMBUSCP].a == 0)
2223 wr(igfx, igfx->gmbus[GMBUSCP].a, port);
2224 wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
2226 /* bus cycle without index and stop, byte count, slave address, read */
2227 wr(igfx, igfx->gmbus[GMBUSCS].a, 1<<30 | 5<<25 | len<<16 | addr<<1 | 1);
2232 for(t=0; t<100; t++){
2233 x = rr(igfx, igfx->gmbus[GMBUSST].a);
2238 if((x & (1<<11)) == 0)
2246 y = rr(igfx, igfx->gmbus[GMBUSDB].a);
2249 data[n++] = y & 0xff, y >>= 8;
2251 data[n++] = y & 0xff, y >>= 8;
2253 data[n++] = y & 0xff, y >>= 8;
2255 data[n++] = y & 0xff;
2263 snarfgmedid(Igfx *igfx, int port, int addr)
2268 if(gmbusread(igfx, port, addr, buf, 128) != 128)
2270 if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
2273 return parseedid128(edidshift(buf));
2279 options, /* options */