]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/igfx.c
igfx: add support for T510 (thanks mycroftiv)
[plan9front.git] / sys / src / cmd / aux / vga / igfx.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 typedef struct Reg Reg;
9 typedef struct Dpll Dpll;
10 typedef struct Hdmi Hdmi;
11 typedef struct Dp Dp;
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;
19
20 enum {
21         MHz = 1000000,
22 };
23
24 enum {
25         TypeG45,
26         TypeIVB,                /* Ivy Bridge */
27         TypeSNB,                /* Sandy Bridge (unfinished) */
28         TypeHSW,                /* Haswell */
29 };
30
31 enum {
32         PortVGA = 0,            /* adpa */
33         PortLCD = 1,            /* lvds */
34         PortDPA = 2,
35         PortDPB = 3,
36         PortDPC = 4,
37         PortDPD = 5,
38         PortDPE = 6,
39 };
40
41 struct Reg {
42         u32int  a;              /* address or 0 when invalid */
43         u32int  v;              /* value */
44 };
45
46 struct Dpll {
47         Reg     ctrl;           /* DPLLx_CTRL */
48         Reg     fp0;            /* FPx0 */
49         Reg     fp1;            /* FPx1 */
50 };
51
52 struct Trans {
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 */
57
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 */
65
66         Reg     conf;           /* pipe/trans CONF_x */
67         Reg     chicken;        /* workarround register */
68
69         Reg     dpctl;          /* TRANS_DP_CTL_x */
70
71         Dpll    *dpll;          /* this transcoders dpll */
72         Reg     clksel;         /* HSW: PIPE_CLK_SEL_x: transcoder clock select */
73 };
74
75 struct Hdmi {
76         Reg     ctl;
77         Reg     bufctl[4];
78 };
79
80 struct Dp {
81         /* HSW */
82         int     hdmi;
83         Reg     stat;
84         Reg     bufctl;         /* DDI_BUF_CTL_x */
85         Reg     buftrans[20];   /* DDI_BUF_TRANS */
86
87         Reg     ctl;            /* HSW: DP_TP_CTL_x */
88         Reg     auxctl;
89         Reg     auxdat[5];
90
91         uchar   dpcd[256];
92 };
93
94 struct Fdi {
95         Trans;
96
97         Reg     txctl;          /* FDI_TX_CTL */
98
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 */
104 };
105
106 struct Pfit {
107         Reg     ctrl;
108         Reg     winpos;
109         Reg     winsize;
110         Reg     pwrgate;
111 };
112
113 struct Plane {
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 */
120
121         Reg     pos;
122         Reg     size;
123 };
124
125 struct Curs {
126         Reg     cntr;
127         Reg     base;
128         Reg     pos;
129 };
130
131 struct Pipe {
132         Trans;                  /* cpu transcoder */
133
134         Reg     src;            /* PIPExSRC */
135
136         Fdi     fdi[1];         /* fdi/dp transcoder */
137
138         Plane   dsp[1];         /* display plane */
139         Curs    cur[1];         /* hardware cursor */
140
141         Pfit    *pfit;          /* selected panel fitter */
142 };
143
144 struct Igfx {
145         Ctlr    *ctlr;
146         Pcidev  *pci;
147
148         u32int  pio;
149         u32int  *mmio;
150
151         int     type;
152         int     cdclk;          /* core display clock in mhz */
153
154         int     npipe;
155         Pipe    pipe[4];
156
157         Dpll    dpll[4];
158         Pfit    pfit[3];
159
160         /* HSW */
161         int     isult;
162
163         Reg     dpllsel[5];     /* DPLL_SEL (IVB), PORT_CLK_SEL_DDIx (HSW) */
164
165         /* IVB */
166         Reg     drefctl;        /* DREF_CTL */
167         Reg     rawclkfreq;     /* RAWCLK_FREQ */
168         Reg     ssc4params;     /* SSC4_PARAMS */
169
170         Dp      dp[5];
171         Hdmi    hdmi[4];
172
173         Reg     ppcontrol;
174         Reg     ppstatus;
175
176         /* G45 */
177         Reg     gmbus[6];       /* GMBUSx */
178
179         Reg     sdvoc;
180         Reg     sdvob;
181
182         /* common */
183         Reg     adpa;
184         Reg     lvds;
185
186         Reg     vgacntrl;
187 };
188
189 static u32int
190 rr(Igfx *igfx, u32int a)
191 {
192         if(a == 0)
193                 return 0;
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);
199 }
200 static void
201 wr(Igfx *igfx, u32int a, u32int v)
202 {
203         if(a == 0)      /* invalid */
204                 return;
205         assert((a & 3) == 0);
206         if(igfx->mmio != nil){
207                 igfx->mmio[a/4] = v;
208                 return;
209         }
210         outportl(igfx->pio, a);
211         outportl(igfx->pio + 4, v);
212 }
213 static void
214 csr(Igfx *igfx, u32int reg, u32int clr, u32int set)
215 {
216         wr(igfx, reg, (rr(igfx, reg) & ~clr) | set);
217 }
218
219 static void
220 loadreg(Igfx *igfx, Reg r)
221 {
222         wr(igfx, r.a, r.v);
223 }
224
225 static Reg
226 snarfreg(Igfx *igfx, u32int a)
227 {
228         Reg r;
229
230         r.a = a;
231         r.v = rr(igfx, a);
232         return r;
233 }
234
235 static void
236 snarftrans(Igfx *igfx, Trans *t, u32int o)
237 {
238         /* pipe timing */
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);
246
247         t->conf = snarfreg(igfx, o + 0x10008);
248
249         switch(igfx->type){
250         case TypeG45:
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 */
256                 }
257                 break;
258         case TypeIVB:
259         case TypeSNB:
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);
268                 break;
269         case TypeHSW:
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);
279                 }
280                 break;
281         }
282 }
283
284 static void
285 snarfpipe(Igfx *igfx, int x)
286 {
287         u32int o;
288         Pipe *p;
289
290         p = &igfx->pipe[x];
291
292         o = x == 3 ? 0x6F000 : 0x60000 + x*0x1000;
293         snarftrans(igfx, p, o);
294
295         if(igfx->type != TypeHSW || x != 3)
296                 p->src = snarfreg(igfx, o + 0x0001C);
297
298         if(igfx->type == TypeHSW) {
299                 p->dpctl = snarfreg(igfx, o + 0x400);   /* PIPE_DDI_FUNC_CTL_x */
300                 p->dpll = &igfx->dpll[0];
301                 if(x == 3){
302                         x = 0;  /* use plane/cursor a */
303                         p->src = snarfreg(igfx, 0x6001C);
304                 }else
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);
308
309                 o = 0xE0000 | x*0x1000;
310                 snarftrans(igfx, p->fdi, o);
311
312                 p->fdi->dpctl = snarfreg(igfx, o + 0x300);
313
314                 p->fdi->rxctl = snarfreg(igfx, o + 0x1000c);
315                 p->fdi->rxmisc = snarfreg(igfx, o + 0x10010);
316
317                 p->fdi->rxiir = snarfreg(igfx, o + 0x10014);
318                 p->fdi->rximr = snarfreg(igfx, o + 0x10018);
319
320                 p->fdi->rxtu[0] = snarfreg(igfx, o + 0x10030);
321                 p->fdi->rxtu[1] = snarfreg(igfx, o + 0x10038);
322
323                 p->fdi->chicken = snarfreg(igfx, o + 0x10064);
324
325                 p->fdi->dpll = &igfx->dpll[(igfx->dpllsel[0].v>>(x*4)) & 1];
326                 p->dpll = nil;
327         } else {
328                 p->dpll = &igfx->dpll[x & 1];
329         }
330
331         /* display plane */
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);
339
340         /* cursor plane */
341         switch(igfx->type){
342         case TypeIVB:
343         case TypeHSW:
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);
347                 break;
348         case TypeG45:
349                 p->dsp->pos     = snarfreg(igfx, 0x7018C + x*0x1000);
350                 p->dsp->size    = snarfreg(igfx, 0x70190 + x*0x1000);
351                 /* wet floor */
352         case TypeSNB:
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);
356                 break;
357         }
358 }
359
360 static int
361 devtype(Igfx *igfx)
362 {
363         if(igfx->pci->vid != 0x8086)
364                 return -1;
365         switch(igfx->pci->did){
366         case 0x0a16:    /* HD 4400 - 4th Gen Core (ULT) */
367                 igfx->isult = 1;
368                 /* wet floor */
369         case 0x0412:    /* HD 4600 - 4th Gen Core */
370                 return TypeHSW;
371         case 0x0166:    /* 3rd Gen Core - ThinkPad X230 */
372         case 0x0152:    /* 2nd/3rd Gen Core - Core-i3 */
373                 return TypeIVB;
374         case 0x0046:    /* Thinkpad T510 */
375         case 0x0102:    /* Dell Optiplex 790 */
376         case 0x0126:    /* Thinkpad X220 */
377                 return TypeSNB;
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 */
382                 return TypeG45;
383         }
384         return -1;
385 }
386
387 static Edid* snarfgmedid(Igfx*, int port, int addr);
388 static Edid* snarfdpedid(Igfx*, Dp *dp, int addr);
389
390 static int enabledp(Igfx*, Dp*);
391
392 static void
393 snarf(Vga* vga, Ctlr* ctlr)
394 {
395         Igfx *igfx;
396         int x, y;
397
398         igfx = vga->private;
399         if(igfx == nil) {
400                 igfx = alloc(sizeof(Igfx));
401                 igfx->ctlr = ctlr;
402                 igfx->pci = vga->pci;
403                 if(igfx->pci == nil){
404                         error("%s: no pci device\n", ctlr->name);
405                         return;
406                 }
407                 igfx->type = devtype(igfx);
408                 if(igfx->type < 0){
409                         error("%s: unrecognized device\n", ctlr->name);
410                         return;
411                 }
412                 vgactlpci(igfx->pci);
413                 if(1){
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);
418                 } else {
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;
422                 }
423                 vga->private = igfx;
424         }
425
426         switch(igfx->type){
427         case TypeG45:
428                 igfx->npipe = 2;        /* A,B */
429                 igfx->cdclk = 200;      /* MHz */
430
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);
437
438                 igfx->adpa              = snarfreg(igfx, 0x061100);
439                 igfx->lvds              = snarfreg(igfx, 0x061180);
440                 igfx->sdvob             = snarfreg(igfx, 0x061140);
441                 igfx->sdvoc             = snarfreg(igfx, 0x061160);
442
443                 for(x=0; x<5; x++)
444                         igfx->gmbus[x]  = snarfreg(igfx, 0x5100 + x*4);
445                 igfx->gmbus[x]  = snarfreg(igfx, 0x5120);
446
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];
451
452                 igfx->ppstatus          = snarfreg(igfx, 0x61200);
453                 igfx->ppcontrol         = snarfreg(igfx, 0x61204);
454
455                 igfx->vgacntrl          = snarfreg(igfx, 0x071400);
456                 break;
457
458         case TypeSNB:
459                 igfx->npipe = 2;        /* A,B */
460                 igfx->cdclk = 400;      /* MHz */
461                 goto IVBcommon;
462
463         case TypeIVB:
464                 igfx->npipe = 3;        /* A,B,C */
465                 igfx->cdclk = 400;      /* MHz */
466                 goto IVBcommon;
467
468         IVBcommon:
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);
475
476                 igfx->dpllsel[0]        = snarfreg(igfx, 0xC7000);
477
478                 igfx->drefctl           = snarfreg(igfx, 0xC6200);
479                 igfx->ssc4params        = snarfreg(igfx, 0xC6210);
480
481                 igfx->dp[0].ctl         = snarfreg(igfx, 0x64000);
482                 for(x=1; x<4; x++)
483                         igfx->dp[x].ctl = snarfreg(igfx, 0xE4000 + 0x100*x);
484
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 */
490
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 */
496
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 */
502
503                 igfx->lvds              = snarfreg(igfx, 0x0E1180);     /* LVDS_CTL */
504                 goto PCHcommon;
505
506         case TypeHSW:
507                 igfx->npipe = 4;        /* A,B,C,eDP */
508                 igfx->cdclk = igfx->isult ? 450 : 540;  /* MHz */
509
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 */
514
515                 for(x=0; x<nelem(igfx->dp); x++){
516                         if(x == 3 && igfx->isult)       /* no DDI D */
517                                 continue;
518                         igfx->dp[x].bufctl      = snarfreg(igfx, 0x64000 + 0x100*x);
519                         igfx->dp[x].ctl         = snarfreg(igfx, 0x64040 + 0x100*x);
520                         if(x > 0)
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);
525                 }
526
527                 goto PCHcommon;
528
529         PCHcommon:
530                 igfx->rawclkfreq        = snarfreg(igfx, 0xC6204);
531
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);
539
540                 /* pch displayport B,C,D */
541                 for(x=1; x<4; x++){
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);
548                 }
549
550                 for(x=0; x<igfx->npipe; x++){
551                         if(igfx->type == TypeHSW && x == 3){
552                                 igfx->pipe[x].pfit = &igfx->pfit[0];
553                                 continue;
554                         }
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);
559
560                         y = (igfx->pfit[x].ctrl.v >> 29) & 3;
561                         if(igfx->pipe[y].pfit == nil)
562                                 igfx->pipe[y].pfit = &igfx->pfit[x];
563                 }
564
565                 igfx->ppstatus          = snarfreg(igfx, 0xC7200);
566                 igfx->ppcontrol         = snarfreg(igfx, 0xC7204);
567
568                 for(x=0; x<5; x++)
569                         igfx->gmbus[x]  = snarfreg(igfx, 0xC5100 + x*4);
570                 igfx->gmbus[x]  = snarfreg(igfx, 0xC5120);
571
572                 igfx->adpa              = snarfreg(igfx, 0x0E1100);     /* DAC_CTL */
573                 igfx->vgacntrl          = snarfreg(igfx, 0x041000);
574                 break;
575         }
576
577         for(x=0; x<igfx->npipe; x++)
578                 snarfpipe(igfx, x);
579
580         for(x=0; x<nelem(vga->edid); x++){
581                 Modelist *l;
582
583                 switch(x){
584                 case PortVGA:
585                         vga->edid[x] = snarfgmedid(igfx, 2, 0x50);
586                         break;
587                 case PortLCD:
588                         vga->edid[x] = snarfgmedid(igfx, 3, 0x50);
589                         if(vga->edid[x] == nil)
590                                 continue;
591                         for(l = vga->edid[x]->modelist; l != nil; l = l->next)
592                                 l->attr = mkattr(l->attr, "lcd", "1");
593                         break;
594                 case PortDPD:
595                         if(igfx->type == TypeHSW && igfx->isult)
596                                 continue;
597                 case PortDPA:
598                 case PortDPB:
599                 case PortDPC:
600                         vga->edid[x] = snarfdpedid(igfx, &igfx->dp[x-PortDPA], 0x50);
601                         break;
602                 default:
603                         continue;
604                 }
605
606                 if(vga->edid[x] == nil){
607                         if(x < PortDPB)
608                                 continue;
609                         vga->edid[x] = snarfgmedid(igfx, x + 1 & ~1 | x >> 1 & 1, 0x50);
610                         if(vga->edid[x] == nil)
611                                 continue;
612                         igfx->dp[x-PortDPA].hdmi = 1;
613                 }
614                 for(l = vga->edid[x]->modelist; l != nil; l = l->next)
615                         l->attr = mkattr(l->attr, "display", "%d", x+1);
616         }
617
618         ctlr->flag |= Fsnarf;
619 }
620
621 static void
622 options(Vga* vga, Ctlr* ctlr)
623 {
624         USED(vga);
625         ctlr->flag |= Hlinear|Ulinear|Foptions;
626 }
627
628 enum {
629         Lcpll = 2700,
630         Lcpll2k = Lcpll * 2000,
631 };
632
633 static int
634 wrbudget(int freq)
635 {
636         static int b[] = {
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
650         };
651         int *i;
652
653         for(i=b; i<b+nelem(b); i+=2)
654                 if(i[0] == freq)
655                         return i[1];
656         return 1000;
657 }
658
659 static void
660 genwrpll(int freq, int *n2, int *p, int *r2)
661 {
662         int budget, N2, P, R2;
663         vlong f2k, a, b, c, d, Î”, bestΔ;
664
665         f2k = freq / 100;
666         if(f2k == Lcpll2k){     /* bypass wrpll entirely and use lcpll */
667                 *n2 = 2;
668                 *p = 1;
669                 *r2 = 2;
670                 return;
671         }
672         budget = wrbudget(freq);
673         *p = 0;
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){
677                         if(*p == 0){
678                                 *n2 = N2;
679                                 *p = P;
680                                 *r2 = R2;
681                                 continue;
682                         }
683                         Î” = f2k * P * R2;
684                         Î” -= N2 * Lcpll2k;
685                         if(Δ < 0)
686                                 Î” = -Δ;
687                         bestΔ = f2k * *p * *r2;
688                         bestΔ -= *n2 * Lcpll2k;
689                         if(bestΔ < 0)
690                                 bestΔ = -bestΔ;
691                         a = f2k * budget;
692                         b = a;
693                         a *= P * R2;
694                         b *= *p * *r2;
695                         c = Î” * MHz;
696                         d = bestΔ * MHz;
697                         if(a < c && b < d && *p * *r2 * Î” < P * R2 * bestΔ
698                         || a >= c && b < d
699                         || a >= c && b >= d && N2 * *r2 * *r2 > *n2 * R2 * R2){
700                                 *n2 = N2;
701                                 *p = P;
702                                 *r2 = R2;
703                         }
704                 }
705 }
706
707 static int
708 genpll(int freq, int cref, int P2, int *m1, int *m2, int *n, int *p1)
709 {
710         int M1, M2, M, N, P, P1;
711         int best, error;
712         vlong a;
713
714         best = -1;
715         for(N=3; N<=8; N++)
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)
722                         continue;
723                 for(P1=1; P1<=8; P1++){
724                         P = P1 * P2;
725                         if(P < 5 || P > 98)
726 //                      if(P < 4 || P > 98)
727                                 continue;
728                         a = cref;
729                         a *= M;
730                         a /= N+2;
731                         a /= P;
732                         if(a < 20*MHz || a > 400*MHz)
733                                 continue;
734                         error = a;
735                         error -= freq;
736                         if(error < 0)
737                                 error = -error;
738                         if(best < 0 || error < best){
739                                 best = error;
740                                 *m1 = M1;
741                                 *m2 = M2;
742                                 *n = N;
743                                 *p1 = P1;
744                         }
745                 }
746         }
747         return best;
748 }
749
750 static int
751 getcref(Igfx *igfx, int x)
752 {
753         Dpll *dpll;
754
755         dpll = &igfx->dpll[x];
756         if(igfx->type == TypeG45){
757                 if(((dpll->ctrl.v >> 13) & 3) == 3)
758                         return 100*MHz;
759                 return 96*MHz;
760         }
761         return 120*MHz;
762 }
763
764 static int
765 initdpll(Igfx *igfx, int x, int freq, int port)
766 {
767         int cref, m1, m2, n, n2, p1, p2, r2;
768         Dpll *dpll;
769
770         switch(igfx->type){
771         case TypeG45:
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;
776                 break;
777         case TypeSNB:
778         case TypeIVB:
779                 /* transcoder dpll enable */
780                 igfx->dpllsel[0].v |= 8<<(x*4);
781                 /* program rawclock to 125MHz */
782                 igfx->rawclkfreq.v = 125;
783
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;
789
790                 if(port == PortLCD){
791                         igfx->drefctl.v |= 2<<11;
792                         igfx->drefctl.v |= 1;
793                 } else {
794                         igfx->drefctl.v |= 2<<9;
795                 }
796
797                 /*
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
802                  */
803                 dpll = igfx->pipe[x].fdi->dpll;
804                 dpll->ctrl.v &= ~(7<<13);
805                 dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
806                 break;
807         case TypeHSW:
808                 /* select port clock to pipe */
809                 igfx->pipe[x].clksel.v = port+1-PortDPA<<29;
810
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];
815
816                         dpll = igfx->pipe[x].dpll;
817                         /* enable pll */
818                         dpll->ctrl.v = 1<<31;
819                         /* LCPLL 2700 (non scc) reference */
820                         dpll->ctrl.v |= 3<<28;
821
822                         genwrpll(freq, &n2, &p1, &r2);
823                         dpll->ctrl.v |= n2 << 16;
824                         dpll->ctrl.v |= p1 << 8;
825                         dpll->ctrl.v |= r2;
826                 }else{
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);
832                 }
833                 return 0;
834         default:
835                 return -1;
836         }
837         cref = getcref(igfx, x);
838
839         /* Dpll Mode select */
840         dpll->ctrl.v &= ~(3<<26);
841         dpll->ctrl.v |= (port == PortLCD ? 2 : 1)<<26;
842
843         /* P2 Clock Divide */
844         dpll->ctrl.v &= ~(3<<24);
845         if(port == PortLCD){
846                 p2 = 14;
847                 if(freq > 112*MHz){
848                         p2 >>= 1;
849                         dpll->ctrl.v |= (1<<24);
850                 }
851                 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
852                         return -1;
853         } else {
854                 /* generate 270MHz clock for displayport */
855                 if(port >= PortDPA)
856                         freq = 270*MHz;
857
858                 p2 = 10;
859                 if(freq > 270*MHz){
860                         p2 >>= 1;
861                         dpll->ctrl.v |= (1<<24);
862                 }
863                 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
864                         return -1;
865         }
866
867         /* Dpll VCO Enable */
868         dpll->ctrl.v |= (1<<31);
869
870         /* Dpll Serial DVO High Speed IO clock Enable */
871         if(port >= PortDPA)
872                 dpll->ctrl.v |= (1<<30);
873         else
874                 dpll->ctrl.v &= ~(1<<30);
875
876         /* VGA Mode Disable */
877         if(igfx->type == TypeG45)
878                 dpll->ctrl.v |= (1<<28);
879
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;
886
887         /* FP0 P1 Post Divisor */
888         dpll->ctrl.v &= ~0xFF0000;
889         dpll->ctrl.v |=  0x010000<<(p1-1);
890
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;
896         }
897
898         return 0;
899 }
900
901 static int
902 needlanes(int freq, int lsclk, int bpp)
903 {
904         vlong v;
905         int n;
906
907         v = ((vlong)freq * bpp) / 8;
908         for(n=1; n<4 && v>lsclk; n<<=1, v>>=1)
909                 ;
910         return n;
911 }
912
913 static void
914 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
915 {
916         u32int m, n;
917
918         n = 0x800000;
919         m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
920
921         t->dm[0].v = (tu-1)<<25 | m;
922         t->dn[0].v = n;
923
924         n = 0x80000;
925         m = ((uvlong)n * freq) / lsclk;
926
927         t->lm[0].v = m;
928         t->ln[0].v = n;
929
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;
934 }
935
936 static void
937 inittrans(Trans *t, Mode *m)
938 {
939         /* clear all but 27:28 frame start delay (initialized by bios) */
940         t->conf.v &= 3<<27;
941
942         /* tans/pipe enable */
943         t->conf.v |= 1<<31;
944
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);
950
951         t->hb.v = t->ht.v;
952         t->vb.v = t->vt.v;
953
954         t->vss.v = 0;
955 }
956
957 static void
958 initpipe(Igfx *igfx, Pipe *p, Mode *m, int bpc, int port)
959 {
960         static uchar bpctab[4] = { 8, 10, 6, 12 };
961         int i, tu, lanes;
962         Fdi *fdi;
963
964         /* source image size */
965         p->src.v = (m->x - 1)<<16 | (m->y - 1);
966
967         if(p->pfit != nil){
968                 /* panel fitter off */
969                 p->pfit->ctrl.v &= ~(1<<31);
970                 p->pfit->winpos.v = 0;
971                 p->pfit->winsize.v = 0;
972         }
973
974         /* enable and set monitor timings for cpu pipe */
975         inittrans(p, m);
976
977         /* default for displayport */
978         lanes = needlanes(m->frequency, 270*MHz, 3*bpc);
979         tu = 64;
980
981         fdi = p->fdi;
982         if(fdi->rxctl.a != 0){
983                 /* enable and set monitor timings for transcoder */
984                 inittrans(fdi, m);
985
986                 /* tx port width selection */
987                 fdi->txctl.v &= ~(7<<19);
988                 fdi->txctl.v |= (lanes-1)<<19;
989
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;
1000                                 break;
1001                         }
1002                 }
1003
1004                 /* enhanced framing on */
1005                 fdi->rxctl.v |= (1<<6);
1006                 fdi->txctl.v |= (1<<18);
1007
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;
1023                 /* sync polarity */
1024                 p->dpctl.v |= 3<<16;
1025                 if(m->hsync == '-')
1026                         p->dpctl.v ^= 1<<16;
1027                 if(m->vsync == '-')
1028                         p->dpctl.v ^= 1<<17;
1029                 /* eDP input select: always on power well */
1030                 p->dpctl.v &= ~(7<<12);
1031                 /* dp port width */
1032                 if(igfx->dp[port-PortDPA].hdmi)
1033                         lanes = 4;
1034                 else{
1035                         p->dpctl.v &= ~(7<<1);
1036                         p->dpctl.v |= lanes-1 << 1;
1037                 }
1038         }
1039
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;
1046                         }else{
1047                                 p->conf.v &= ~(7<<5);
1048                                 p->conf.v |= i<<5;
1049                         }
1050                         break;
1051                 }
1052         }
1053         initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1054 }
1055
1056 static void
1057 init(Vga* vga, Ctlr* ctlr)
1058 {
1059         int x, nl, port, bpc;
1060         char *val;
1061         Igfx *igfx;
1062         Pipe *p;
1063         Mode *m;
1064         Reg *r;
1065
1066         m = vga->mode;
1067         if(m->z != 32)
1068                 error("%s: unsupported color depth %d\n", ctlr->name, m->z);
1069
1070         bpc = 8;        /* bits per color channel */
1071
1072         igfx = vga->private;
1073
1074         /* disable vga */
1075         igfx->vgacntrl.v |= (1<<31);
1076
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;
1088         }
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);
1092         }
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);
1102                 }else{
1103                         igfx->pipe[x].dpctl.v |= (3<<29);
1104                         igfx->pipe[x].fdi->dpctl.v |= (3<<29);
1105                 }
1106                 /* disable transcoder/pipe */
1107                 igfx->pipe[x].conf.v &= ~(1<<31);
1108                 igfx->pipe[x].fdi->conf.v &= ~(1<<31);
1109         }
1110
1111         if((val = dbattr(m->attr, "display")) != nil){
1112                 port = atoi(val)-1;
1113                 if(igfx->type == TypeHSW && !igfx->dp[port-PortDPA].hdmi)
1114                         bpc = 6;
1115         }else if(dbattr(m->attr, "lcd") != nil)
1116                 port = PortLCD;
1117         else
1118                 port = PortVGA;
1119
1120         trace("%s: display #%d\n", ctlr->name, port+1);
1121
1122         switch(port){
1123         default:
1124         Badport:
1125                 error("%s: display #%d not supported\n", ctlr->name, port+1);
1126                 break;
1127
1128         case PortVGA:
1129                 if(igfx->type == TypeHSW)       /* unimplemented */
1130                         goto Badport;
1131                 if(igfx->type == TypeG45)
1132                         x = (igfx->adpa.v >> 30) & 1;
1133                 else
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 */
1138
1139                         igfx->adpa.v &= ~(1<<15);       /* ADPA Polarity Select */
1140                         igfx->adpa.v |= 3<<3;
1141                         if(m->hsync == '-')
1142                                 igfx->adpa.v ^= 1<<3;
1143                         if(m->vsync == '-')
1144                                 igfx->adpa.v ^= 1<<4;
1145                 }
1146                 break;
1147
1148         case PortLCD:
1149                 if(igfx->type == TypeHSW)
1150                         goto Badport;
1151                 if(igfx->type == TypeG45)
1152                         x = (igfx->lvds.v >> 30) & 1;
1153                 else
1154                         x = (igfx->lvds.v >> 29) & 3;
1155                 igfx->lvds.v |= (1<<31);
1156                 igfx->ppcontrol.v |= 5;
1157
1158                 if(igfx->type == TypeG45){
1159                         igfx->lvds.v &= ~(1<<24);       /* data format select 18/24bpc */
1160
1161                         igfx->lvds.v &= ~(3<<20);
1162                         if(m->hsync == '-')
1163                                 igfx->lvds.v ^= 1<<20;
1164                         if(m->vsync == '-')
1165                                 igfx->lvds.v ^= 1<<21;
1166
1167                         igfx->lvds.v |= (1<<15);        /* border enable */
1168                 }
1169                 break;
1170
1171         case PortDPA:
1172         case PortDPB:
1173         case PortDPC:
1174         case PortDPD:
1175         case PortDPE:
1176                 r = &igfx->dp[port - PortDPA].ctl;
1177                 if(r->a == 0)
1178                         goto Badport;
1179                 /* port enable */
1180                 r->v |= 1<<31;
1181                 /* use PIPE_A for displayport */
1182                 x = 0;
1183
1184                 if(igfx->type == TypeHSW){
1185                         if(port == PortDPA){
1186                                 /* only enable panel for eDP */
1187                                 igfx->ppcontrol.v |= 5;
1188                                 /* use eDP pipe */
1189                                 x = 3;
1190                         }
1191
1192                         /* reserved MBZ */
1193                         r->v &= ~(7<<28) & ~(1<<26) & ~(63<<19) & ~(3<<16) & ~(15<<11) & ~(1<<7) & ~31;
1194                         /* displayport SST mode */
1195                         r->v &= ~(1<<27);
1196                         /* link not in training, send normal pixels */
1197                         r->v |= 3<<8;
1198                         if(igfx->dp[port-PortDPA].hdmi){
1199                                 /* hdmi: do not configure displayport */
1200                                 r->a = 0;
1201                                 r->v &= ~(1<<31);
1202                         }
1203
1204                         r = &igfx->dp[port - PortDPA].bufctl;
1205                         /* buffer enable */
1206                         r->v |= 1<<31;
1207                         /* reserved MBZ */
1208                         r->v &= ~(7<<28) & ~(127<<17) & ~(255<<8) & ~(3<<5);
1209                         /* grab lanes shared with port e when using port a */
1210                         if(port == PortDPA)
1211                                 r->v |= 1<<4;
1212                         else if(port == PortDPE)
1213                                 igfx->dp[0].bufctl.v &= ~(1<<4);
1214                         /* dp port width */
1215                         r->v &= ~(15<<1);
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)
1220                                         goto Badport;
1221                                 r->v |= nl-1 << 1;
1222                         }
1223                         /* port reversal: off */
1224                         r->v &= ~(1<<16);
1225
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;
1238                         break;
1239                 }
1240
1241                 if(port == PortDPE)
1242                         goto Badport;
1243
1244                 /* port width selection */
1245                 r->v &= ~(7<<19);
1246                 r->v |= needlanes(m->frequency, 270*MHz, 3*bpc)-1 << 19;
1247
1248                 /* port reversal: off */
1249                 r->v &= ~(1<<15);
1250                 /* reserved MBZ */
1251                 r->v &= ~(15<<11);
1252                 /* displayport transcoder */
1253                 if(port == PortDPA){
1254                         /* reserved MBZ */
1255                         r->v &= ~(15<<10);
1256                         /* pll frequency: 270mhz */
1257                         r->v &= ~(3<<16);
1258                         /* pll enable */
1259                         r->v |= 1<<14;
1260                         /* pipe select */
1261                         r->v &= ~(3<<29);
1262                         r->v |= x<<29;
1263                 } else if(igfx->pipe[x].fdi->dpctl.a != 0){
1264                         /* reserved MBZ */
1265                         r->v &= ~(15<<11);
1266                         /* audio output: disable */
1267                         r->v &= ~(1<<6);
1268                         /* transcoder displayport configuration */
1269                         r = &igfx->pipe[x].fdi->dpctl;
1270                         /* transcoder enable */
1271                         r->v |= 1<<31;
1272                         /* port select: B,C,D */
1273                         r->v &= ~(3<<29);
1274                         r->v |= (port-PortDPB)<<29;
1275                 }
1276                 /* sync polarity */
1277                 r->v |= 3<<3;
1278                 if(m->hsync == '-')
1279                         r->v ^= 1<<3;
1280                 if(m->vsync == '-')
1281                         r->v ^= 1<<4;
1282                 break;
1283         }
1284         p = &igfx->pipe[x];
1285
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 */
1290         else
1291                 p->dsp->cntr.v &= ~511; /* mbz */
1292
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;
1297
1298         /* virtual width in pixels */
1299         vga->virtx = p->dsp->stride.v / (m->z / 8);
1300
1301         /* plane position and size */
1302         p->dsp->pos.v = 0;
1303         p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1);   /* sic */
1304
1305         p->dsp->surf.v = 0;
1306         p->dsp->linoff.v = 0;
1307         p->dsp->tileoff.v = 0;
1308         p->dsp->leftsurf.v = 0;
1309
1310         /* cursor plane off */
1311         p->cur->cntr.v = 0;
1312         if(igfx->type == TypeG45)
1313                 p->cur->cntr.v |= x<<28;        /* pipe assign */
1314         p->cur->pos.v = 0;
1315         p->cur->base.v = 0;
1316
1317         if(initdpll(igfx, x, m->frequency, port) < 0)
1318                 error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
1319
1320         initpipe(igfx, p, m, bpc, port);
1321
1322         ctlr->flag |= Finit;
1323 }
1324
1325 static void
1326 loadtrans(Igfx *igfx, Trans *t)
1327 {
1328         int i;
1329
1330         if(t->conf.a == 0)
1331                 return;
1332
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);
1341
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]);
1350
1351         if(t->dpll != nil && igfx->type != TypeHSW){
1352                 /* program dpll */
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);
1357
1358                 /* enable dpll */
1359                 t->dpll->ctrl.v |= (1<<31);
1360                 loadreg(igfx, t->dpll->ctrl);
1361                 sleep(10);
1362         }
1363
1364         /* workarround: set timing override bit */
1365         csr(igfx, t->chicken.a, 0, 1<<31);
1366
1367         /* enable displayport transcoder */
1368         loadreg(igfx, t->dpctl);
1369
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++){
1375                 sleep(10);
1376                 if(rr(igfx, t->conf.a) & (1<<30))
1377                         break;
1378         }
1379 }
1380
1381 static void
1382 enablepipe(Igfx *igfx, int x)
1383 {
1384         int i;
1385         Pipe *p;
1386
1387         p = &igfx->pipe[x];
1388         if((p->conf.v & (1<<31)) == 0)
1389                 return; /* pipe is disabled, done */
1390
1391         /* select pipe clock */
1392         loadreg(igfx, p->clksel);
1393
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);
1399                 sleep(5);
1400                 p->fdi->rxctl.v |= (1<<4);      /* pcdclk */
1401                 loadreg(igfx, p->fdi->rxctl);
1402                 sleep(5);
1403                 /* clear auto training bits */
1404                 if(igfx->type == TypeSNB)
1405                         p->fdi->txctl.v &= ~(3<<28 | 1<<10 | 1);
1406                 else
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);
1411                 sleep(5);
1412         }
1413
1414         /* image size (vga needs to be off) */
1415         loadreg(igfx, p->src);
1416
1417         /* set panel fitter as needed */
1418         if(p->pfit != nil){
1419                 loadreg(igfx, p->pfit->ctrl);
1420                 loadreg(igfx, p->pfit->winpos);
1421                 loadreg(igfx, p->pfit->winsize);        /* arm */
1422         }
1423
1424         /* keep planes disabled while pipe comes up */
1425         if(igfx->type == TypeG45)
1426                 p->conf.v |= 3<<18;
1427
1428         /* enable cpu pipe */
1429         loadtrans(igfx, p);
1430
1431         /* program plane */
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);
1440
1441         /* program cursor */
1442         loadreg(igfx, p->cur->cntr);
1443         loadreg(igfx, p->cur->pos);
1444         loadreg(igfx, p->cur->base);    /* arm */
1445
1446         /* enable planes */
1447         if(igfx->type == TypeG45) {
1448                 p->conf.v &= ~(3<<18);
1449                 loadreg(igfx, p->conf);
1450         }
1451
1452         if(p->fdi->rxctl.a != 0){
1453                 /* enable fdi */
1454                 loadreg(igfx, p->fdi->rxtu[1]);
1455                 loadreg(igfx, p->fdi->rxtu[0]);
1456                 loadreg(igfx, p->fdi->rxmisc);
1457
1458                 if(igfx->type == TypeSNB){
1459                         /* unmask bit lock and symbol lock bits */
1460                         csr(igfx, p->fdi->rximr.a, 3<<8, 0);
1461
1462                         p->fdi->txctl.v &= ~(3<<28);    /* link train pattern1 */
1463                         p->fdi->txctl.v |= 1<<31;       /* enable */
1464                         loadreg(igfx, p->fdi->txctl);
1465
1466                         p->fdi->rxctl.v &= ~(3<<8);     /* link train pattern1 */
1467                         p->fdi->rxctl.v |= 1<<31;       /* enable */
1468                         loadreg(igfx, p->fdi->rxctl);
1469
1470                         /* wait for bit lock */
1471                         for(i=0; i<10; i++){
1472                                 sleep(1);
1473                                 if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
1474                                         break;
1475                         }
1476                         csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
1477         
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);
1481
1482                         /* wait for symbol lock */
1483                         for(i=0; i<10; i++){
1484                                 sleep(1);
1485                                 if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
1486                                         break;
1487                         }
1488                         csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
1489
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);
1493
1494                         /* wait idle pattern time */
1495                         sleep(5);
1496                 } else {
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);
1501
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);
1506
1507                         /* wait for link training done */
1508                         for(i=0; i<200; i++){
1509                                 sleep(5);
1510                                 if(rr(igfx, p->fdi->txctl.a) & 2)
1511                                         break;
1512                         }
1513                 }
1514         }
1515
1516         /* enable the transcoder */
1517         loadtrans(igfx, p->fdi);
1518 }
1519
1520 static void
1521 disabletrans(Igfx *igfx, Trans *t)
1522 {
1523         int i;
1524
1525         /* deselect pipe clock */
1526         csr(igfx, t->clksel.a, 7<<29, 0);
1527
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);
1538         }else
1539                 csr(igfx, t->dpctl.a, 1<<31, 3<<29);
1540
1541         /* disable transcoder / pipe */
1542         csr(igfx, t->conf.a, 1<<31, 0);
1543         for(i=0; i<100; i++){
1544                 sleep(10);
1545                 if((rr(igfx, t->conf.a) & (1<<30)) == 0)
1546                         break;
1547         }
1548         /* workarround: clear timing override bit */
1549         csr(igfx, t->chicken.a, 1<<31, 0);
1550
1551         /* disable dpll  */
1552         if(igfx->type != TypeHSW && t->dpll != nil)
1553                 csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
1554 }
1555
1556 static void
1557 disablepipe(Igfx *igfx, int x)
1558 {
1559         Pipe *p;
1560
1561         p = &igfx->pipe[x];
1562
1563         /* planes off */
1564         csr(igfx, p->dsp->cntr.a, 1<<31, 0);
1565         wr(igfx, p->dsp->surf.a, 0);    /* arm */
1566         /* cursor off */
1567         if(igfx->type == TypeHSW)
1568                 csr(igfx, p->cur->cntr.a, 0x3F, 0);
1569         else
1570                 csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
1571         wr(igfx, p->cur->base.a, 0);    /* arm */
1572
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);
1577
1578         /* disable cpu pipe */
1579         disabletrans(igfx, p);
1580
1581         /* disable panel fitter */
1582         if(p->pfit != nil)
1583                 csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
1584
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);
1588
1589         /* disable pch transcoder */
1590         disabletrans(igfx, p->fdi);
1591
1592         /* disable pch dpll enable bit */
1593         if(igfx->type != TypeHSW)
1594                 csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
1595 }
1596
1597 void
1598 checkgtt(Igfx *igfx, Mode *m)
1599 {
1600         int fd, c;
1601         ulong n;
1602         char buf[64], *fl[5];
1603         u32int i, j, pa, nilpte, *gtt;
1604
1605         if(igfx->mmio == nil)
1606                 return;
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)
1611                         break;
1612         n = m->x * m->y * m->z / 8;
1613         if(i<<12 >= n)
1614                 return;
1615
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)
1621                         break;
1622                 pa = gtt[j];
1623                 gtt[j] = nilpte;
1624         }
1625         wr(igfx, 0x2170, 0);    /* flush write buffers */
1626
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){
1630                 close(fd);
1631                 if(remove(buf) < 0)
1632                         goto err;
1633         }
1634         if((fd = create(buf, OREAD, DMDIR|0777)) < 0)
1635                 goto err;
1636         close(fd);
1637         strncat(buf, "/ctl", sizeof(buf)-strlen("/ctl"));
1638         if((fd = open(buf, ORDWR|OTRUNC)) < 0)
1639                 goto err;
1640         snprint(buf, sizeof buf, "va 0x10000000 %#lux fixed", n - (i<<12));
1641         if(write(fd, buf, strlen(buf)) < 0){
1642                 close(fd);
1643                 goto err;
1644         }
1645         seek(fd, 0, 0);
1646         if((c = read(fd, buf, sizeof buf)) <= 0){
1647                 close(fd);
1648                 goto err;
1649         }
1650         close(fd);
1651         buf[c-1] = 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");
1655                 goto err;
1656         }
1657         n >>= 12;
1658         wr(igfx, 0x2170, 0);    /* flush write buffers */
1659         for(; i<n; i++, pa+=1<<12)
1660                 gtt[i] = pa | 1;
1661         wr(igfx, 0x2170, 0);    /* flush write buffers */
1662         return;
1663 err:
1664         trace("%s: checkgtt: %r\n", igfx->ctlr->name);
1665 }
1666
1667 static void
1668 load(Vga* vga, Ctlr* ctlr)
1669 {
1670         Igfx *igfx;
1671         int x, y;
1672
1673         igfx = vga->private;
1674
1675         /* power lcd off */
1676         if(igfx->ppcontrol.a != 0){
1677                 csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
1678                 for(x=0; x<5000; x++){
1679                         sleep(10);
1680                         if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
1681                                 break;
1682                 }
1683         }
1684
1685         /* disable ports */
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 */
1695                         for(y=0; y<5; y++){
1696                                 sleep(10);
1697                                 if(rr(igfx, igfx->dp[x].bufctl.a) & 1<<7)
1698                                         break;
1699                         }
1700                 }
1701         }
1702         for(x = 0; x < nelem(igfx->hdmi); x++)
1703                 csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
1704
1705         /* disable vga plane */
1706         csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
1707
1708         /* turn off all pipes */
1709         for(x = 0; x < igfx->npipe; x++)
1710                 disablepipe(igfx, x);
1711
1712         /* check if enough memory has been mapped for requested mode */
1713         checkgtt(igfx, vga->mode);
1714
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);
1723         }
1724
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);
1729
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);
1733         }
1734
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);
1742         sleep(10);
1743
1744         /* set lvds before enabling dpll */
1745         loadreg(igfx, igfx->lvds);
1746
1747         /* new dpll setting */
1748         for(x=0; x<nelem(igfx->dpllsel); x++)
1749                 loadreg(igfx, igfx->dpllsel[x]);
1750
1751         /* program all pipes */
1752         for(x = 0; x < igfx->npipe; x++)
1753                 enablepipe(igfx, x);
1754
1755         /* program vga plane */
1756         loadreg(igfx, igfx->vgacntrl);
1757
1758         /* program ports */
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;
1768         }
1769
1770         /* program lcd power */
1771         loadreg(igfx, igfx->ppcontrol);
1772
1773         ctlr->flag |= Fload;
1774 }
1775
1776 static void
1777 dumpreg(char *name, char *item, Reg r)
1778 {
1779         if(r.a == 0)
1780                 return;
1781
1782         printitem(name, item);
1783         Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
1784 }
1785
1786 static void
1787 dumphex(char *name, char *item, uchar *data, int len)
1788 {
1789         int i;
1790
1791         for(i=0; i<len; i++){
1792                 if((i & 15) == 0){
1793                         if(i > 0)
1794                                 Bprint(&stdout, "\n");
1795                         printitem(name, item);
1796                         Bprint(&stdout, " [%.2x] =", i);
1797                 }
1798                 Bprint(&stdout, " %.2X", data[i]);
1799         }
1800         Bprint(&stdout, "\n");
1801 }
1802
1803 static void
1804 dumptiming(char *name, Trans *t)
1805 {
1806         int tu, m, n;
1807
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);
1812
1813                 m = t->dm[0].v & 0xffffff;
1814                 n = t->dn[0].v;
1815                 if(n > 0){
1816                         printitem(name, "dm1/dn1");
1817                         Bprint(&stdout, " %f\n", (double)m / (double)n);
1818                 }
1819
1820                 m = t->lm[0].v;
1821                 n = t->ln[0].v;
1822                 if(n > 0){
1823                         printitem(name, "lm1/ln1");
1824                         Bprint(&stdout, " %f\n", (double)m / (double)n);
1825                 }
1826         }
1827 }
1828
1829 static void
1830 dumptrans(char *name, Trans *t)
1831 {
1832         dumpreg(name, "conf", t->conf);
1833
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]);
1842
1843         dumptiming(name, t);
1844
1845         dumpreg(name, "ht", t->ht);
1846         dumpreg(name, "hb", t->hb);
1847         dumpreg(name, "hs", t->hs);
1848
1849         dumpreg(name, "vt", t->vt);
1850         dumpreg(name, "vb", t->vb);
1851         dumpreg(name, "vs", t->vs);
1852         dumpreg(name, "vss", t->vss);
1853
1854         dumpreg(name, "dpctl", t->dpctl);
1855         dumpreg(name, "clksel", t->clksel);
1856 }
1857
1858 static void
1859 dumppipe(Igfx *igfx, int x)
1860 {
1861         char name[32];
1862         Pipe *p;
1863
1864         p = &igfx->pipe[x];
1865
1866         snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
1867         dumpreg(name, "src", p->src);
1868         dumptrans(name, p);
1869
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]);
1877
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);
1887
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);
1892 }
1893
1894 static void
1895 dumpdpll(Igfx *igfx, int x)
1896 {
1897         int cref, m1, m2, n, p1, p2;
1898         uvlong freq;
1899         char name[32];
1900         Dpll *dpll;
1901         u32int m;
1902
1903         dpll = &igfx->dpll[x];
1904         snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
1905
1906         dumpreg(name, "ctrl", dpll->ctrl);
1907         dumpreg(name, "fp0", dpll->fp0);
1908         dumpreg(name, "fp1", dpll->fp1);
1909
1910         if(igfx->type == TypeHSW)
1911                 return;
1912
1913         p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
1914         if(((dpll->ctrl.v >> 24) & 3) == 1)
1915                 p2 >>= 1;
1916         m = (dpll->ctrl.v >> 16) & 0xFF;
1917         for(p1 = 1; p1 <= 8; p1++)
1918                 if(m & (1<<(p1-1)))
1919                         break;
1920         printitem(name, "ctrl p1");
1921         Bprint(&stdout, " %d\n", p1);
1922         printitem(name, "ctrl p2");
1923         Bprint(&stdout, " %d\n", p2);
1924
1925         n = (dpll->fp0.v >> 16) & 0x3f;
1926         m1 = (dpll->fp0.v >> 8) & 0x3f;
1927         m2 = (dpll->fp0.v >> 0) & 0x3f;
1928
1929         cref = getcref(igfx, x);
1930         freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
1931
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);
1938
1939         printitem(name, "cref");
1940         Bprint(&stdout, " %d\n", cref);
1941         printitem(name, "fp0 freq");
1942         Bprint(&stdout, " %lld\n", freq);
1943 }
1944
1945 static void
1946 dump(Vga* vga, Ctlr* ctlr)
1947 {
1948         char name[32];
1949         Igfx *igfx;
1950         int x, y;
1951
1952         if((igfx = vga->private) == nil)
1953                 return;
1954
1955         for(x=0; x<igfx->npipe; x++)
1956                 dumppipe(igfx, x);
1957
1958         for(x=0; x<nelem(igfx->dpll); x++)
1959                 dumpdpll(igfx, x);
1960
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]);
1964         }
1965
1966         dumpreg(ctlr->name, "drefctl", igfx->drefctl);
1967         dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
1968         dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
1969
1970         for(x=0; x<nelem(igfx->dp); x++){
1971                 if(igfx->dp[x].ctl.a == 0)
1972                         continue;
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]);
1981                 }
1982         }
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);
1986         }
1987
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);
1994         }
1995
1996         dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
1997         dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);
1998
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);
2003
2004         dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
2005 }
2006
2007 static int
2008 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
2009 {
2010         int t, i;
2011         u32int w;
2012
2013         if(dp->auxctl.a == 0){
2014                 werrstr("not present");
2015                 return -1;
2016         }
2017
2018         t = 0;
2019         while(rr(igfx, dp->auxctl.a) & (1<<31)){
2020                 if(++t >= 10){
2021                         werrstr("busy");
2022                         return -1;
2023                 }
2024                 sleep(5);
2025         }
2026
2027         /* clear sticky bits */
2028         wr(igfx, dp->auxctl.a, (1<<28) | (1<<25) | (1<<30));
2029
2030         for(i=0; i<nelem(dp->auxdat); i++){
2031                 w  = buf[i*4+0]<<24;
2032                 w |= buf[i*4+1]<<16;
2033                 w |= buf[i*4+2]<<8;
2034                 w |= buf[i*4+3];
2035                 wr(igfx, dp->auxdat[i].a, w);
2036         }
2037
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");
2042                 return -1;
2043         }
2044
2045         /* hack: slow down a bit */
2046         w += 2;
2047
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);
2054
2055         t = 0;
2056         for(;;){
2057                 w = rr(igfx, dp->auxctl.a);
2058                 if((w & (1<<30)) != 0)
2059                         break;
2060                 if(++t >= 10){
2061                         werrstr("busy");
2062                         return -1;
2063                 }
2064                 sleep(5);
2065         }
2066         if(w & (1<<28)){
2067                 werrstr("receive timeout");
2068                 return -1;
2069         }
2070         if(w & (1<<25)){
2071                 werrstr("receive error");
2072                 return -1;
2073         }
2074
2075         len = (w >> 20) & 0x1f;
2076         for(i=0; i<nelem(dp->auxdat); i++){
2077                 w = rr(igfx, dp->auxdat[i].a);
2078                 buf[i*4+0] = w>>24;
2079                 buf[i*4+1] = w>>16;
2080                 buf[i*4+2] = w>>8;
2081                 buf[i*4+3] = w;
2082         }
2083
2084         return len;
2085 }
2086
2087 enum {
2088         CmdNative       = 8,
2089         CmdMot          = 4,
2090         CmdRead         = 1,
2091         CmdWrite        = 0,
2092 };
2093
2094 static int
2095 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
2096 {
2097         uchar buf[20];
2098         int r;
2099
2100         assert(len <= 16);
2101
2102         memset(buf, 0, sizeof(buf));
2103         buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
2104         buf[1] = addr >> 8;
2105         buf[2] = addr;
2106         buf[3] = len-1;
2107         r = 3;  
2108         if(data != nil && len > 0){
2109                 if((cmd & CmdRead) == 0)
2110                         memmove(buf+4, data, len);
2111                 r = 4;
2112                 if((cmd & CmdRead) == 0)
2113                         r += len;
2114         }
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);
2118                 return -1;
2119         }
2120         if(r == 0 || data == nil || len == 0)
2121                 return 0;
2122         if((cmd & CmdRead) != 0){
2123                 if(--r < len)
2124                         len = r;
2125                 memmove(data, buf+1, len);
2126         }
2127         return len;
2128 }
2129
2130 static int
2131 rdpaux(Igfx *igfx, Dp *dp, int addr)
2132 {
2133         uchar buf[1];
2134         if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
2135                 return -1;
2136         return buf[0];
2137 }
2138 static int
2139 wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
2140 {
2141         if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
2142                 return -1;
2143         return 0;
2144 }
2145
2146 static int
2147 enabledp(Igfx *igfx, Dp *dp)
2148 {
2149         int try, r;
2150         u32int w;
2151
2152         if(dp->ctl.a == 0)
2153                 return 0;
2154         if((dp->ctl.v & (1<<31)) == 0)
2155                 return 0;
2156
2157         /* FIXME: always times out */
2158         if(igfx->type == TypeHSW && dp == &igfx->dp[0])
2159                 goto Skip;
2160
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);
2165
2166         r = 0;
2167
2168         /* Link training pattern 1 */
2169         dp->ctl.v &= ~(7<<8);
2170         loadreg(igfx, dp->ctl);
2171         for(try = 0;;try++){
2172                 if(try > 5)
2173                         goto Fail;
2174                 /* Link training pattern 1 */
2175                 wdpaux(igfx, dp, 0x102, 0x01);
2176                 sleep(100);
2177                 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2178                         goto Fail;
2179                 if(r & 1)       /* LANE0_CR_DONE */
2180                         break;
2181         }
2182         trace("pattern1 finished: %x\n", r);
2183
2184         /* Link training pattern 2 */
2185         dp->ctl.v &= ~(7<<8);
2186         dp->ctl.v |= 1<<8;
2187         loadreg(igfx, dp->ctl);
2188         for(try = 0;;try++){
2189                 if(try > 5)
2190                         goto Fail;
2191                 /* Link training pattern 2 */
2192                 wdpaux(igfx, dp, 0x102, 0x02);
2193                 sleep(100);
2194                 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2195                         goto Fail;
2196                 if((r & 7) == 7)
2197                         break;
2198         }
2199         trace("pattern2 finished: %x\n", r);
2200
2201         if(igfx->type == TypeHSW){
2202                 /* set link training to idle pattern and wait for 5 idle
2203                  * patterns */
2204                 dp->ctl.v &= ~(7<<8);
2205                 dp->ctl.v |= 2<<8;
2206                 loadreg(igfx, dp->ctl);
2207                 for(try=0; try<10; try++){
2208                         sleep(10);
2209                         if(rr(igfx, dp->stat.a) & (1<<25))
2210                                 break;
2211                 }
2212         }
2213 Skip:
2214         /* stop training */
2215         dp->ctl.v &= ~(7<<8);
2216         dp->ctl.v |= 3<<8;
2217         loadreg(igfx, dp->ctl);
2218         wdpaux(igfx, dp, 0x102, 0x00);
2219         return 1;
2220
2221 Fail:
2222         trace("training failed: %x\n", r);
2223
2224         /* disable port */
2225         dp->ctl.v &= ~(1<<31);
2226         loadreg(igfx, dp->ctl);
2227         wdpaux(igfx, dp, 0x102, 0x00);
2228         return -1;
2229 }
2230
2231 static uchar*
2232 edidshift(uchar buf[256])
2233 {
2234         uchar tmp[256];
2235         int i;
2236
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);
2244                         break;
2245                 }
2246         }
2247         return buf;
2248 }
2249
2250 static Edid*
2251 snarfdpedid(Igfx *igfx, Dp *dp, int addr)
2252 {
2253         uchar buf[256];
2254         int i;
2255         Edid *e;
2256
2257         for(i=0; i<sizeof(dp->dpcd); i+=16)
2258                 if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
2259                         return nil;
2260
2261         if(dp->dpcd[0] == 0)    /* nothing there, dont try to get edid */
2262                 return nil;
2263
2264         if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
2265                 return nil;
2266
2267         for(i=0; i<sizeof(buf); i+=16){
2268                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2269                         continue;
2270                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2271                         continue;
2272                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2273                         continue;
2274                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2275                         continue;
2276                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2277                         continue;
2278                 return nil;
2279         }
2280
2281         dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
2282
2283         if((e = parseedid128(edidshift(buf))) == nil)
2284                 trace("%s: snarfdpedid: dp %c: %r\n", igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]));
2285         return e;
2286 }
2287
2288 enum {
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 */
2295 };
2296         
2297 static int
2298 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
2299 {
2300         u32int x, y;
2301         int n, t;
2302
2303         if(igfx->gmbus[GMBUSCP].a == 0)
2304                 return -1;
2305
2306         wr(igfx, igfx->gmbus[GMBUSCP].a, port);
2307         wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
2308
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);
2311
2312         n = 0;
2313         while(len > 0){
2314                 x = 0;
2315                 for(t=0; t<100; t++){
2316                         x = rr(igfx, igfx->gmbus[GMBUSST].a);
2317                         if(x & (1<<11))
2318                                 break;
2319                         sleep(5);
2320                 }
2321                 if((x & (1<<11)) == 0)
2322                         return -1;
2323
2324                 t = 4 - (x & 3);
2325                 if(t > len)
2326                         t = len;
2327                 len -= t;
2328
2329                 y = rr(igfx, igfx->gmbus[GMBUSDB].a);
2330                 switch(t){
2331                 case 4:
2332                         data[n++] = y & 0xff, y >>= 8;
2333                 case 3:
2334                         data[n++] = y & 0xff, y >>= 8;
2335                 case 2:
2336                         data[n++] = y & 0xff, y >>= 8;
2337                 case 1:
2338                         data[n++] = y & 0xff;
2339                 }
2340         }
2341
2342         return n;
2343 }
2344
2345 static Edid*
2346 snarfgmedid(Igfx *igfx, int port, int addr)
2347 {
2348         uchar buf[256];
2349
2350         /* read twice */
2351         if(gmbusread(igfx, port, addr, buf, 128) != 128)
2352                 return nil;
2353         if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
2354                 return nil;
2355
2356         return parseedid128(edidshift(buf));
2357 }
2358
2359 Ctlr igfx = {
2360         "igfx",                 /* name */
2361         snarf,                  /* snarf */
2362         options,                /* options */
2363         init,                   /* init */
2364         load,                   /* load */
2365         dump,                   /* dump */
2366 };
2367
2368 Ctlr igfxhwgc = {
2369         "igfxhwgc",
2370 };