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 0x0046: /* Thinkpad T510 */
375 case 0x0102: /* Dell Optiplex 790 */
376 case 0x0126: /* Thinkpad X220 */
378 case 0x27a2: /* GM945/82940GML - ThinkPad X60 Tablet */
379 case 0x29a2: /* 82P965/G965 HECI desktop */
380 case 0x2a02: /* GM965/GL960/X3100 - ThinkPad X61 Tablet */
381 case 0x2a42: /* 4 Series Mobile - ThinkPad X200 */
387 static Edid* snarfgmedid(Igfx*, int port, int addr);
388 static Edid* snarfdpedid(Igfx*, Dp *dp, int addr);
390 static int enabledp(Igfx*, Dp*);
393 snarf(Vga* vga, Ctlr* ctlr)
400 igfx = alloc(sizeof(Igfx));
402 igfx->pci = vga->pci;
403 if(igfx->pci == nil){
404 error("%s: no pci device\n", ctlr->name);
407 igfx->type = devtype(igfx);
409 error("%s: unrecognized device\n", ctlr->name);
412 vgactlpci(igfx->pci);
414 vgactlw("type", ctlr->name);
415 igfx->mmio = segattach(0, "igfxmmio", 0, igfx->pci->mem[0].size);
416 if(igfx->mmio == (u32int*)-1)
417 error("%s: attaching mmio: %r\n", ctlr->name);
419 if((igfx->pci->mem[4].bar & 1) == 0)
420 error("%s: no pio bar\n", ctlr->name);
421 igfx->pio = igfx->pci->mem[4].bar & ~1;
428 igfx->npipe = 2; /* A,B */
429 igfx->cdclk = 200; /* MHz */
431 igfx->dpll[0].ctrl = snarfreg(igfx, 0x06014);
432 igfx->dpll[0].fp0 = snarfreg(igfx, 0x06040);
433 igfx->dpll[0].fp1 = snarfreg(igfx, 0x06044);
434 igfx->dpll[1].ctrl = snarfreg(igfx, 0x06018);
435 igfx->dpll[1].fp0 = snarfreg(igfx, 0x06048);
436 igfx->dpll[1].fp1 = snarfreg(igfx, 0x0604c);
438 igfx->adpa = snarfreg(igfx, 0x061100);
439 igfx->lvds = snarfreg(igfx, 0x061180);
440 igfx->sdvob = snarfreg(igfx, 0x061140);
441 igfx->sdvoc = snarfreg(igfx, 0x061160);
444 igfx->gmbus[x] = snarfreg(igfx, 0x5100 + x*4);
445 igfx->gmbus[x] = snarfreg(igfx, 0x5120);
447 igfx->pfit[0].ctrl = snarfreg(igfx, 0x061230);
448 y = (igfx->pfit[0].ctrl.v >> 29) & 3;
449 if(igfx->pipe[y].pfit == nil)
450 igfx->pipe[y].pfit = &igfx->pfit[0];
452 igfx->ppstatus = snarfreg(igfx, 0x61200);
453 igfx->ppcontrol = snarfreg(igfx, 0x61204);
455 igfx->vgacntrl = snarfreg(igfx, 0x071400);
459 igfx->npipe = 2; /* A,B */
460 igfx->cdclk = 400; /* MHz */
464 igfx->npipe = 3; /* A,B,C */
465 igfx->cdclk = 400; /* MHz */
469 igfx->dpll[0].ctrl = snarfreg(igfx, 0xC6014);
470 igfx->dpll[0].fp0 = snarfreg(igfx, 0xC6040);
471 igfx->dpll[0].fp1 = snarfreg(igfx, 0xC6044);
472 igfx->dpll[1].ctrl = snarfreg(igfx, 0xC6018);
473 igfx->dpll[1].fp0 = snarfreg(igfx, 0xC6048);
474 igfx->dpll[1].fp1 = snarfreg(igfx, 0xC604c);
476 igfx->dpllsel[0] = snarfreg(igfx, 0xC7000);
478 igfx->drefctl = snarfreg(igfx, 0xC6200);
479 igfx->ssc4params = snarfreg(igfx, 0xC6210);
481 igfx->dp[0].ctl = snarfreg(igfx, 0x64000);
483 igfx->dp[x].ctl = snarfreg(igfx, 0xE4000 + 0x100*x);
485 igfx->hdmi[1].ctl = snarfreg(igfx, 0x0E1140); /* HDMI_CTL_B */
486 igfx->hdmi[1].bufctl[0] = snarfreg(igfx, 0x0FC810); /* HTMI_BUF_CTL_0 */
487 igfx->hdmi[1].bufctl[1] = snarfreg(igfx, 0x0FC81C); /* HTMI_BUF_CTL_1 */
488 igfx->hdmi[1].bufctl[2] = snarfreg(igfx, 0x0FC828); /* HTMI_BUF_CTL_2 */
489 igfx->hdmi[1].bufctl[3] = snarfreg(igfx, 0x0FC834); /* HTMI_BUF_CTL_3 */
491 igfx->hdmi[2].ctl = snarfreg(igfx, 0x0E1150); /* HDMI_CTL_C */
492 igfx->hdmi[2].bufctl[0] = snarfreg(igfx, 0x0FCC00); /* HTMI_BUF_CTL_4 */
493 igfx->hdmi[2].bufctl[1] = snarfreg(igfx, 0x0FCC0C); /* HTMI_BUF_CTL_5 */
494 igfx->hdmi[2].bufctl[2] = snarfreg(igfx, 0x0FCC18); /* HTMI_BUF_CTL_6 */
495 igfx->hdmi[2].bufctl[3] = snarfreg(igfx, 0x0FCC24); /* HTMI_BUF_CTL_7 */
497 igfx->hdmi[3].ctl = snarfreg(igfx, 0x0E1160); /* HDMI_CTL_D */
498 igfx->hdmi[3].bufctl[0] = snarfreg(igfx, 0x0FD000); /* HTMI_BUF_CTL_8 */
499 igfx->hdmi[3].bufctl[1] = snarfreg(igfx, 0x0FD00C); /* HTMI_BUF_CTL_9 */
500 igfx->hdmi[3].bufctl[2] = snarfreg(igfx, 0x0FD018); /* HTMI_BUF_CTL_10 */
501 igfx->hdmi[3].bufctl[3] = snarfreg(igfx, 0x0FD024); /* HTMI_BUF_CTL_11 */
503 igfx->lvds = snarfreg(igfx, 0x0E1180); /* LVDS_CTL */
507 igfx->npipe = 4; /* A,B,C,eDP */
508 igfx->cdclk = igfx->isult ? 450 : 540; /* MHz */
510 igfx->dpll[0].ctrl = snarfreg(igfx, 0x130040); /* LCPLL_CTL */
511 igfx->dpll[1].ctrl = snarfreg(igfx, 0x46040); /* WRPLL_CTL1 */
512 igfx->dpll[2].ctrl = snarfreg(igfx, 0x46060); /* WRPLL_CTL2 */
513 igfx->dpll[3].ctrl = snarfreg(igfx, 0x46020); /* SPLL_CTL */
515 for(x=0; x<nelem(igfx->dp); x++){
516 if(x == 3 && igfx->isult) /* no DDI D */
518 igfx->dp[x].bufctl = snarfreg(igfx, 0x64000 + 0x100*x);
519 igfx->dp[x].ctl = snarfreg(igfx, 0x64040 + 0x100*x);
521 igfx->dp[x].stat = snarfreg(igfx, 0x64044 + 0x100*x);
522 for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
523 igfx->dp[x].buftrans[y] = snarfreg(igfx, 0x64E00 + 0x60*x + 4*y);
524 igfx->dpllsel[x] = snarfreg(igfx, 0x46100 + 4*x);
530 igfx->rawclkfreq = snarfreg(igfx, 0xC6204);
532 /* cpu displayport A */
533 igfx->dp[0].auxctl = snarfreg(igfx, 0x64010);
534 igfx->dp[0].auxdat[0] = snarfreg(igfx, 0x64014);
535 igfx->dp[0].auxdat[1] = snarfreg(igfx, 0x64018);
536 igfx->dp[0].auxdat[2] = snarfreg(igfx, 0x6401C);
537 igfx->dp[0].auxdat[3] = snarfreg(igfx, 0x64020);
538 igfx->dp[0].auxdat[4] = snarfreg(igfx, 0x64024);
540 /* pch displayport B,C,D */
542 igfx->dp[x].auxctl = snarfreg(igfx, 0xE4010 + 0x100*x);
543 igfx->dp[x].auxdat[0] = snarfreg(igfx, 0xE4014 + 0x100*x);
544 igfx->dp[x].auxdat[1] = snarfreg(igfx, 0xE4018 + 0x100*x);
545 igfx->dp[x].auxdat[2] = snarfreg(igfx, 0xE401C + 0x100*x);
546 igfx->dp[x].auxdat[3] = snarfreg(igfx, 0xE4020 + 0x100*x);
547 igfx->dp[x].auxdat[4] = snarfreg(igfx, 0xE4024 + 0x100*x);
550 for(x=0; x<igfx->npipe; x++){
551 if(igfx->type == TypeHSW && x == 3){
552 igfx->pipe[x].pfit = &igfx->pfit[0];
555 igfx->pfit[x].pwrgate = snarfreg(igfx, 0x68060 + 0x800*x);
556 igfx->pfit[x].winpos = snarfreg(igfx, 0x68070 + 0x800*x);
557 igfx->pfit[x].winsize = snarfreg(igfx, 0x68074 + 0x800*x);
558 igfx->pfit[x].ctrl = snarfreg(igfx, 0x68080 + 0x800*x);
560 y = (igfx->pfit[x].ctrl.v >> 29) & 3;
561 if(igfx->pipe[y].pfit == nil)
562 igfx->pipe[y].pfit = &igfx->pfit[x];
565 igfx->ppstatus = snarfreg(igfx, 0xC7200);
566 igfx->ppcontrol = snarfreg(igfx, 0xC7204);
569 igfx->gmbus[x] = snarfreg(igfx, 0xC5100 + x*4);
570 igfx->gmbus[x] = snarfreg(igfx, 0xC5120);
572 igfx->adpa = snarfreg(igfx, 0x0E1100); /* DAC_CTL */
573 igfx->vgacntrl = snarfreg(igfx, 0x041000);
577 for(x=0; x<igfx->npipe; x++)
580 for(x=0; x<nelem(vga->edid); x++){
585 vga->edid[x] = snarfgmedid(igfx, 2, 0x50);
588 vga->edid[x] = snarfgmedid(igfx, 3, 0x50);
589 if(vga->edid[x] == nil)
591 for(l = vga->edid[x]->modelist; l != nil; l = l->next)
592 l->attr = mkattr(l->attr, "lcd", "1");
595 if(igfx->type == TypeHSW && igfx->isult)
600 vga->edid[x] = snarfdpedid(igfx, &igfx->dp[x-PortDPA], 0x50);
606 if(vga->edid[x] == nil){
609 vga->edid[x] = snarfgmedid(igfx, x + 1 & ~1 | x >> 1 & 1, 0x50);
610 if(vga->edid[x] == nil)
612 igfx->dp[x-PortDPA].hdmi = 1;
614 for(l = vga->edid[x]->modelist; l != nil; l = l->next)
615 l->attr = mkattr(l->attr, "display", "%d", x+1);
618 ctlr->flag |= Fsnarf;
622 options(Vga* vga, Ctlr* ctlr)
625 ctlr->flag |= Hlinear|Ulinear|Foptions;
630 Lcpll2k = Lcpll * 2000,
637 25175000,0, 25200000,0, 27000000,0, 27027000,0,
638 37762500,0, 37800000,0, 40500000,0, 40541000,0,
639 54000000,0, 54054000,0, 59341000,0, 59400000,0,
640 72000000,0, 74176000,0, 74250000,0, 81000000,0,
641 81081000,0, 89012000,0, 89100000,0, 108000000,0,
642 108108000,0, 111264000,0, 111375000,0, 148352000,0,
643 148500000,0, 162000000,0, 162162000,0, 222525000,0,
644 222750000,0, 296703000,0, 297000000,0, 233500000,1500,
645 245250000,1500, 247750000,1500, 253250000,1500, 298000000,1500,
646 169128000,2000, 169500000,2000, 179500000,2000, 202000000,2000,
647 256250000,4000, 262500000,4000, 270000000,4000, 272500000,4000,
648 273750000,4000, 280750000,4000, 281250000,4000, 286000000,4000,
649 291750000,4000, 267250000,5000, 268500000,5000
653 for(i=b; i<b+nelem(b); i+=2)
660 genwrpll(int freq, int *n2, int *p, int *r2)
662 int budget, N2, P, R2;
663 vlong f2k, a, b, c, d, Δ, bestΔ;
666 if(f2k == Lcpll2k){ /* bypass wrpll entirely and use lcpll */
672 budget = wrbudget(freq);
674 for(R2=Lcpll*2/400+1; R2<=Lcpll*2/48; R2++)
675 for(N2=2400*R2/Lcpll+1; N2<=4800*R2/Lcpll; N2++)
676 for(P=2; P<=64; P+=2){
687 bestΔ = f2k * *p * *r2;
688 bestΔ -= *n2 * Lcpll2k;
697 if(a < c && b < d && *p * *r2 * Δ < P * R2 * bestΔ
699 || a >= c && b >= d && N2 * *r2 * *r2 > *n2 * R2 * R2){
708 genpll(int freq, int cref, int P2, int *m1, int *m2, int *n, int *p1)
710 int M1, M2, M, N, P, P1;
716 for(M2=5; M2<=9; M2++)
717 // for(M1=10; M1<=20; M1++){
718 for(M1=12; M1<=22; M1++){
719 M = 5*(M1+2) + (M2+2);
720 if(M < 79 || M > 127)
721 // if(M < 70 || M > 120)
723 for(P1=1; P1<=8; P1++){
726 // if(P < 4 || P > 98)
732 if(a < 20*MHz || a > 400*MHz)
738 if(best < 0 || error < best){
751 getcref(Igfx *igfx, int x)
755 dpll = &igfx->dpll[x];
756 if(igfx->type == TypeG45){
757 if(((dpll->ctrl.v >> 13) & 3) == 3)
765 initdpll(Igfx *igfx, int x, int freq, int port)
767 int cref, m1, m2, n, n2, p1, p2, r2;
772 /* PLL Reference Input Select */
773 dpll = igfx->pipe[x].dpll;
774 dpll->ctrl.v &= ~(3<<13);
775 dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
779 /* transcoder dpll enable */
780 igfx->dpllsel[0].v |= 8<<(x*4);
781 /* program rawclock to 125MHz */
782 igfx->rawclkfreq.v = 125;
784 igfx->drefctl.v &= ~(3<<13);
785 igfx->drefctl.v &= ~(3<<11);
786 igfx->drefctl.v &= ~(3<<9);
787 igfx->drefctl.v &= ~(3<<7);
788 igfx->drefctl.v &= ~3;
791 igfx->drefctl.v |= 2<<11;
792 igfx->drefctl.v |= 1;
794 igfx->drefctl.v |= 2<<9;
798 * PLL Reference Input Select:
799 * 000 DREFCLK (default is 120 MHz) for DAC/HDMI/DVI/DP
800 * 001 Super SSC 120MHz super-spread clock
801 * 011 SSC Spread spectrum input clock (120MHz default) for LVDS/DP
803 dpll = igfx->pipe[x].fdi->dpll;
804 dpll->ctrl.v &= ~(7<<13);
805 dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
808 /* select port clock to pipe */
809 igfx->pipe[x].clksel.v = port+1-PortDPA<<29;
811 if(igfx->dp[port-PortDPA].hdmi){
812 /* select port clock */
813 igfx->dpllsel[port-PortDPA].v = 1<<31; /* WRPLL1 */
814 igfx->pipe[x].dpll = &igfx->dpll[1];
816 dpll = igfx->pipe[x].dpll;
818 dpll->ctrl.v = 1<<31;
819 /* LCPLL 2700 (non scc) reference */
820 dpll->ctrl.v |= 3<<28;
822 genwrpll(freq, &n2, &p1, &r2);
823 dpll->ctrl.v |= n2 << 16;
824 dpll->ctrl.v |= p1 << 8;
827 /* select port clock */
828 igfx->dpllsel[port-PortDPA].v = 1<<29; /* LCPLL 1350 */
829 /* keep preconfigured frequency settings, keep cdclk */
830 dpll = igfx->pipe[x].dpll;
831 dpll->ctrl.v &= ~(1<<31) & ~(1<<28) & ~(1<<26);
837 cref = getcref(igfx, x);
839 /* Dpll Mode select */
840 dpll->ctrl.v &= ~(3<<26);
841 dpll->ctrl.v |= (port == PortLCD ? 2 : 1)<<26;
843 /* P2 Clock Divide */
844 dpll->ctrl.v &= ~(3<<24);
849 dpll->ctrl.v |= (1<<24);
851 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
854 /* generate 270MHz clock for displayport */
861 dpll->ctrl.v |= (1<<24);
863 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
867 /* Dpll VCO Enable */
868 dpll->ctrl.v |= (1<<31);
870 /* Dpll Serial DVO High Speed IO clock Enable */
872 dpll->ctrl.v |= (1<<30);
874 dpll->ctrl.v &= ~(1<<30);
876 /* VGA Mode Disable */
877 if(igfx->type == TypeG45)
878 dpll->ctrl.v |= (1<<28);
880 dpll->fp0.v &= ~(0x3f<<16);
881 dpll->fp0.v |= n << 16;
882 dpll->fp0.v &= ~(0x3f<<8);
883 dpll->fp0.v |= m1 << 8;
884 dpll->fp0.v &= ~(0x3f<<0);
885 dpll->fp0.v |= m2 << 0;
887 /* FP0 P1 Post Divisor */
888 dpll->ctrl.v &= ~0xFF0000;
889 dpll->ctrl.v |= 0x010000<<(p1-1);
891 /* FP1 P1 Post divisor */
892 if(igfx->pci->did != 0x27a2){
893 dpll->ctrl.v &= ~0xFF;
894 dpll->ctrl.v |= 0x01<<(p1-1);
895 dpll->fp1.v = dpll->fp0.v;
902 needlanes(int freq, int lsclk, int bpp)
907 v = ((vlong)freq * bpp) / 8;
908 for(n=1; n<4 && v>lsclk; n<<=1, v>>=1)
914 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
919 m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
921 t->dm[0].v = (tu-1)<<25 | m;
925 m = ((uvlong)n * freq) / lsclk;
930 t->dm[1].v = t->dm[0].v;
931 t->dn[1].v = t->dn[0].v;
932 t->lm[1].v = t->lm[0].v;
933 t->ln[1].v = t->ln[0].v;
937 inittrans(Trans *t, Mode *m)
939 /* clear all but 27:28 frame start delay (initialized by bios) */
942 /* tans/pipe enable */
945 /* trans/pipe timing */
946 t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
947 t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);
948 t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
949 t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
958 initpipe(Igfx *igfx, Pipe *p, Mode *m, int bpc, int port)
960 static uchar bpctab[4] = { 8, 10, 6, 12 };
964 /* source image size */
965 p->src.v = (m->x - 1)<<16 | (m->y - 1);
968 /* panel fitter off */
969 p->pfit->ctrl.v &= ~(1<<31);
970 p->pfit->winpos.v = 0;
971 p->pfit->winsize.v = 0;
974 /* enable and set monitor timings for cpu pipe */
977 /* default for displayport */
978 lanes = needlanes(m->frequency, 270*MHz, 3*bpc);
982 if(fdi->rxctl.a != 0){
983 /* enable and set monitor timings for transcoder */
986 /* tx port width selection */
987 fdi->txctl.v &= ~(7<<19);
988 fdi->txctl.v |= (lanes-1)<<19;
990 /* rx port width selection */
991 fdi->rxctl.v &= ~(7<<19);
992 fdi->rxctl.v |= (lanes-1)<<19;
993 /* bits per color for transcoder */
994 for(i=0; i<nelem(bpctab); i++){
995 if(bpctab[i] == bpc){
996 fdi->rxctl.v &= ~(7<<16);
997 fdi->rxctl.v |= i<<16;
998 fdi->dpctl.v &= ~(7<<9);
999 fdi->dpctl.v |= i<<9;
1004 /* enhanced framing on */
1005 fdi->rxctl.v |= (1<<6);
1006 fdi->txctl.v |= (1<<18);
1008 /* tusize 1 and 2 */
1009 fdi->rxtu[0].v = (tu-1)<<25;
1010 fdi->rxtu[1].v = (tu-1)<<25;
1011 initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1012 }else if(igfx->type == TypeHSW){
1013 p->dpctl.v &= 0xf773733e; /* mbz */
1014 /* transcoder enable */
1015 p->dpctl.v |= 1<<31;
1016 /* DDI select (ignored by eDP) */
1017 p->dpctl.v &= ~(7<<28);
1018 p->dpctl.v |= (port-PortDPA)<<28;
1019 /* displayport SST or hdmi mode */
1020 p->dpctl.v &= ~(7<<24);
1021 if(!igfx->dp[port-PortDPA].hdmi)
1022 p->dpctl.v |= 2<<24;
1024 p->dpctl.v |= 3<<16;
1026 p->dpctl.v ^= 1<<16;
1028 p->dpctl.v ^= 1<<17;
1029 /* eDP input select: always on power well */
1030 p->dpctl.v &= ~(7<<12);
1032 if(igfx->dp[port-PortDPA].hdmi)
1035 p->dpctl.v &= ~(7<<1);
1036 p->dpctl.v |= lanes-1 << 1;
1040 /* bits per color for cpu pipe */
1041 for(i=0; i<nelem(bpctab); i++){
1042 if(bpctab[i] == bpc){
1043 if(igfx->type == TypeHSW){
1044 p->dpctl.v &= ~(7<<20);
1045 p->dpctl.v |= i<<20;
1047 p->conf.v &= ~(7<<5);
1053 initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1057 init(Vga* vga, Ctlr* ctlr)
1059 int x, nl, port, bpc;
1068 error("%s: unsupported color depth %d\n", ctlr->name, m->z);
1070 bpc = 8; /* bits per color channel */
1072 igfx = vga->private;
1075 igfx->vgacntrl.v |= (1<<31);
1077 /* disable all pipes and ports */
1078 igfx->ppcontrol.v &= 10; /* 15:4 mbz; unset 5<<0 */
1079 igfx->lvds.v &= ~(1<<31);
1080 igfx->adpa.v &= ~(1<<31);
1081 if(igfx->type == TypeG45)
1082 igfx->adpa.v |= (3<<10); /* Monitor DPMS: off */
1083 if(igfx->type == TypeHSW){
1084 for(x=1; x<nelem(igfx->dpll); x++)
1085 igfx->dpll[x].ctrl.v &= ~(1<<31);
1086 for(x=0; x<nelem(igfx->dpllsel); x++)
1087 igfx->dpllsel[x].v = 7<<29;
1089 for(x=0; x<nelem(igfx->dp); x++){
1090 igfx->dp[x].ctl.v &= ~(1<<31);
1091 igfx->dp[x].bufctl.v &= ~(1<<31);
1093 for(x=0; x<nelem(igfx->hdmi); x++)
1094 igfx->hdmi[x].ctl.v &= ~(1<<31);
1095 for(x=0; x<igfx->npipe; x++){
1096 /* disable displayport transcoders */
1097 igfx->pipe[x].dpctl.v &= ~(1<<31);
1098 igfx->pipe[x].fdi->dpctl.v &= ~(1<<31);
1099 if(igfx->type == TypeHSW){
1100 igfx->pipe[x].dpctl.v &= ~(7<<28);
1101 igfx->pipe[x].fdi->dpctl.v &= ~(7<<28);
1103 igfx->pipe[x].dpctl.v |= (3<<29);
1104 igfx->pipe[x].fdi->dpctl.v |= (3<<29);
1106 /* disable transcoder/pipe */
1107 igfx->pipe[x].conf.v &= ~(1<<31);
1108 igfx->pipe[x].fdi->conf.v &= ~(1<<31);
1111 if((val = dbattr(m->attr, "display")) != nil){
1113 if(igfx->type == TypeHSW && !igfx->dp[port-PortDPA].hdmi)
1115 }else if(dbattr(m->attr, "lcd") != nil)
1120 trace("%s: display #%d\n", ctlr->name, port+1);
1125 error("%s: display #%d not supported\n", ctlr->name, port+1);
1129 if(igfx->type == TypeHSW) /* unimplemented */
1131 if(igfx->type == TypeG45)
1132 x = (igfx->adpa.v >> 30) & 1;
1134 x = (igfx->adpa.v >> 29) & 3;
1135 igfx->adpa.v |= (1<<31);
1136 if(igfx->type == TypeG45){
1137 igfx->adpa.v &= ~(3<<10); /* Monitor DPMS: on */
1139 igfx->adpa.v &= ~(1<<15); /* ADPA Polarity Select */
1140 igfx->adpa.v |= 3<<3;
1142 igfx->adpa.v ^= 1<<3;
1144 igfx->adpa.v ^= 1<<4;
1149 if(igfx->type == TypeHSW)
1151 if(igfx->type == TypeG45)
1152 x = (igfx->lvds.v >> 30) & 1;
1154 x = (igfx->lvds.v >> 29) & 3;
1155 igfx->lvds.v |= (1<<31);
1156 igfx->ppcontrol.v |= 5;
1158 if(igfx->type == TypeG45){
1159 igfx->lvds.v &= ~(1<<24); /* data format select 18/24bpc */
1161 igfx->lvds.v &= ~(3<<20);
1163 igfx->lvds.v ^= 1<<20;
1165 igfx->lvds.v ^= 1<<21;
1167 igfx->lvds.v |= (1<<15); /* border enable */
1176 r = &igfx->dp[port - PortDPA].ctl;
1181 /* use PIPE_A for displayport */
1184 if(igfx->type == TypeHSW){
1185 if(port == PortDPA){
1186 /* only enable panel for eDP */
1187 igfx->ppcontrol.v |= 5;
1193 r->v &= ~(7<<28) & ~(1<<26) & ~(63<<19) & ~(3<<16) & ~(15<<11) & ~(1<<7) & ~31;
1194 /* displayport SST mode */
1196 /* link not in training, send normal pixels */
1198 if(igfx->dp[port-PortDPA].hdmi){
1199 /* hdmi: do not configure displayport */
1204 r = &igfx->dp[port - PortDPA].bufctl;
1208 r->v &= ~(7<<28) & ~(127<<17) & ~(255<<8) & ~(3<<5);
1209 /* grab lanes shared with port e when using port a */
1212 else if(port == PortDPE)
1213 igfx->dp[0].bufctl.v &= ~(1<<4);
1216 if(!igfx->dp[port-PortDPA].hdmi){
1217 nl = needlanes(m->frequency, 270*MHz, 3*bpc);
1218 /* x4 unsupported on port e */
1219 if(nl > 2 && port == PortDPE)
1223 /* port reversal: off */
1226 /* buffer translation (vsl/pel) */
1227 r = igfx->dp[port - PortDPA].buftrans;
1228 r[1].v = 0x0006000E; r[0].v = 0x00FFFFFF;
1229 r[3].v = 0x0005000A; r[2].v = 0x00D75FFF;
1230 r[5].v = 0x00040006; r[4].v = 0x00C30FFF;
1231 r[7].v = 0x000B0000; r[6].v = 0x80AAAFFF;
1232 r[9].v = 0x0005000A; r[8].v = 0x00FFFFFF;
1233 r[11].v = 0x000C0004; r[10].v = 0x00D75FFF;
1234 r[13].v = 0x000B0000; r[12].v = 0x80C30FFF;
1235 r[15].v = 0x00040006; r[14].v = 0x00FFFFFF;
1236 r[17].v = 0x000B0000; r[16].v = 0x80D75FFF;
1237 r[19].v = 0x00040006; r[18].v = 0x00FFFFFF;
1244 /* port width selection */
1246 r->v |= needlanes(m->frequency, 270*MHz, 3*bpc)-1 << 19;
1248 /* port reversal: off */
1252 /* displayport transcoder */
1253 if(port == PortDPA){
1256 /* pll frequency: 270mhz */
1263 } else if(igfx->pipe[x].fdi->dpctl.a != 0){
1266 /* audio output: disable */
1268 /* transcoder displayport configuration */
1269 r = &igfx->pipe[x].fdi->dpctl;
1270 /* transcoder enable */
1272 /* port select: B,C,D */
1274 r->v |= (port-PortDPB)<<29;
1286 /* plane enable, 32bpp */
1287 p->dsp->cntr.v = (1<<31) | (6<<26);
1288 if(igfx->type == TypeG45)
1289 p->dsp->cntr.v |= x<<24; /* pipe assign */
1291 p->dsp->cntr.v &= ~511; /* mbz */
1293 /* stride must be 64 byte aligned */
1294 p->dsp->stride.v = m->x * (m->z / 8);
1295 p->dsp->stride.v += 63;
1296 p->dsp->stride.v &= ~63;
1298 /* virtual width in pixels */
1299 vga->virtx = p->dsp->stride.v / (m->z / 8);
1301 /* plane position and size */
1303 p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1); /* sic */
1306 p->dsp->linoff.v = 0;
1307 p->dsp->tileoff.v = 0;
1308 p->dsp->leftsurf.v = 0;
1310 /* cursor plane off */
1312 if(igfx->type == TypeG45)
1313 p->cur->cntr.v |= x<<28; /* pipe assign */
1317 if(initdpll(igfx, x, m->frequency, port) < 0)
1318 error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
1320 initpipe(igfx, p, m, bpc, port);
1322 ctlr->flag |= Finit;
1326 loadtrans(Igfx *igfx, Trans *t)
1333 /* program trans/pipe timings */
1334 loadreg(igfx, t->ht);
1335 loadreg(igfx, t->hb);
1336 loadreg(igfx, t->hs);
1337 loadreg(igfx, t->vt);
1338 loadreg(igfx, t->vb);
1339 loadreg(igfx, t->vs);
1340 loadreg(igfx, t->vss);
1342 loadreg(igfx, t->dm[0]);
1343 loadreg(igfx, t->dn[0]);
1344 loadreg(igfx, t->lm[0]);
1345 loadreg(igfx, t->ln[0]);
1346 loadreg(igfx, t->dm[1]);
1347 loadreg(igfx, t->dn[1]);
1348 loadreg(igfx, t->lm[1]);
1349 loadreg(igfx, t->ln[1]);
1351 if(t->dpll != nil && igfx->type != TypeHSW){
1353 t->dpll->ctrl.v &= ~(1<<31);
1354 loadreg(igfx, t->dpll->ctrl);
1355 loadreg(igfx, t->dpll->fp0);
1356 loadreg(igfx, t->dpll->fp1);
1359 t->dpll->ctrl.v |= (1<<31);
1360 loadreg(igfx, t->dpll->ctrl);
1364 /* workarround: set timing override bit */
1365 csr(igfx, t->chicken.a, 0, 1<<31);
1367 /* enable displayport transcoder */
1368 loadreg(igfx, t->dpctl);
1370 /* enable trans/pipe */
1371 t->conf.v |= (1<<31);
1372 t->conf.v &= ~(1<<30);
1373 loadreg(igfx, t->conf);
1374 for(i=0; i<100; i++){
1376 if(rr(igfx, t->conf.a) & (1<<30))
1382 enablepipe(Igfx *igfx, int x)
1388 if((p->conf.v & (1<<31)) == 0)
1389 return; /* pipe is disabled, done */
1391 /* select pipe clock */
1392 loadreg(igfx, p->clksel);
1394 if(p->fdi->rxctl.a != 0){
1395 p->fdi->rxctl.v &= ~(1<<31);
1396 p->fdi->rxctl.v &= ~(1<<4); /* rawclk */
1397 p->fdi->rxctl.v |= (1<<13); /* enable pll */
1398 loadreg(igfx, p->fdi->rxctl);
1400 p->fdi->rxctl.v |= (1<<4); /* pcdclk */
1401 loadreg(igfx, p->fdi->rxctl);
1403 /* clear auto training bits */
1404 if(igfx->type == TypeSNB)
1405 p->fdi->txctl.v &= ~(3<<28 | 1<<10 | 1);
1407 p->fdi->txctl.v &= ~(7<<8 | 1);
1408 p->fdi->txctl.v &= ~(1<<31); /* disable */
1409 p->fdi->txctl.v |= (1<<14); /* enable pll */
1410 loadreg(igfx, p->fdi->txctl);
1414 /* image size (vga needs to be off) */
1415 loadreg(igfx, p->src);
1417 /* set panel fitter as needed */
1419 loadreg(igfx, p->pfit->ctrl);
1420 loadreg(igfx, p->pfit->winpos);
1421 loadreg(igfx, p->pfit->winsize); /* arm */
1424 /* keep planes disabled while pipe comes up */
1425 if(igfx->type == TypeG45)
1428 /* enable cpu pipe */
1432 loadreg(igfx, p->dsp->cntr);
1433 loadreg(igfx, p->dsp->linoff);
1434 loadreg(igfx, p->dsp->stride);
1435 loadreg(igfx, p->dsp->tileoff);
1436 loadreg(igfx, p->dsp->size);
1437 loadreg(igfx, p->dsp->pos);
1438 loadreg(igfx, p->dsp->surf); /* arm */
1439 loadreg(igfx, p->dsp->leftsurf);
1441 /* program cursor */
1442 loadreg(igfx, p->cur->cntr);
1443 loadreg(igfx, p->cur->pos);
1444 loadreg(igfx, p->cur->base); /* arm */
1447 if(igfx->type == TypeG45) {
1448 p->conf.v &= ~(3<<18);
1449 loadreg(igfx, p->conf);
1452 if(p->fdi->rxctl.a != 0){
1454 loadreg(igfx, p->fdi->rxtu[1]);
1455 loadreg(igfx, p->fdi->rxtu[0]);
1456 loadreg(igfx, p->fdi->rxmisc);
1458 if(igfx->type == TypeSNB){
1459 /* unmask bit lock and symbol lock bits */
1460 csr(igfx, p->fdi->rximr.a, 3<<8, 0);
1462 p->fdi->txctl.v &= ~(3<<28); /* link train pattern1 */
1463 p->fdi->txctl.v |= 1<<31; /* enable */
1464 loadreg(igfx, p->fdi->txctl);
1466 p->fdi->rxctl.v &= ~(3<<8); /* link train pattern1 */
1467 p->fdi->rxctl.v |= 1<<31; /* enable */
1468 loadreg(igfx, p->fdi->rxctl);
1470 /* wait for bit lock */
1471 for(i=0; i<10; i++){
1473 if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
1476 csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
1478 /* switch to link train pattern2 */
1479 csr(igfx, p->fdi->txctl.a, 3<<28, 1<<28);
1480 csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
1482 /* wait for symbol lock */
1483 for(i=0; i<10; i++){
1485 if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
1488 csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
1490 /* switch to link train normal */
1491 csr(igfx, p->fdi->txctl.a, 0, 3<<28);
1492 csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
1494 /* wait idle pattern time */
1497 p->fdi->rxctl.v &= ~(3<<8); /* link train pattern 00 */
1498 p->fdi->rxctl.v |= 1<<10; /* auto train enable */
1499 p->fdi->rxctl.v |= 1<<31; /* enable */
1500 loadreg(igfx, p->fdi->rxctl);
1502 p->fdi->txctl.v &= ~(3<<8); /* link train pattern 00 */
1503 p->fdi->txctl.v |= 1<<10; /* auto train enable */
1504 p->fdi->txctl.v |= 1<<31; /* enable */
1505 loadreg(igfx, p->fdi->txctl);
1507 /* wait for link training done */
1508 for(i=0; i<200; i++){
1510 if(rr(igfx, p->fdi->txctl.a) & 2)
1516 /* enable the transcoder */
1517 loadtrans(igfx, p->fdi);
1521 disabletrans(Igfx *igfx, Trans *t)
1525 /* deselect pipe clock */
1526 csr(igfx, t->clksel.a, 7<<29, 0);
1528 /* disable displayport transcoder */
1529 if(igfx->type == TypeHSW){
1530 csr(igfx, t->dpctl.a, 15<<28, 0);
1531 csr(igfx, t->ht.a, ~0, 0);
1532 csr(igfx, t->hb.a, ~0, 0);
1533 csr(igfx, t->hs.a, ~0, 0);
1534 csr(igfx, t->vt.a, ~0, 0);
1535 csr(igfx, t->vb.a, ~0, 0);
1536 csr(igfx, t->vs.a, ~0, 0);
1537 csr(igfx, t->vss.a, ~0, 0);
1539 csr(igfx, t->dpctl.a, 1<<31, 3<<29);
1541 /* disable transcoder / pipe */
1542 csr(igfx, t->conf.a, 1<<31, 0);
1543 for(i=0; i<100; i++){
1545 if((rr(igfx, t->conf.a) & (1<<30)) == 0)
1548 /* workarround: clear timing override bit */
1549 csr(igfx, t->chicken.a, 1<<31, 0);
1552 if(igfx->type != TypeHSW && t->dpll != nil)
1553 csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
1557 disablepipe(Igfx *igfx, int x)
1564 csr(igfx, p->dsp->cntr.a, 1<<31, 0);
1565 wr(igfx, p->dsp->surf.a, 0); /* arm */
1567 if(igfx->type == TypeHSW)
1568 csr(igfx, p->cur->cntr.a, 0x3F, 0);
1570 csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
1571 wr(igfx, p->cur->base.a, 0); /* arm */
1573 /* display/overlay/cursor planes off */
1574 if(igfx->type == TypeG45)
1575 csr(igfx, p->conf.a, 0, 3<<18);
1576 csr(igfx, p->src.a, ~0, 0);
1578 /* disable cpu pipe */
1579 disabletrans(igfx, p);
1581 /* disable panel fitter */
1583 csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
1585 /* disable fdi transmitter and receiver */
1586 csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
1587 csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
1589 /* disable pch transcoder */
1590 disabletrans(igfx, p->fdi);
1592 /* disable pch dpll enable bit */
1593 if(igfx->type != TypeHSW)
1594 csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
1598 checkgtt(Igfx *igfx, Mode *m)
1602 char buf[64], *fl[5];
1603 u32int i, j, pa, nilpte, *gtt;
1605 if(igfx->mmio == nil)
1607 gtt = (u32int*)((uchar*)igfx->mmio + igfx->pci->mem[0].size/2);
1608 pa = (gtt[0] & ~((1<<12)-1)) + (1<<12) | 1;
1609 for(i=1; i<64*1024/4-4; i++, pa+=1<<12)
1610 if((gtt[i] & ~((1<<11)-1<<1)) != pa)
1612 n = m->x * m->y * m->z / 8;
1616 /* unmap pages past stolen memory */
1617 nilpte = gtt[64*1024/4-5];
1618 wr(igfx, 0x2170, 0); /* flush write buffers */
1619 for(j=i; j<64*1024/4-5; j++){
1620 if((gtt[j] & 1) == 0 || (gtt[j] & ~((1<<11)-1<<1)) == pa)
1625 wr(igfx, 0x2170, 0); /* flush write buffers */
1627 trace("%s: mapping %lud additional bytes for requested mode\n", igfx->ctlr->name, n - (i<<12));
1628 snprint(buf, sizeof buf, "#g/igfxtra");
1629 if((fd = open(buf, OREAD)) >= 0){
1634 if((fd = create(buf, OREAD, DMDIR|0777)) < 0)
1637 strncat(buf, "/ctl", sizeof(buf)-strlen("/ctl"));
1638 if((fd = open(buf, ORDWR|OTRUNC)) < 0)
1640 snprint(buf, sizeof buf, "va 0x10000000 %#lux fixed", n - (i<<12));
1641 if(write(fd, buf, strlen(buf)) < 0){
1646 if((c = read(fd, buf, sizeof buf)) <= 0){
1652 if(getfields(buf, fl, nelem(fl), 0, " ") != nelem(fl)
1653 || (pa = strtoul(fl[4], nil, 16)) == 0){
1654 werrstr("invalid physical base address");
1658 wr(igfx, 0x2170, 0); /* flush write buffers */
1659 for(; i<n; i++, pa+=1<<12)
1661 wr(igfx, 0x2170, 0); /* flush write buffers */
1664 trace("%s: checkgtt: %r\n", igfx->ctlr->name);
1668 load(Vga* vga, Ctlr* ctlr)
1673 igfx = vga->private;
1676 if(igfx->ppcontrol.a != 0){
1677 csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
1678 for(x=0; x<5000; x++){
1680 if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
1686 csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
1687 csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
1688 csr(igfx, igfx->adpa.a, 1<<31, 0);
1689 csr(igfx, igfx->lvds.a, 1<<31, 0);
1690 for(x = 0; x < nelem(igfx->dp); x++){
1691 csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
1692 if(igfx->dp[x].bufctl.a != 0){
1693 csr(igfx, igfx->dp[x].bufctl.a, 1<<31, 0);
1694 /* wait for buffers to return to idle */
1697 if(rr(igfx, igfx->dp[x].bufctl.a) & 1<<7)
1702 for(x = 0; x < nelem(igfx->hdmi); x++)
1703 csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
1705 /* disable vga plane */
1706 csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
1708 /* turn off all pipes */
1709 for(x = 0; x < igfx->npipe; x++)
1710 disablepipe(igfx, x);
1712 /* check if enough memory has been mapped for requested mode */
1713 checkgtt(igfx, vga->mode);
1715 if(igfx->type == TypeG45){
1716 /* toggle dsp a on and off (from enable sequence) */
1717 csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);
1718 csr(igfx, igfx->pipe[0].dsp->cntr.a, 0, 1<<31);
1719 wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1720 csr(igfx, igfx->pipe[0].dsp->cntr.a, 1<<31, 0);
1721 wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1722 csr(igfx, igfx->pipe[0].conf.a, 0, 3<<18);
1725 if(igfx->type == TypeHSW){
1726 /* deselect port clock */
1727 for(x=0; x<nelem(igfx->dpllsel); x++)
1728 csr(igfx, igfx->dpllsel[x].a, 0, 7<<29);
1730 /* disable dpll's other than LCPLL */
1731 for(x=1; x<nelem(igfx->dpll); x++)
1732 csr(igfx, igfx->dpll[x].ctrl.a, 1<<31, 0);
1735 /* program new clock sources */
1736 loadreg(igfx, igfx->rawclkfreq);
1737 loadreg(igfx, igfx->drefctl);
1738 /* program cpu pll */
1739 if(igfx->type == TypeHSW)
1740 for(x=0; x<nelem(igfx->dpll); x++)
1741 loadreg(igfx, igfx->dpll[x].ctrl);
1744 /* set lvds before enabling dpll */
1745 loadreg(igfx, igfx->lvds);
1747 /* new dpll setting */
1748 for(x=0; x<nelem(igfx->dpllsel); x++)
1749 loadreg(igfx, igfx->dpllsel[x]);
1751 /* program all pipes */
1752 for(x = 0; x < igfx->npipe; x++)
1753 enablepipe(igfx, x);
1755 /* program vga plane */
1756 loadreg(igfx, igfx->vgacntrl);
1759 loadreg(igfx, igfx->adpa);
1760 loadreg(igfx, igfx->sdvob);
1761 loadreg(igfx, igfx->sdvoc);
1762 for(x = 0; x < nelem(igfx->dp); x++){
1763 for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
1764 loadreg(igfx, igfx->dp[x].buftrans[y]);
1765 loadreg(igfx, igfx->dp[x].bufctl);
1766 if(enabledp(igfx, &igfx->dp[x]) < 0)
1767 ctlr->flag |= Ferror;
1770 /* program lcd power */
1771 loadreg(igfx, igfx->ppcontrol);
1773 ctlr->flag |= Fload;
1777 dumpreg(char *name, char *item, Reg r)
1782 printitem(name, item);
1783 Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
1787 dumphex(char *name, char *item, uchar *data, int len)
1791 for(i=0; i<len; i++){
1794 Bprint(&stdout, "\n");
1795 printitem(name, item);
1796 Bprint(&stdout, " [%.2x] =", i);
1798 Bprint(&stdout, " %.2X", data[i]);
1800 Bprint(&stdout, "\n");
1804 dumptiming(char *name, Trans *t)
1808 if(t->dm[0].a != 0 && t->dm[0].v != 0){
1809 tu = 1+((t->dm[0].v >> 25) & 0x3f);
1810 printitem(name, "dm1 tu");
1811 Bprint(&stdout, " %d\n", tu);
1813 m = t->dm[0].v & 0xffffff;
1816 printitem(name, "dm1/dn1");
1817 Bprint(&stdout, " %f\n", (double)m / (double)n);
1823 printitem(name, "lm1/ln1");
1824 Bprint(&stdout, " %f\n", (double)m / (double)n);
1830 dumptrans(char *name, Trans *t)
1832 dumpreg(name, "conf", t->conf);
1834 dumpreg(name, "dm1", t->dm[0]);
1835 dumpreg(name, "dn1", t->dn[0]);
1836 dumpreg(name, "lm1", t->lm[0]);
1837 dumpreg(name, "ln1", t->ln[0]);
1838 dumpreg(name, "dm2", t->dm[1]);
1839 dumpreg(name, "dn2", t->dn[1]);
1840 dumpreg(name, "lm2", t->lm[1]);
1841 dumpreg(name, "ln2", t->ln[1]);
1843 dumptiming(name, t);
1845 dumpreg(name, "ht", t->ht);
1846 dumpreg(name, "hb", t->hb);
1847 dumpreg(name, "hs", t->hs);
1849 dumpreg(name, "vt", t->vt);
1850 dumpreg(name, "vb", t->vb);
1851 dumpreg(name, "vs", t->vs);
1852 dumpreg(name, "vss", t->vss);
1854 dumpreg(name, "dpctl", t->dpctl);
1855 dumpreg(name, "clksel", t->clksel);
1859 dumppipe(Igfx *igfx, int x)
1866 snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
1867 dumpreg(name, "src", p->src);
1870 snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
1871 dumptrans(name, p->fdi);
1872 dumpreg(name, "txctl", p->fdi->txctl);
1873 dumpreg(name, "rxctl", p->fdi->rxctl);
1874 dumpreg(name, "rxmisc", p->fdi->rxmisc);
1875 dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
1876 dumpreg(name, "rxtu2", p->fdi->rxtu[1]);
1878 snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
1879 dumpreg(name, "cntr", p->dsp->cntr);
1880 dumpreg(name, "linoff", p->dsp->linoff);
1881 dumpreg(name, "stride", p->dsp->stride);
1882 dumpreg(name, "surf", p->dsp->surf);
1883 dumpreg(name, "tileoff", p->dsp->tileoff);
1884 dumpreg(name, "leftsurf", p->dsp->leftsurf);
1885 dumpreg(name, "pos", p->dsp->pos);
1886 dumpreg(name, "size", p->dsp->size);
1888 snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
1889 dumpreg(name, "cntr", p->cur->cntr);
1890 dumpreg(name, "base", p->cur->base);
1891 dumpreg(name, "pos", p->cur->pos);
1895 dumpdpll(Igfx *igfx, int x)
1897 int cref, m1, m2, n, p1, p2;
1903 dpll = &igfx->dpll[x];
1904 snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
1906 dumpreg(name, "ctrl", dpll->ctrl);
1907 dumpreg(name, "fp0", dpll->fp0);
1908 dumpreg(name, "fp1", dpll->fp1);
1910 if(igfx->type == TypeHSW)
1913 p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
1914 if(((dpll->ctrl.v >> 24) & 3) == 1)
1916 m = (dpll->ctrl.v >> 16) & 0xFF;
1917 for(p1 = 1; p1 <= 8; p1++)
1920 printitem(name, "ctrl p1");
1921 Bprint(&stdout, " %d\n", p1);
1922 printitem(name, "ctrl p2");
1923 Bprint(&stdout, " %d\n", p2);
1925 n = (dpll->fp0.v >> 16) & 0x3f;
1926 m1 = (dpll->fp0.v >> 8) & 0x3f;
1927 m2 = (dpll->fp0.v >> 0) & 0x3f;
1929 cref = getcref(igfx, x);
1930 freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
1932 printitem(name, "fp0 m1");
1933 Bprint(&stdout, " %d\n", m1);
1934 printitem(name, "fp0 m2");
1935 Bprint(&stdout, " %d\n", m2);
1936 printitem(name, "fp0 n");
1937 Bprint(&stdout, " %d\n", n);
1939 printitem(name, "cref");
1940 Bprint(&stdout, " %d\n", cref);
1941 printitem(name, "fp0 freq");
1942 Bprint(&stdout, " %lld\n", freq);
1946 dump(Vga* vga, Ctlr* ctlr)
1952 if((igfx = vga->private) == nil)
1955 for(x=0; x<igfx->npipe; x++)
1958 for(x=0; x<nelem(igfx->dpll); x++)
1961 for(x=0; x<nelem(igfx->dpllsel); x++){
1962 snprint(name, sizeof(name), "%s dpllsel %c", ctlr->name, 'a'+x);
1963 dumpreg(name, "dpllsel", igfx->dpllsel[x]);
1966 dumpreg(ctlr->name, "drefctl", igfx->drefctl);
1967 dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
1968 dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
1970 for(x=0; x<nelem(igfx->dp); x++){
1971 if(igfx->dp[x].ctl.a == 0)
1973 snprint(name, sizeof(name), "%s dp %c", ctlr->name, 'a'+x);
1974 dumpreg(name, "ctl", igfx->dp[x].ctl);
1975 dumpreg(name, "bufctl", igfx->dp[x].bufctl);
1976 dumpreg(name, "stat", igfx->dp[x].stat);
1977 dumphex(name, "dpcd", igfx->dp[x].dpcd, sizeof(igfx->dp[x].dpcd));
1978 for(y=0; y<nelem(igfx->dp[x].buftrans); y++){
1979 snprint(name, sizeof(name), "%s buftrans %c %d", ctlr->name, 'a'+x, y);
1980 dumpreg(name, "ctl", igfx->dp[x].buftrans[y]);
1983 for(x=0; x<nelem(igfx->hdmi); x++){
1984 snprint(name, sizeof(name), "%s hdmi %c", ctlr->name, 'a'+x);
1985 dumpreg(name, "ctl", igfx->hdmi[x].ctl);
1988 for(x=0; x<nelem(igfx->pfit); x++){
1989 snprint(name, sizeof(name), "%s pfit %c", ctlr->name, 'a'+x);
1990 dumpreg(name, "ctrl", igfx->pfit[x].ctrl);
1991 dumpreg(name, "winpos", igfx->pfit[x].winpos);
1992 dumpreg(name, "winsize", igfx->pfit[x].winsize);
1993 dumpreg(name, "pwrgate", igfx->pfit[x].pwrgate);
1996 dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
1997 dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);
1999 dumpreg(ctlr->name, "adpa", igfx->adpa);
2000 dumpreg(ctlr->name, "lvds", igfx->lvds);
2001 dumpreg(ctlr->name, "sdvob", igfx->sdvob);
2002 dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
2004 dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
2008 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
2013 if(dp->auxctl.a == 0){
2014 werrstr("not present");
2019 while(rr(igfx, dp->auxctl.a) & (1<<31)){
2027 /* clear sticky bits */
2028 wr(igfx, dp->auxctl.a, (1<<28) | (1<<25) | (1<<30));
2030 for(i=0; i<nelem(dp->auxdat); i++){
2032 w |= buf[i*4+1]<<16;
2035 wr(igfx, dp->auxdat[i].a, w);
2038 /* 2X Bit Clock divider */
2039 w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3ff)) >> 1;
2040 if(w < 1 || w > 0x3fd){
2041 werrstr("bad clock");
2045 /* hack: slow down a bit */
2048 w |= 1<<31; /* SendBusy */
2049 w |= 1<<29; /* interrupt disabled */
2050 w |= 3<<26; /* timeout 1600µs */
2051 w |= len<<20; /* send bytes */
2052 w |= 5<<16; /* precharge time (5*2 = 10µs) */
2053 wr(igfx, dp->auxctl.a, w);
2057 w = rr(igfx, dp->auxctl.a);
2058 if((w & (1<<30)) != 0)
2067 werrstr("receive timeout");
2071 werrstr("receive error");
2075 len = (w >> 20) & 0x1f;
2076 for(i=0; i<nelem(dp->auxdat); i++){
2077 w = rr(igfx, dp->auxdat[i].a);
2095 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
2102 memset(buf, 0, sizeof(buf));
2103 buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
2108 if(data != nil && len > 0){
2109 if((cmd & CmdRead) == 0)
2110 memmove(buf+4, data, len);
2112 if((cmd & CmdRead) == 0)
2115 if((r = dpauxio(igfx, dp, buf, r)) < 0){
2116 trace("%s: dpauxio: dp %c, cmd %x, addr %x, len %d: %r\n",
2117 igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]), cmd, addr, len);
2120 if(r == 0 || data == nil || len == 0)
2122 if((cmd & CmdRead) != 0){
2125 memmove(data, buf+1, len);
2131 rdpaux(Igfx *igfx, Dp *dp, int addr)
2134 if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
2139 wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
2141 if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
2147 enabledp(Igfx *igfx, Dp *dp)
2154 if((dp->ctl.v & (1<<31)) == 0)
2157 /* FIXME: always times out */
2158 if(igfx->type == TypeHSW && dp == &igfx->dp[0])
2161 /* Link configuration */
2162 wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000);
2163 w = dp->ctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
2164 wdpaux(igfx, dp, 0x101, w+1);
2168 /* Link training pattern 1 */
2169 dp->ctl.v &= ~(7<<8);
2170 loadreg(igfx, dp->ctl);
2171 for(try = 0;;try++){
2174 /* Link training pattern 1 */
2175 wdpaux(igfx, dp, 0x102, 0x01);
2177 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2179 if(r & 1) /* LANE0_CR_DONE */
2182 trace("pattern1 finished: %x\n", r);
2184 /* Link training pattern 2 */
2185 dp->ctl.v &= ~(7<<8);
2187 loadreg(igfx, dp->ctl);
2188 for(try = 0;;try++){
2191 /* Link training pattern 2 */
2192 wdpaux(igfx, dp, 0x102, 0x02);
2194 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2199 trace("pattern2 finished: %x\n", r);
2201 if(igfx->type == TypeHSW){
2202 /* set link training to idle pattern and wait for 5 idle
2204 dp->ctl.v &= ~(7<<8);
2206 loadreg(igfx, dp->ctl);
2207 for(try=0; try<10; try++){
2209 if(rr(igfx, dp->stat.a) & (1<<25))
2215 dp->ctl.v &= ~(7<<8);
2217 loadreg(igfx, dp->ctl);
2218 wdpaux(igfx, dp, 0x102, 0x00);
2222 trace("training failed: %x\n", r);
2225 dp->ctl.v &= ~(1<<31);
2226 loadreg(igfx, dp->ctl);
2227 wdpaux(igfx, dp, 0x102, 0x00);
2232 edidshift(uchar buf[256])
2237 /* shift if neccesary so edid block is at the start */
2238 for(i=0; i<256-8; i++){
2239 if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
2240 && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
2241 memmove(tmp, buf, i);
2242 memmove(buf, buf + i, 256 - i);
2243 memmove(buf + (256 - i), tmp, i);
2251 snarfdpedid(Igfx *igfx, Dp *dp, int addr)
2257 for(i=0; i<sizeof(dp->dpcd); i+=16)
2258 if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
2261 if(dp->dpcd[0] == 0) /* nothing there, dont try to get edid */
2264 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
2267 for(i=0; i<sizeof(buf); i+=16){
2268 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2270 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2272 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2274 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2276 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2281 dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
2283 if((e = parseedid128(edidshift(buf))) == nil)
2284 trace("%s: snarfdpedid: dp %c: %r\n", igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]));
2289 GMBUSCP = 0, /* Clock/Port selection */
2290 GMBUSCS = 1, /* Command/Status */
2291 GMBUSST = 2, /* Status Register */
2292 GMBUSDB = 3, /* Data Buffer Register */
2293 GMBUSIM = 4, /* Interrupt Mask */
2294 GMBUSIX = 5, /* Index Register */
2298 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
2303 if(igfx->gmbus[GMBUSCP].a == 0)
2306 wr(igfx, igfx->gmbus[GMBUSCP].a, port);
2307 wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
2309 /* bus cycle without index and stop, byte count, slave address, read */
2310 wr(igfx, igfx->gmbus[GMBUSCS].a, 1<<30 | 5<<25 | len<<16 | addr<<1 | 1);
2315 for(t=0; t<100; t++){
2316 x = rr(igfx, igfx->gmbus[GMBUSST].a);
2321 if((x & (1<<11)) == 0)
2329 y = rr(igfx, igfx->gmbus[GMBUSDB].a);
2332 data[n++] = y & 0xff, y >>= 8;
2334 data[n++] = y & 0xff, y >>= 8;
2336 data[n++] = y & 0xff, y >>= 8;
2338 data[n++] = y & 0xff;
2346 snarfgmedid(Igfx *igfx, int port, int addr)
2351 if(gmbusread(igfx, port, addr, buf, 128) != 128)
2353 if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
2356 return parseedid128(edidshift(buf));
2362 options, /* options */