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 = 400; /* 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);
848 dpll->ctrl.v |= (1<<24);
850 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
853 /* generate 270MHz clock for displayport */
860 dpll->ctrl.v |= (1<<24);
862 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
866 /* Dpll VCO Enable */
867 dpll->ctrl.v |= (1<<31);
869 /* Dpll Serial DVO High Speed IO clock Enable */
871 dpll->ctrl.v |= (1<<30);
873 dpll->ctrl.v &= ~(1<<30);
875 /* VGA Mode Disable */
876 if(igfx->type == TypeG45)
877 dpll->ctrl.v |= (1<<28);
879 dpll->fp0.v &= ~(0x3f<<16);
880 dpll->fp0.v |= n << 16;
881 dpll->fp0.v &= ~(0x3f<<8);
882 dpll->fp0.v |= m1 << 8;
883 dpll->fp0.v &= ~(0x3f<<0);
884 dpll->fp0.v |= m2 << 0;
886 /* FP0 P1 Post Divisor */
887 dpll->ctrl.v &= ~0xFF0000;
888 dpll->ctrl.v |= 0x010000<<(p1-1);
890 /* FP1 P1 Post divisor */
891 if(igfx->pci->did != 0x27a2){
892 dpll->ctrl.v &= ~0xFF;
893 dpll->ctrl.v |= 0x01<<(p1-1);
894 dpll->fp1.v = dpll->fp0.v;
901 needlanes(int freq, int lsclk, int bpp)
906 v = ((vlong)freq * bpp) / 8;
907 for(n=1; n<4 && v>lsclk; n<<=1, v>>=1)
913 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
918 m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
920 t->dm[0].v = (tu-1)<<25 | m;
924 m = ((uvlong)n * freq) / lsclk;
929 t->dm[1].v = t->dm[0].v;
930 t->dn[1].v = t->dn[0].v;
931 t->lm[1].v = t->lm[0].v;
932 t->ln[1].v = t->ln[0].v;
936 inittrans(Trans *t, Mode *m)
938 /* clear all but 27:28 frame start delay (initialized by bios) */
941 /* tans/pipe enable */
944 /* trans/pipe timing */
945 t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
946 t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);
947 t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
948 t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
957 initpipe(Igfx *igfx, Pipe *p, Mode *m, int bpc, int port)
959 static uchar bpctab[4] = { 8, 10, 6, 12 };
963 /* source image size */
964 p->src.v = (m->x - 1)<<16 | (m->y - 1);
967 /* panel fitter off */
968 p->pfit->ctrl.v &= ~(1<<31);
969 p->pfit->winpos.v = 0;
970 p->pfit->winsize.v = 0;
973 /* enable and set monitor timings for cpu pipe */
976 /* default for displayport */
977 lanes = needlanes(m->frequency, 270*MHz, 3*bpc);
981 if(fdi->rxctl.a != 0){
982 /* enable and set monitor timings for transcoder */
985 /* tx port width selection */
986 fdi->txctl.v &= ~(7<<19);
987 fdi->txctl.v |= (lanes-1)<<19;
989 /* rx port width selection */
990 fdi->rxctl.v &= ~(7<<19);
991 fdi->rxctl.v |= (lanes-1)<<19;
992 /* bits per color for transcoder */
993 for(i=0; i<nelem(bpctab); i++){
994 if(bpctab[i] == bpc){
995 fdi->rxctl.v &= ~(7<<16);
996 fdi->rxctl.v |= i<<16;
997 fdi->dpctl.v &= ~(7<<9);
998 fdi->dpctl.v |= i<<9;
1003 /* enhanced framing on */
1004 fdi->rxctl.v |= (1<<6);
1005 fdi->txctl.v |= (1<<18);
1007 /* tusize 1 and 2 */
1008 fdi->rxtu[0].v = (tu-1)<<25;
1009 fdi->rxtu[1].v = (tu-1)<<25;
1010 initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1011 }else if(igfx->type == TypeHSW){
1012 p->dpctl.v &= 0xf773733e; /* mbz */
1013 /* transcoder enable */
1014 p->dpctl.v |= 1<<31;
1015 /* DDI select (ignored by eDP) */
1016 p->dpctl.v &= ~(7<<28);
1017 p->dpctl.v |= (port-PortDPA)<<28;
1018 /* displayport SST or hdmi mode */
1019 p->dpctl.v &= ~(7<<24);
1020 if(!igfx->dp[port-PortDPA].hdmi)
1021 p->dpctl.v |= 2<<24;
1023 p->dpctl.v |= 3<<16;
1025 p->dpctl.v ^= 1<<16;
1027 p->dpctl.v ^= 1<<17;
1028 /* eDP input select: always on power well */
1029 p->dpctl.v &= ~(7<<12);
1031 if(igfx->dp[port-PortDPA].hdmi)
1034 p->dpctl.v &= ~(7<<1);
1035 p->dpctl.v |= lanes-1 << 1;
1039 /* bits per color for cpu pipe */
1040 for(i=0; i<nelem(bpctab); i++){
1041 if(bpctab[i] == bpc){
1042 if(igfx->type == TypeHSW){
1043 p->dpctl.v &= ~(7<<20);
1044 p->dpctl.v |= i<<20;
1046 p->conf.v &= ~(7<<5);
1052 initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1056 init(Vga* vga, Ctlr* ctlr)
1058 int x, nl, port, bpc;
1067 error("%s: unsupported color depth %d\n", ctlr->name, m->z);
1069 bpc = 8; /* bits per color channel */
1071 igfx = vga->private;
1074 igfx->vgacntrl.v |= (1<<31);
1076 /* disable all pipes and ports */
1077 igfx->ppcontrol.v &= 10; /* 15:4 mbz; unset 5<<0 */
1078 igfx->lvds.v &= ~(1<<31);
1079 igfx->adpa.v &= ~(1<<31);
1080 if(igfx->type == TypeG45)
1081 igfx->adpa.v |= (3<<10); /* Monitor DPMS: off */
1082 if(igfx->type == TypeHSW){
1083 for(x=1; x<nelem(igfx->dpll); x++)
1084 igfx->dpll[x].ctrl.v &= ~(1<<31);
1085 for(x=0; x<nelem(igfx->dpllsel); x++)
1086 igfx->dpllsel[x].v = 7<<29;
1088 for(x=0; x<nelem(igfx->dp); x++){
1089 igfx->dp[x].ctl.v &= ~(1<<31);
1090 igfx->dp[x].bufctl.v &= ~(1<<31);
1092 for(x=0; x<nelem(igfx->hdmi); x++)
1093 igfx->hdmi[x].ctl.v &= ~(1<<31);
1094 for(x=0; x<igfx->npipe; x++){
1095 /* disable displayport transcoders */
1096 igfx->pipe[x].dpctl.v &= ~(1<<31);
1097 igfx->pipe[x].fdi->dpctl.v &= ~(1<<31);
1098 if(igfx->type == TypeHSW){
1099 igfx->pipe[x].dpctl.v &= ~(7<<28);
1100 igfx->pipe[x].fdi->dpctl.v &= ~(7<<28);
1102 igfx->pipe[x].dpctl.v |= (3<<29);
1103 igfx->pipe[x].fdi->dpctl.v |= (3<<29);
1105 /* disable transcoder/pipe */
1106 igfx->pipe[x].conf.v &= ~(1<<31);
1107 igfx->pipe[x].fdi->conf.v &= ~(1<<31);
1110 if((val = dbattr(m->attr, "display")) != nil){
1112 if(igfx->type == TypeHSW && !igfx->dp[port-PortDPA].hdmi)
1114 }else if(dbattr(m->attr, "lcd") != nil)
1119 trace("%s: display #%d\n", ctlr->name, port+1);
1124 error("%s: display #%d not supported\n", ctlr->name, port+1);
1128 if(igfx->type == TypeHSW) /* unimplemented */
1130 if(igfx->type == TypeG45)
1131 x = (igfx->adpa.v >> 30) & 1;
1133 x = (igfx->adpa.v >> 29) & 3;
1134 igfx->adpa.v |= (1<<31);
1135 if(igfx->type == TypeG45){
1136 igfx->adpa.v &= ~(3<<10); /* Monitor DPMS: on */
1138 igfx->adpa.v &= ~(1<<15); /* ADPA Polarity Select */
1139 igfx->adpa.v |= 3<<3;
1141 igfx->adpa.v ^= 1<<3;
1143 igfx->adpa.v ^= 1<<4;
1148 if(igfx->type == TypeHSW)
1150 if(igfx->type == TypeG45)
1151 x = (igfx->lvds.v >> 30) & 1;
1153 x = (igfx->lvds.v >> 29) & 3;
1154 igfx->lvds.v |= (1<<31);
1155 igfx->ppcontrol.v |= 5;
1157 if(igfx->type == TypeG45){
1158 igfx->lvds.v &= ~(1<<24); /* data format select 18/24bpc */
1160 igfx->lvds.v &= ~(3<<20);
1162 igfx->lvds.v ^= 1<<20;
1164 igfx->lvds.v ^= 1<<21;
1166 igfx->lvds.v |= (1<<15); /* border enable */
1175 r = &igfx->dp[port - PortDPA].ctl;
1180 /* use PIPE_A for displayport */
1183 if(igfx->type == TypeHSW){
1184 if(port == PortDPA){
1185 /* only enable panel for eDP */
1186 igfx->ppcontrol.v |= 5;
1192 r->v &= ~(7<<28) & ~(1<<26) & ~(63<<19) & ~(3<<16) & ~(15<<11) & ~(1<<7) & ~31;
1193 /* displayport SST mode */
1195 /* link not in training, send normal pixels */
1197 if(igfx->dp[port-PortDPA].hdmi){
1198 /* hdmi: do not configure displayport */
1203 r = &igfx->dp[port - PortDPA].bufctl;
1207 r->v &= ~(7<<28) & ~(127<<17) & ~(255<<8) & ~(3<<5);
1208 /* grab lanes shared with port e when using port a */
1211 else if(port == PortDPE)
1212 igfx->dp[0].bufctl.v &= ~(1<<4);
1215 if(!igfx->dp[port-PortDPA].hdmi){
1216 nl = needlanes(m->frequency, 270*MHz, 3*bpc);
1217 /* x4 unsupported on port e */
1218 if(nl > 2 && port == PortDPE)
1222 /* port reversal: off */
1225 /* buffer translation (vsl/pel) */
1226 r = igfx->dp[port - PortDPA].buftrans;
1227 r[1].v = 0x0006000E; r[0].v = 0x00FFFFFF;
1228 r[3].v = 0x0005000A; r[2].v = 0x00D75FFF;
1229 r[5].v = 0x00040006; r[4].v = 0x00C30FFF;
1230 r[7].v = 0x000B0000; r[6].v = 0x80AAAFFF;
1231 r[9].v = 0x0005000A; r[8].v = 0x00FFFFFF;
1232 r[11].v = 0x000C0004; r[10].v = 0x00D75FFF;
1233 r[13].v = 0x000B0000; r[12].v = 0x80C30FFF;
1234 r[15].v = 0x00040006; r[14].v = 0x00FFFFFF;
1235 r[17].v = 0x000B0000; r[16].v = 0x80D75FFF;
1236 r[19].v = 0x00040006; r[18].v = 0x00FFFFFF;
1243 /* port width selection */
1245 r->v |= needlanes(m->frequency, 270*MHz, 3*bpc)-1 << 19;
1247 /* port reversal: off */
1251 /* displayport transcoder */
1252 if(port == PortDPA){
1255 /* pll frequency: 270mhz */
1262 } else if(igfx->pipe[x].fdi->dpctl.a != 0){
1265 /* audio output: disable */
1267 /* transcoder displayport configuration */
1268 r = &igfx->pipe[x].fdi->dpctl;
1269 /* transcoder enable */
1271 /* port select: B,C,D */
1273 r->v |= (port-PortDPB)<<29;
1285 /* plane enable, 32bpp */
1286 p->dsp->cntr.v = (1<<31) | (6<<26);
1287 if(igfx->type == TypeG45)
1288 p->dsp->cntr.v |= x<<24; /* pipe assign */
1290 p->dsp->cntr.v &= ~511; /* mbz */
1292 /* stride must be 64 byte aligned */
1293 p->dsp->stride.v = m->x * (m->z / 8);
1294 p->dsp->stride.v += 63;
1295 p->dsp->stride.v &= ~63;
1297 /* virtual width in pixels */
1298 vga->virtx = p->dsp->stride.v / (m->z / 8);
1300 /* plane position and size */
1302 p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1); /* sic */
1305 p->dsp->linoff.v = 0;
1306 p->dsp->tileoff.v = 0;
1307 p->dsp->leftsurf.v = 0;
1309 /* cursor plane off */
1311 if(igfx->type == TypeG45)
1312 p->cur->cntr.v |= x<<28; /* pipe assign */
1316 if(initdpll(igfx, x, m->frequency, port) < 0)
1317 error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
1319 initpipe(igfx, p, m, bpc, port);
1321 ctlr->flag |= Finit;
1325 loadtrans(Igfx *igfx, Trans *t)
1332 /* program trans/pipe timings */
1333 loadreg(igfx, t->ht);
1334 loadreg(igfx, t->hb);
1335 loadreg(igfx, t->hs);
1336 loadreg(igfx, t->vt);
1337 loadreg(igfx, t->vb);
1338 loadreg(igfx, t->vs);
1339 loadreg(igfx, t->vss);
1341 loadreg(igfx, t->dm[0]);
1342 loadreg(igfx, t->dn[0]);
1343 loadreg(igfx, t->lm[0]);
1344 loadreg(igfx, t->ln[0]);
1345 loadreg(igfx, t->dm[1]);
1346 loadreg(igfx, t->dn[1]);
1347 loadreg(igfx, t->lm[1]);
1348 loadreg(igfx, t->ln[1]);
1350 if(t->dpll != nil && igfx->type != TypeHSW){
1352 t->dpll->ctrl.v &= ~(1<<31);
1353 loadreg(igfx, t->dpll->ctrl);
1354 loadreg(igfx, t->dpll->fp0);
1355 loadreg(igfx, t->dpll->fp1);
1358 t->dpll->ctrl.v |= (1<<31);
1359 loadreg(igfx, t->dpll->ctrl);
1363 /* workarround: set timing override bit */
1364 csr(igfx, t->chicken.a, 0, 1<<31);
1366 /* enable displayport transcoder */
1367 loadreg(igfx, t->dpctl);
1369 /* enable trans/pipe */
1370 t->conf.v |= (1<<31);
1371 t->conf.v &= ~(1<<30);
1372 loadreg(igfx, t->conf);
1373 for(i=0; i<100; i++){
1375 if(rr(igfx, t->conf.a) & (1<<30))
1381 enablepipe(Igfx *igfx, int x)
1387 if((p->conf.v & (1<<31)) == 0)
1388 return; /* pipe is disabled, done */
1390 /* select pipe clock */
1391 loadreg(igfx, p->clksel);
1393 if(p->fdi->rxctl.a != 0){
1394 p->fdi->rxctl.v &= ~(1<<31);
1395 p->fdi->rxctl.v &= ~(1<<4); /* rawclk */
1396 p->fdi->rxctl.v |= (1<<13); /* enable pll */
1397 loadreg(igfx, p->fdi->rxctl);
1399 p->fdi->rxctl.v |= (1<<4); /* pcdclk */
1400 loadreg(igfx, p->fdi->rxctl);
1402 /* clear auto training bits */
1403 if(igfx->type == TypeSNB)
1404 p->fdi->txctl.v &= ~(3<<28 | 1<<10 | 1);
1406 p->fdi->txctl.v &= ~(7<<8 | 1);
1407 p->fdi->txctl.v &= ~(1<<31); /* disable */
1408 p->fdi->txctl.v |= (1<<14); /* enable pll */
1409 loadreg(igfx, p->fdi->txctl);
1413 /* image size (vga needs to be off) */
1414 loadreg(igfx, p->src);
1416 /* set panel fitter as needed */
1418 loadreg(igfx, p->pfit->ctrl);
1419 loadreg(igfx, p->pfit->winpos);
1420 loadreg(igfx, p->pfit->winsize); /* arm */
1423 /* keep planes disabled while pipe comes up */
1424 if(igfx->type == TypeG45)
1427 /* enable cpu pipe */
1431 loadreg(igfx, p->dsp->cntr);
1432 loadreg(igfx, p->dsp->linoff);
1433 loadreg(igfx, p->dsp->stride);
1434 loadreg(igfx, p->dsp->tileoff);
1435 loadreg(igfx, p->dsp->size);
1436 loadreg(igfx, p->dsp->pos);
1437 loadreg(igfx, p->dsp->surf); /* arm */
1438 loadreg(igfx, p->dsp->leftsurf);
1440 /* program cursor */
1441 loadreg(igfx, p->cur->cntr);
1442 loadreg(igfx, p->cur->pos);
1443 loadreg(igfx, p->cur->base); /* arm */
1446 if(igfx->type == TypeG45) {
1447 p->conf.v &= ~(3<<18);
1448 loadreg(igfx, p->conf);
1451 if(p->fdi->rxctl.a != 0){
1453 loadreg(igfx, p->fdi->rxtu[1]);
1454 loadreg(igfx, p->fdi->rxtu[0]);
1455 loadreg(igfx, p->fdi->rxmisc);
1457 if(igfx->type == TypeSNB){
1458 /* unmask bit lock and symbol lock bits */
1459 csr(igfx, p->fdi->rximr.a, 3<<8, 0);
1461 p->fdi->txctl.v &= ~(3<<28); /* link train pattern1 */
1462 p->fdi->txctl.v |= 1<<31; /* enable */
1463 loadreg(igfx, p->fdi->txctl);
1465 p->fdi->rxctl.v &= ~(3<<8); /* link train pattern1 */
1466 p->fdi->rxctl.v |= 1<<31; /* enable */
1467 loadreg(igfx, p->fdi->rxctl);
1469 /* wait for bit lock */
1470 for(i=0; i<10; i++){
1472 if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
1475 csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
1477 /* switch to link train pattern2 */
1478 csr(igfx, p->fdi->txctl.a, 3<<28, 1<<28);
1479 csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
1481 /* wait for symbol lock */
1482 for(i=0; i<10; i++){
1484 if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
1487 csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
1489 /* switch to link train normal */
1490 csr(igfx, p->fdi->txctl.a, 0, 3<<28);
1491 csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
1493 /* wait idle pattern time */
1496 p->fdi->rxctl.v &= ~(3<<8); /* link train pattern 00 */
1497 p->fdi->rxctl.v |= 1<<10; /* auto train enable */
1498 p->fdi->rxctl.v |= 1<<31; /* enable */
1499 loadreg(igfx, p->fdi->rxctl);
1501 p->fdi->txctl.v &= ~(3<<8); /* link train pattern 00 */
1502 p->fdi->txctl.v |= 1<<10; /* auto train enable */
1503 p->fdi->txctl.v |= 1<<31; /* enable */
1504 loadreg(igfx, p->fdi->txctl);
1506 /* wait for link training done */
1507 for(i=0; i<200; i++){
1509 if(rr(igfx, p->fdi->txctl.a) & 2)
1515 /* enable the transcoder */
1516 loadtrans(igfx, p->fdi);
1520 disabletrans(Igfx *igfx, Trans *t)
1524 /* deselect pipe clock */
1525 csr(igfx, t->clksel.a, 7<<29, 0);
1527 /* disable displayport transcoder */
1528 if(igfx->type == TypeHSW){
1529 csr(igfx, t->dpctl.a, 15<<28, 0);
1530 csr(igfx, t->ht.a, ~0, 0);
1531 csr(igfx, t->hb.a, ~0, 0);
1532 csr(igfx, t->hs.a, ~0, 0);
1533 csr(igfx, t->vt.a, ~0, 0);
1534 csr(igfx, t->vb.a, ~0, 0);
1535 csr(igfx, t->vs.a, ~0, 0);
1536 csr(igfx, t->vss.a, ~0, 0);
1538 csr(igfx, t->dpctl.a, 1<<31, 3<<29);
1540 /* disable transcoder / pipe */
1541 csr(igfx, t->conf.a, 1<<31, 0);
1542 for(i=0; i<100; i++){
1544 if((rr(igfx, t->conf.a) & (1<<30)) == 0)
1547 /* workarround: clear timing override bit */
1548 csr(igfx, t->chicken.a, 1<<31, 0);
1551 if(igfx->type != TypeHSW && t->dpll != nil)
1552 csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
1556 disablepipe(Igfx *igfx, int x)
1563 csr(igfx, p->dsp->cntr.a, 1<<31, 0);
1564 wr(igfx, p->dsp->surf.a, 0); /* arm */
1566 if(igfx->type == TypeHSW)
1567 csr(igfx, p->cur->cntr.a, 0x3F, 0);
1569 csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
1570 wr(igfx, p->cur->base.a, 0); /* arm */
1572 /* display/overlay/cursor planes off */
1573 if(igfx->type == TypeG45)
1574 csr(igfx, p->conf.a, 0, 3<<18);
1575 csr(igfx, p->src.a, ~0, 0);
1577 /* disable cpu pipe */
1578 disabletrans(igfx, p);
1580 /* disable panel fitter */
1582 csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
1584 /* disable fdi transmitter and receiver */
1585 csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
1586 csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
1588 /* disable pch transcoder */
1589 disabletrans(igfx, p->fdi);
1591 /* disable pch dpll enable bit */
1592 if(igfx->type != TypeHSW)
1593 csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
1597 load(Vga* vga, Ctlr* ctlr)
1602 igfx = vga->private;
1605 if(igfx->ppcontrol.a != 0){
1606 csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
1607 for(x=0; x<5000; x++){
1609 if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
1615 csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
1616 csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
1617 csr(igfx, igfx->adpa.a, 1<<31, 0);
1618 csr(igfx, igfx->lvds.a, 1<<31, 0);
1619 for(x = 0; x < nelem(igfx->dp); x++){
1620 csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
1621 if(igfx->dp[x].bufctl.a != 0){
1622 csr(igfx, igfx->dp[x].bufctl.a, 1<<31, 0);
1623 /* wait for buffers to return to idle */
1626 if(rr(igfx, igfx->dp[x].bufctl.a) & 1<<7)
1631 for(x = 0; x < nelem(igfx->hdmi); x++)
1632 csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
1634 /* disable vga plane */
1635 csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
1637 /* turn off all pipes */
1638 for(x = 0; x < igfx->npipe; x++)
1639 disablepipe(igfx, x);
1641 if(igfx->type == TypeG45){
1642 /* toggle dsp a on and off (from enable sequence) */
1643 csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);
1644 csr(igfx, igfx->pipe[0].dsp->cntr.a, 0, 1<<31);
1645 wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1646 csr(igfx, igfx->pipe[0].dsp->cntr.a, 1<<31, 0);
1647 wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1648 csr(igfx, igfx->pipe[0].conf.a, 0, 3<<18);
1651 if(igfx->type == TypeHSW){
1652 /* deselect port clock */
1653 for(x=0; x<nelem(igfx->dpllsel); x++)
1654 csr(igfx, igfx->dpllsel[x].a, 0, 7<<29);
1656 /* disable dpll's other than LCPLL */
1657 for(x=1; x<nelem(igfx->dpll); x++)
1658 csr(igfx, igfx->dpll[x].ctrl.a, 1<<31, 0);
1661 /* program new clock sources */
1662 loadreg(igfx, igfx->rawclkfreq);
1663 loadreg(igfx, igfx->drefctl);
1664 /* program cpu pll */
1665 if(igfx->type == TypeHSW)
1666 for(x=0; x<nelem(igfx->dpll); x++)
1667 loadreg(igfx, igfx->dpll[x].ctrl);
1670 /* set lvds before enabling dpll */
1671 loadreg(igfx, igfx->lvds);
1673 /* new dpll setting */
1674 for(x=0; x<nelem(igfx->dpllsel); x++)
1675 loadreg(igfx, igfx->dpllsel[x]);
1677 /* program all pipes */
1678 for(x = 0; x < igfx->npipe; x++)
1679 enablepipe(igfx, x);
1681 /* program vga plane */
1682 loadreg(igfx, igfx->vgacntrl);
1685 loadreg(igfx, igfx->adpa);
1686 loadreg(igfx, igfx->sdvob);
1687 loadreg(igfx, igfx->sdvoc);
1688 for(x = 0; x < nelem(igfx->dp); x++){
1689 for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
1690 loadreg(igfx, igfx->dp[x].buftrans[y]);
1691 loadreg(igfx, igfx->dp[x].bufctl);
1692 if(enabledp(igfx, &igfx->dp[x]) < 0)
1693 ctlr->flag |= Ferror;
1696 /* program lcd power */
1697 loadreg(igfx, igfx->ppcontrol);
1699 ctlr->flag |= Fload;
1703 dumpreg(char *name, char *item, Reg r)
1708 printitem(name, item);
1709 Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
1713 dumphex(char *name, char *item, uchar *data, int len)
1717 for(i=0; i<len; i++){
1720 Bprint(&stdout, "\n");
1721 printitem(name, item);
1722 Bprint(&stdout, " [%.2x] =", i);
1724 Bprint(&stdout, " %.2X", data[i]);
1726 Bprint(&stdout, "\n");
1730 dumptiming(char *name, Trans *t)
1734 if(t->dm[0].a != 0 && t->dm[0].v != 0){
1735 tu = 1+((t->dm[0].v >> 25) & 0x3f);
1736 printitem(name, "dm1 tu");
1737 Bprint(&stdout, " %d\n", tu);
1739 m = t->dm[0].v & 0xffffff;
1742 printitem(name, "dm1/dn1");
1743 Bprint(&stdout, " %f\n", (double)m / (double)n);
1749 printitem(name, "lm1/ln1");
1750 Bprint(&stdout, " %f\n", (double)m / (double)n);
1756 dumptrans(char *name, Trans *t)
1758 dumpreg(name, "conf", t->conf);
1760 dumpreg(name, "dm1", t->dm[0]);
1761 dumpreg(name, "dn1", t->dn[0]);
1762 dumpreg(name, "lm1", t->lm[0]);
1763 dumpreg(name, "ln1", t->ln[0]);
1764 dumpreg(name, "dm2", t->dm[1]);
1765 dumpreg(name, "dn2", t->dn[1]);
1766 dumpreg(name, "lm2", t->lm[1]);
1767 dumpreg(name, "ln2", t->ln[1]);
1769 dumptiming(name, t);
1771 dumpreg(name, "ht", t->ht);
1772 dumpreg(name, "hb", t->hb);
1773 dumpreg(name, "hs", t->hs);
1775 dumpreg(name, "vt", t->vt);
1776 dumpreg(name, "vb", t->vb);
1777 dumpreg(name, "vs", t->vs);
1778 dumpreg(name, "vss", t->vss);
1780 dumpreg(name, "dpctl", t->dpctl);
1781 dumpreg(name, "clksel", t->clksel);
1785 dumppipe(Igfx *igfx, int x)
1792 snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
1793 dumpreg(name, "src", p->src);
1796 snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
1797 dumptrans(name, p->fdi);
1798 dumpreg(name, "txctl", p->fdi->txctl);
1799 dumpreg(name, "rxctl", p->fdi->rxctl);
1800 dumpreg(name, "rxmisc", p->fdi->rxmisc);
1801 dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
1802 dumpreg(name, "rxtu2", p->fdi->rxtu[1]);
1804 snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
1805 dumpreg(name, "cntr", p->dsp->cntr);
1806 dumpreg(name, "linoff", p->dsp->linoff);
1807 dumpreg(name, "stride", p->dsp->stride);
1808 dumpreg(name, "surf", p->dsp->surf);
1809 dumpreg(name, "tileoff", p->dsp->tileoff);
1810 dumpreg(name, "leftsurf", p->dsp->leftsurf);
1811 dumpreg(name, "pos", p->dsp->pos);
1812 dumpreg(name, "size", p->dsp->size);
1814 snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
1815 dumpreg(name, "cntr", p->cur->cntr);
1816 dumpreg(name, "base", p->cur->base);
1817 dumpreg(name, "pos", p->cur->pos);
1821 dumpdpll(Igfx *igfx, int x)
1823 int cref, m1, m2, n, p1, p2;
1829 dpll = &igfx->dpll[x];
1830 snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
1832 dumpreg(name, "ctrl", dpll->ctrl);
1833 dumpreg(name, "fp0", dpll->fp0);
1834 dumpreg(name, "fp1", dpll->fp1);
1836 if(igfx->type == TypeHSW)
1839 p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
1840 if(((dpll->ctrl.v >> 24) & 3) == 1)
1842 m = (dpll->ctrl.v >> 16) & 0xFF;
1843 for(p1 = 1; p1 <= 8; p1++)
1846 printitem(name, "ctrl p1");
1847 Bprint(&stdout, " %d\n", p1);
1848 printitem(name, "ctrl p2");
1849 Bprint(&stdout, " %d\n", p2);
1851 n = (dpll->fp0.v >> 16) & 0x3f;
1852 m1 = (dpll->fp0.v >> 8) & 0x3f;
1853 m2 = (dpll->fp0.v >> 0) & 0x3f;
1855 cref = getcref(igfx, x);
1856 freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
1858 printitem(name, "fp0 m1");
1859 Bprint(&stdout, " %d\n", m1);
1860 printitem(name, "fp0 m2");
1861 Bprint(&stdout, " %d\n", m2);
1862 printitem(name, "fp0 n");
1863 Bprint(&stdout, " %d\n", n);
1865 printitem(name, "cref");
1866 Bprint(&stdout, " %d\n", cref);
1867 printitem(name, "fp0 freq");
1868 Bprint(&stdout, " %lld\n", freq);
1872 dump(Vga* vga, Ctlr* ctlr)
1878 if((igfx = vga->private) == nil)
1881 for(x=0; x<igfx->npipe; x++)
1884 for(x=0; x<nelem(igfx->dpll); x++)
1887 for(x=0; x<nelem(igfx->dpllsel); x++){
1888 snprint(name, sizeof(name), "%s dpllsel %c", ctlr->name, 'a'+x);
1889 dumpreg(name, "dpllsel", igfx->dpllsel[x]);
1892 dumpreg(ctlr->name, "drefctl", igfx->drefctl);
1893 dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
1894 dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
1896 for(x=0; x<nelem(igfx->dp); x++){
1897 if(igfx->dp[x].ctl.a == 0)
1899 snprint(name, sizeof(name), "%s dp %c", ctlr->name, 'a'+x);
1900 dumpreg(name, "ctl", igfx->dp[x].ctl);
1901 dumpreg(name, "bufctl", igfx->dp[x].bufctl);
1902 dumpreg(name, "stat", igfx->dp[x].stat);
1903 dumphex(name, "dpcd", igfx->dp[x].dpcd, sizeof(igfx->dp[x].dpcd));
1904 for(y=0; y<nelem(igfx->dp[x].buftrans); y++){
1905 snprint(name, sizeof(name), "%s buftrans %c %d", ctlr->name, 'a'+x, y);
1906 dumpreg(name, "ctl", igfx->dp[x].buftrans[y]);
1909 for(x=0; x<nelem(igfx->hdmi); x++){
1910 snprint(name, sizeof(name), "%s hdmi %c", ctlr->name, 'a'+x);
1911 dumpreg(name, "ctl", igfx->hdmi[x].ctl);
1914 for(x=0; x<nelem(igfx->pfit); x++){
1915 snprint(name, sizeof(name), "%s pfit %c", ctlr->name, 'a'+x);
1916 dumpreg(name, "ctrl", igfx->pfit[x].ctrl);
1917 dumpreg(name, "winpos", igfx->pfit[x].winpos);
1918 dumpreg(name, "winsize", igfx->pfit[x].winsize);
1919 dumpreg(name, "pwrgate", igfx->pfit[x].pwrgate);
1922 dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
1923 dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);
1925 dumpreg(ctlr->name, "adpa", igfx->adpa);
1926 dumpreg(ctlr->name, "lvds", igfx->lvds);
1927 dumpreg(ctlr->name, "sdvob", igfx->sdvob);
1928 dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
1930 dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
1934 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
1939 if(dp->auxctl.a == 0){
1940 werrstr("not present");
1945 while(rr(igfx, dp->auxctl.a) & (1<<31)){
1953 /* clear sticky bits */
1954 wr(igfx, dp->auxctl.a, (1<<28) | (1<<25) | (1<<30));
1956 for(i=0; i<nelem(dp->auxdat); i++){
1958 w |= buf[i*4+1]<<16;
1961 wr(igfx, dp->auxdat[i].a, w);
1964 /* 2X Bit Clock divider */
1965 w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3ff)) >> 1;
1966 if(w < 1 || w > 0x3fd){
1967 werrstr("bad clock");
1971 /* hack: slow down a bit */
1974 w |= 1<<31; /* SendBusy */
1975 w |= 1<<29; /* interrupt disabled */
1976 w |= 3<<26; /* timeout 1600µs */
1977 w |= len<<20; /* send bytes */
1978 w |= 5<<16; /* precharge time (5*2 = 10µs) */
1979 wr(igfx, dp->auxctl.a, w);
1983 w = rr(igfx, dp->auxctl.a);
1984 if((w & (1<<30)) != 0)
1993 werrstr("receive timeout");
1997 werrstr("receive error");
2001 len = (w >> 20) & 0x1f;
2002 for(i=0; i<nelem(dp->auxdat); i++){
2003 w = rr(igfx, dp->auxdat[i].a);
2021 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
2028 memset(buf, 0, sizeof(buf));
2029 buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
2034 if(data != nil && len > 0){
2035 if((cmd & CmdRead) == 0)
2036 memmove(buf+4, data, len);
2038 if((cmd & CmdRead) == 0)
2041 if((r = dpauxio(igfx, dp, buf, r)) < 0){
2042 trace("%s: dpauxio: dp %c, cmd %x, addr %x, len %d: %r\n",
2043 igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]), cmd, addr, len);
2046 if(r == 0 || data == nil || len == 0)
2048 if((cmd & CmdRead) != 0){
2051 memmove(data, buf+1, len);
2057 rdpaux(Igfx *igfx, Dp *dp, int addr)
2060 if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
2065 wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
2067 if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
2073 enabledp(Igfx *igfx, Dp *dp)
2080 if((dp->ctl.v & (1<<31)) == 0)
2083 /* FIXME: always times out */
2084 if(igfx->type == TypeHSW && dp == &igfx->dp[0])
2087 /* Link configuration */
2088 wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000);
2089 w = dp->ctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
2090 wdpaux(igfx, dp, 0x101, w+1);
2094 /* Link training pattern 1 */
2095 dp->ctl.v &= ~(7<<8);
2096 loadreg(igfx, dp->ctl);
2097 for(try = 0;;try++){
2100 /* Link training pattern 1 */
2101 wdpaux(igfx, dp, 0x102, 0x01);
2103 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2105 if(r & 1) /* LANE0_CR_DONE */
2108 trace("pattern1 finished: %x\n", r);
2110 /* Link training pattern 2 */
2111 dp->ctl.v &= ~(7<<8);
2113 loadreg(igfx, dp->ctl);
2114 for(try = 0;;try++){
2117 /* Link training pattern 2 */
2118 wdpaux(igfx, dp, 0x102, 0x02);
2120 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2125 trace("pattern2 finished: %x\n", r);
2127 if(igfx->type == TypeHSW){
2128 /* set link training to idle pattern and wait for 5 idle
2130 dp->ctl.v &= ~(7<<8);
2132 loadreg(igfx, dp->ctl);
2133 for(try=0; try<10; try++){
2135 if(rr(igfx, dp->stat.a) & (1<<25))
2141 dp->ctl.v &= ~(7<<8);
2143 loadreg(igfx, dp->ctl);
2144 wdpaux(igfx, dp, 0x102, 0x00);
2148 trace("training failed: %x\n", r);
2151 dp->ctl.v &= ~(1<<31);
2152 loadreg(igfx, dp->ctl);
2153 wdpaux(igfx, dp, 0x102, 0x00);
2158 edidshift(uchar buf[256])
2163 /* shift if neccesary so edid block is at the start */
2164 for(i=0; i<256-8; i++){
2165 if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
2166 && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
2167 memmove(tmp, buf, i);
2168 memmove(buf, buf + i, 256 - i);
2169 memmove(buf + (256 - i), tmp, i);
2177 snarfdpedid(Igfx *igfx, Dp *dp, int addr)
2183 for(i=0; i<sizeof(dp->dpcd); i+=16)
2184 if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
2187 if(dp->dpcd[0] == 0) /* nothing there, dont try to get edid */
2190 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
2193 for(i=0; i<sizeof(buf); i+=16){
2194 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2196 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2198 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2200 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2202 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2207 dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
2209 if((e = parseedid128(edidshift(buf))) == nil)
2210 trace("%s: snarfdpedid: dp %c: %r\n", igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]));
2215 GMBUSCP = 0, /* Clock/Port selection */
2216 GMBUSCS = 1, /* Command/Status */
2217 GMBUSST = 2, /* Status Register */
2218 GMBUSDB = 3, /* Data Buffer Register */
2219 GMBUSIM = 4, /* Interrupt Mask */
2220 GMBUSIX = 5, /* Index Register */
2224 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
2229 if(igfx->gmbus[GMBUSCP].a == 0)
2232 wr(igfx, igfx->gmbus[GMBUSCP].a, port);
2233 wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
2235 /* bus cycle without index and stop, byte count, slave address, read */
2236 wr(igfx, igfx->gmbus[GMBUSCS].a, 1<<30 | 5<<25 | len<<16 | addr<<1 | 1);
2241 for(t=0; t<100; t++){
2242 x = rr(igfx, igfx->gmbus[GMBUSST].a);
2247 if((x & (1<<11)) == 0)
2255 y = rr(igfx, igfx->gmbus[GMBUSDB].a);
2258 data[n++] = y & 0xff, y >>= 8;
2260 data[n++] = y & 0xff, y >>= 8;
2262 data[n++] = y & 0xff, y >>= 8;
2264 data[n++] = y & 0xff;
2272 snarfgmedid(Igfx *igfx, int port, int addr)
2277 if(gmbusread(igfx, port, addr, buf, 128) != 128)
2279 if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
2282 return parseedid128(edidshift(buf));
2288 options, /* options */