]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/igfx.c
igfx: add support for haswell graphics
[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 0x0102:    /* Dell Optiplex 790 */
375         case 0x0126:    /* Thinkpad X220 */
376                 return TypeSNB;
377         case 0x27a2:    /* GM945/82940GML - ThinkPad X60 Tablet */
378         case 0x29a2:    /* 82P965/G965 HECI desktop */
379         case 0x2a02:    /* GM965/GL960/X3100 - ThinkPad X61 Tablet */
380         case 0x2a42:    /* 4 Series Mobile - ThinkPad X200 */
381                 return TypeG45;
382         }
383         return -1;
384 }
385
386 static Edid* snarfgmedid(Igfx*, int port, int addr);
387 static Edid* snarfdpedid(Igfx*, Dp *dp, int addr);
388
389 static int enabledp(Igfx*, Dp*);
390
391 static void
392 snarf(Vga* vga, Ctlr* ctlr)
393 {
394         Igfx *igfx;
395         int x, y;
396
397         igfx = vga->private;
398         if(igfx == nil) {
399                 igfx = alloc(sizeof(Igfx));
400                 igfx->ctlr = ctlr;
401                 igfx->pci = vga->pci;
402                 if(igfx->pci == nil){
403                         error("%s: no pci device\n", ctlr->name);
404                         return;
405                 }
406                 igfx->type = devtype(igfx);
407                 if(igfx->type < 0){
408                         error("%s: unrecognized device\n", ctlr->name);
409                         return;
410                 }
411                 vgactlpci(igfx->pci);
412                 if(1){
413                         vgactlw("type", ctlr->name);
414                         igfx->mmio = segattach(0, "igfxmmio", 0, igfx->pci->mem[0].size);
415                         if(igfx->mmio == (u32int*)-1)
416                                 error("%s: attaching mmio: %r\n", ctlr->name);
417                 } else {
418                         if((igfx->pci->mem[4].bar & 1) == 0)
419                                 error("%s: no pio bar\n", ctlr->name);
420                         igfx->pio = igfx->pci->mem[4].bar & ~1;
421                 }
422                 vga->private = igfx;
423         }
424
425         switch(igfx->type){
426         case TypeG45:
427                 igfx->npipe = 2;        /* A,B */
428                 igfx->cdclk = 200;      /* MHz */
429
430                 igfx->dpll[0].ctrl      = snarfreg(igfx, 0x06014);
431                 igfx->dpll[0].fp0       = snarfreg(igfx, 0x06040);
432                 igfx->dpll[0].fp1       = snarfreg(igfx, 0x06044);
433                 igfx->dpll[1].ctrl      = snarfreg(igfx, 0x06018);
434                 igfx->dpll[1].fp0       = snarfreg(igfx, 0x06048);
435                 igfx->dpll[1].fp1       = snarfreg(igfx, 0x0604c);
436
437                 igfx->adpa              = snarfreg(igfx, 0x061100);
438                 igfx->lvds              = snarfreg(igfx, 0x061180);
439                 igfx->sdvob             = snarfreg(igfx, 0x061140);
440                 igfx->sdvoc             = snarfreg(igfx, 0x061160);
441
442                 for(x=0; x<5; x++)
443                         igfx->gmbus[x]  = snarfreg(igfx, 0x5100 + x*4);
444                 igfx->gmbus[x]  = snarfreg(igfx, 0x5120);
445
446                 igfx->pfit[0].ctrl      = snarfreg(igfx, 0x061230);
447                 y = (igfx->pfit[0].ctrl.v >> 29) & 3;
448                 if(igfx->pipe[y].pfit == nil)
449                         igfx->pipe[y].pfit = &igfx->pfit[0];
450
451                 igfx->ppstatus          = snarfreg(igfx, 0x61200);
452                 igfx->ppcontrol         = snarfreg(igfx, 0x61204);
453
454                 igfx->vgacntrl          = snarfreg(igfx, 0x071400);
455                 break;
456
457         case TypeSNB:
458                 igfx->npipe = 2;        /* A,B */
459                 igfx->cdclk = 300;      /* MHz */
460                 goto IVBcommon;
461
462         case TypeIVB:
463                 igfx->npipe = 3;        /* A,B,C */
464                 igfx->cdclk = 400;      /* MHz */
465                 goto IVBcommon;
466
467         IVBcommon:
468                 igfx->dpll[0].ctrl      = snarfreg(igfx, 0xC6014);
469                 igfx->dpll[0].fp0       = snarfreg(igfx, 0xC6040);
470                 igfx->dpll[0].fp1       = snarfreg(igfx, 0xC6044);
471                 igfx->dpll[1].ctrl      = snarfreg(igfx, 0xC6018);
472                 igfx->dpll[1].fp0       = snarfreg(igfx, 0xC6048);
473                 igfx->dpll[1].fp1       = snarfreg(igfx, 0xC604c);
474
475                 igfx->dpllsel[0]        = snarfreg(igfx, 0xC7000);
476
477                 igfx->drefctl           = snarfreg(igfx, 0xC6200);
478                 igfx->ssc4params        = snarfreg(igfx, 0xC6210);
479
480                 igfx->dp[0].ctl         = snarfreg(igfx, 0x64000);
481                 for(x=1; x<4; x++)
482                         igfx->dp[x].ctl = snarfreg(igfx, 0xE4000 + 0x100*x);
483
484                 igfx->hdmi[1].ctl       = snarfreg(igfx, 0x0E1140);     /* HDMI_CTL_B */
485                 igfx->hdmi[1].bufctl[0] = snarfreg(igfx, 0x0FC810);     /* HTMI_BUF_CTL_0 */
486                 igfx->hdmi[1].bufctl[1] = snarfreg(igfx, 0x0FC81C);     /* HTMI_BUF_CTL_1 */
487                 igfx->hdmi[1].bufctl[2] = snarfreg(igfx, 0x0FC828);     /* HTMI_BUF_CTL_2 */
488                 igfx->hdmi[1].bufctl[3] = snarfreg(igfx, 0x0FC834);     /* HTMI_BUF_CTL_3 */
489
490                 igfx->hdmi[2].ctl       = snarfreg(igfx, 0x0E1150);     /* HDMI_CTL_C */
491                 igfx->hdmi[2].bufctl[0] = snarfreg(igfx, 0x0FCC00);     /* HTMI_BUF_CTL_4 */
492                 igfx->hdmi[2].bufctl[1] = snarfreg(igfx, 0x0FCC0C);     /* HTMI_BUF_CTL_5 */
493                 igfx->hdmi[2].bufctl[2] = snarfreg(igfx, 0x0FCC18);     /* HTMI_BUF_CTL_6 */
494                 igfx->hdmi[2].bufctl[3] = snarfreg(igfx, 0x0FCC24);     /* HTMI_BUF_CTL_7 */
495
496                 igfx->hdmi[3].ctl       = snarfreg(igfx, 0x0E1160);     /* HDMI_CTL_D */
497                 igfx->hdmi[3].bufctl[0] = snarfreg(igfx, 0x0FD000);     /* HTMI_BUF_CTL_8 */
498                 igfx->hdmi[3].bufctl[1] = snarfreg(igfx, 0x0FD00C);     /* HTMI_BUF_CTL_9 */
499                 igfx->hdmi[3].bufctl[2] = snarfreg(igfx, 0x0FD018);     /* HTMI_BUF_CTL_10 */
500                 igfx->hdmi[3].bufctl[3] = snarfreg(igfx, 0x0FD024);     /* HTMI_BUF_CTL_11 */
501
502                 igfx->lvds              = snarfreg(igfx, 0x0E1180);     /* LVDS_CTL */
503                 goto PCHcommon;
504
505         case TypeHSW:
506                 igfx->npipe = 4;        /* A,B,C,eDP */
507                 igfx->cdclk = igfx->isult ? 450 : 540;  /* MHz */
508
509                 igfx->dpll[0].ctrl      = snarfreg(igfx, 0x130040);     /* LCPLL_CTL */
510                 igfx->dpll[1].ctrl      = snarfreg(igfx, 0x46040);      /* WRPLL_CTL1 */
511                 igfx->dpll[2].ctrl      = snarfreg(igfx, 0x46060);      /* WRPLL_CTL2 */
512                 igfx->dpll[3].ctrl      = snarfreg(igfx, 0x46020);      /* SPLL_CTL */
513
514                 for(x=0; x<nelem(igfx->dp); x++){
515                         if(x == 3 && igfx->isult)       /* no DDI D */
516                                 continue;
517                         igfx->dp[x].bufctl      = snarfreg(igfx, 0x64000 + 0x100*x);
518                         igfx->dp[x].ctl         = snarfreg(igfx, 0x64040 + 0x100*x);
519                         if(x > 0)
520                                 igfx->dp[x].stat        = snarfreg(igfx, 0x64044 + 0x100*x);
521                         for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
522                                 igfx->dp[x].buftrans[y] = snarfreg(igfx, 0x64E00 + 0x60*x + 4*y);
523                         igfx->dpllsel[x]        = snarfreg(igfx, 0x46100 + 4*x);
524                 }
525
526                 goto PCHcommon;
527
528         PCHcommon:
529                 igfx->rawclkfreq        = snarfreg(igfx, 0xC6204);
530
531                 /* cpu displayport A */
532                 igfx->dp[0].auxctl      = snarfreg(igfx, 0x64010);
533                 igfx->dp[0].auxdat[0]   = snarfreg(igfx, 0x64014);
534                 igfx->dp[0].auxdat[1]   = snarfreg(igfx, 0x64018);
535                 igfx->dp[0].auxdat[2]   = snarfreg(igfx, 0x6401C);
536                 igfx->dp[0].auxdat[3]   = snarfreg(igfx, 0x64020);
537                 igfx->dp[0].auxdat[4]   = snarfreg(igfx, 0x64024);
538
539                 /* pch displayport B,C,D */
540                 for(x=1; x<4; x++){
541                         igfx->dp[x].auxctl      = snarfreg(igfx, 0xE4010 + 0x100*x);
542                         igfx->dp[x].auxdat[0]   = snarfreg(igfx, 0xE4014 + 0x100*x);
543                         igfx->dp[x].auxdat[1]   = snarfreg(igfx, 0xE4018 + 0x100*x);
544                         igfx->dp[x].auxdat[2]   = snarfreg(igfx, 0xE401C + 0x100*x);
545                         igfx->dp[x].auxdat[3]   = snarfreg(igfx, 0xE4020 + 0x100*x);
546                         igfx->dp[x].auxdat[4]   = snarfreg(igfx, 0xE4024 + 0x100*x);
547                 }
548
549                 for(x=0; x<igfx->npipe; x++){
550                         if(igfx->type == TypeHSW && x == 3){
551                                 igfx->pipe[x].pfit = &igfx->pfit[0];
552                                 continue;
553                         }
554                         igfx->pfit[x].pwrgate   = snarfreg(igfx, 0x68060 + 0x800*x);
555                         igfx->pfit[x].winpos    = snarfreg(igfx, 0x68070 + 0x800*x);
556                         igfx->pfit[x].winsize   = snarfreg(igfx, 0x68074 + 0x800*x);
557                         igfx->pfit[x].ctrl      = snarfreg(igfx, 0x68080 + 0x800*x);
558
559                         y = (igfx->pfit[x].ctrl.v >> 29) & 3;
560                         if(igfx->pipe[y].pfit == nil)
561                                 igfx->pipe[y].pfit = &igfx->pfit[x];
562                 }
563
564                 igfx->ppstatus          = snarfreg(igfx, 0xC7200);
565                 igfx->ppcontrol         = snarfreg(igfx, 0xC7204);
566
567                 for(x=0; x<5; x++)
568                         igfx->gmbus[x]  = snarfreg(igfx, 0xC5100 + x*4);
569                 igfx->gmbus[x]  = snarfreg(igfx, 0xC5120);
570
571                 igfx->adpa              = snarfreg(igfx, 0x0E1100);     /* DAC_CTL */
572                 igfx->vgacntrl          = snarfreg(igfx, 0x041000);
573                 break;
574         }
575
576         for(x=0; x<igfx->npipe; x++)
577                 snarfpipe(igfx, x);
578
579         for(x=0; x<nelem(vga->edid); x++){
580                 Modelist *l;
581
582                 switch(x){
583                 case PortVGA:
584                         vga->edid[x] = snarfgmedid(igfx, 2, 0x50);
585                         break;
586                 case PortLCD:
587                         vga->edid[x] = snarfgmedid(igfx, 3, 0x50);
588                         if(vga->edid[x] == nil)
589                                 continue;
590                         for(l = vga->edid[x]->modelist; l != nil; l = l->next)
591                                 l->attr = mkattr(l->attr, "lcd", "1");
592                         break;
593                 case PortDPD:
594                         if(igfx->type == TypeHSW && igfx->isult)
595                                 continue;
596                 case PortDPA:
597                 case PortDPB:
598                 case PortDPC:
599                         vga->edid[x] = snarfdpedid(igfx, &igfx->dp[x-PortDPA], 0x50);
600                         break;
601                 default:
602                         continue;
603                 }
604
605                 if(vga->edid[x] == nil){
606                         if(x < PortDPB)
607                                 continue;
608                         vga->edid[x] = snarfgmedid(igfx, x + 1 & ~1 | x >> 1 & 1, 0x50);
609                         if(vga->edid[x] == nil)
610                                 continue;
611                         igfx->dp[x-PortDPA].hdmi = 1;
612                 }
613                 for(l = vga->edid[x]->modelist; l != nil; l = l->next)
614                         l->attr = mkattr(l->attr, "display", "%d", x+1);
615         }
616
617         ctlr->flag |= Fsnarf;
618 }
619
620 static void
621 options(Vga* vga, Ctlr* ctlr)
622 {
623         USED(vga);
624         ctlr->flag |= Hlinear|Ulinear|Foptions;
625 }
626
627 enum {
628         Lcpll = 2700,
629         Lcpll2k = Lcpll * 2000,
630 };
631
632 static int
633 wrbudget(int freq)
634 {
635         static int b[] = {
636                 25175000,0, 25200000,0, 27000000,0, 27027000,0,
637                 37762500,0, 37800000,0, 40500000,0, 40541000,0,
638                 54000000,0, 54054000,0, 59341000,0, 59400000,0,
639                 72000000,0, 74176000,0, 74250000,0, 81000000,0,
640                 81081000,0, 89012000,0, 89100000,0, 108000000,0,
641                 108108000,0, 111264000,0, 111375000,0, 148352000,0,
642                 148500000,0, 162000000,0, 162162000,0, 222525000,0,
643                 222750000,0, 296703000,0, 297000000,0, 233500000,1500,
644                 245250000,1500, 247750000,1500, 253250000,1500, 298000000,1500,
645                 169128000,2000, 169500000,2000, 179500000,2000, 202000000,2000,
646                 256250000,4000, 262500000,4000, 270000000,4000, 272500000,4000,
647                 273750000,4000, 280750000,4000, 281250000,4000, 286000000,4000,
648                 291750000,4000, 267250000,5000, 268500000,5000
649         };
650         int *i;
651
652         for(i=b; i<b+nelem(b); i+=2)
653                 if(i[0] == freq)
654                         return i[1];
655         return 1000;
656 }
657
658 static void
659 genwrpll(int freq, int *n2, int *p, int *r2)
660 {
661         int budget, N2, P, R2;
662         vlong f2k, a, b, c, d, Î”, bestΔ;
663
664         f2k = freq / 100;
665         if(f2k == Lcpll2k){     /* bypass wrpll entirely and use lcpll */
666                 *n2 = 2;
667                 *p = 1;
668                 *r2 = 2;
669                 return;
670         }
671         budget = wrbudget(freq);
672         *p = 0;
673         for(R2=Lcpll*2/400+1; R2<=Lcpll*2/48; R2++)
674         for(N2=2400*R2/Lcpll+1; N2<=4800*R2/Lcpll; N2++)
675                 for(P=2; P<=64; P+=2){
676                         if(*p == 0){
677                                 *n2 = N2;
678                                 *p = P;
679                                 *r2 = R2;
680                                 continue;
681                         }
682                         Î” = f2k * P * R2;
683                         Î” -= N2 * Lcpll2k;
684                         if(Δ < 0)
685                                 Î” = -Δ;
686                         bestΔ = f2k * *p * *r2;
687                         bestΔ -= *n2 * Lcpll2k;
688                         if(bestΔ < 0)
689                                 bestΔ = -bestΔ;
690                         a = f2k * budget;
691                         b = a;
692                         a *= P * R2;
693                         b *= *p * *r2;
694                         c = Î” * MHz;
695                         d = bestΔ * MHz;
696                         if(a < c && b < d && *p * *r2 * Î” < P * R2 * bestΔ
697                         || a >= c && b < d
698                         || a >= c && b >= d && N2 * *r2 * *r2 > *n2 * R2 * R2){
699                                 *n2 = N2;
700                                 *p = P;
701                                 *r2 = R2;
702                         }
703                 }
704 }
705
706 static int
707 genpll(int freq, int cref, int P2, int *m1, int *m2, int *n, int *p1)
708 {
709         int M1, M2, M, N, P, P1;
710         int best, error;
711         vlong a;
712
713         best = -1;
714         for(N=3; N<=8; N++)
715         for(M2=5; M2<=9; M2++)
716 //      for(M1=10; M1<=20; M1++){
717         for(M1=12; M1<=22; M1++){
718                 M = 5*(M1+2) + (M2+2);
719                 if(M < 79 || M > 127)
720 //              if(M < 70 || M > 120)
721                         continue;
722                 for(P1=1; P1<=8; P1++){
723                         P = P1 * P2;
724                         if(P < 5 || P > 98)
725 //                      if(P < 4 || P > 98)
726                                 continue;
727                         a = cref;
728                         a *= M;
729                         a /= N+2;
730                         a /= P;
731                         if(a < 20*MHz || a > 400*MHz)
732                                 continue;
733                         error = a;
734                         error -= freq;
735                         if(error < 0)
736                                 error = -error;
737                         if(best < 0 || error < best){
738                                 best = error;
739                                 *m1 = M1;
740                                 *m2 = M2;
741                                 *n = N;
742                                 *p1 = P1;
743                         }
744                 }
745         }
746         return best;
747 }
748
749 static int
750 getcref(Igfx *igfx, int x)
751 {
752         Dpll *dpll;
753
754         dpll = &igfx->dpll[x];
755         if(igfx->type == TypeG45){
756                 if(((dpll->ctrl.v >> 13) & 3) == 3)
757                         return 100*MHz;
758                 return 96*MHz;
759         }
760         return 120*MHz;
761 }
762
763 static int
764 initdpll(Igfx *igfx, int x, int freq, int port)
765 {
766         int cref, m1, m2, n, n2, p1, p2, r2;
767         Dpll *dpll;
768
769         switch(igfx->type){
770         case TypeG45:
771                 /* PLL Reference Input Select */
772                 dpll = igfx->pipe[x].dpll;
773                 dpll->ctrl.v &= ~(3<<13);
774                 dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
775                 break;
776         case TypeSNB:
777         case TypeIVB:
778                 /* transcoder dpll enable */
779                 igfx->dpllsel[0].v |= 8<<(x*4);
780                 /* program rawclock to 125MHz */
781                 igfx->rawclkfreq.v = 125;
782
783                 igfx->drefctl.v &= ~(3<<13);
784                 igfx->drefctl.v &= ~(3<<11);
785                 igfx->drefctl.v &= ~(3<<9);
786                 igfx->drefctl.v &= ~(3<<7);
787                 igfx->drefctl.v &= ~3;
788
789                 if(port == PortLCD){
790                         igfx->drefctl.v |= 2<<11;
791                         igfx->drefctl.v |= 1;
792                 } else {
793                         igfx->drefctl.v |= 2<<9;
794                 }
795
796                 /*
797                  * PLL Reference Input Select:
798                  * 000  DREFCLK         (default is 120 MHz) for DAC/HDMI/DVI/DP
799                  * 001  Super SSC       120MHz super-spread clock
800                  * 011  SSC             Spread spectrum input clock (120MHz default) for LVDS/DP
801                  */
802                 dpll = igfx->pipe[x].fdi->dpll;
803                 dpll->ctrl.v &= ~(7<<13);
804                 dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
805                 break;
806         case TypeHSW:
807                 /* select port clock to pipe */
808                 igfx->pipe[x].clksel.v = port+1-PortDPA<<29;
809
810                 if(igfx->dp[port-PortDPA].hdmi){
811                         /* select port clock */
812                         igfx->dpllsel[port-PortDPA].v = 1<<31;  /* WRPLL1 */
813                         igfx->pipe[x].dpll = &igfx->dpll[1];
814
815                         dpll = igfx->pipe[x].dpll;
816                         /* enable pll */
817                         dpll->ctrl.v = 1<<31;
818                         /* LCPLL 2700 (non scc) reference */
819                         dpll->ctrl.v |= 3<<28;
820
821                         genwrpll(freq, &n2, &p1, &r2);
822                         dpll->ctrl.v |= n2 << 16;
823                         dpll->ctrl.v |= p1 << 8;
824                         dpll->ctrl.v |= r2;
825                 }else{
826                         /* select port clock */
827                         igfx->dpllsel[port-PortDPA].v = 1<<29;  /* LCPLL 1350 */
828                         /* keep preconfigured frequency settings, keep cdclk */
829                         dpll = igfx->pipe[x].dpll;
830                         dpll->ctrl.v &= ~(1<<31) & ~(1<<28) & ~(1<<26);
831                 }
832                 return 0;
833         default:
834                 return -1;
835         }
836         cref = getcref(igfx, x);
837
838         /* Dpll Mode select */
839         dpll->ctrl.v &= ~(3<<26);
840         dpll->ctrl.v |= (port == PortLCD ? 2 : 1)<<26;
841
842         /* P2 Clock Divide */
843         dpll->ctrl.v &= ~(3<<24);
844         if(port == PortLCD){
845                 p2 = 14;
846                 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
847                         return -1;
848         } else {
849                 /* generate 270MHz clock for displayport */
850                 if(port >= PortDPA)
851                         freq = 270*MHz;
852
853                 p2 = 10;
854                 if(freq > 270*MHz){
855                         p2 >>= 1;
856                         dpll->ctrl.v |= (1<<24);
857                 }
858                 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
859                         return -1;
860         }
861
862         /* Dpll VCO Enable */
863         dpll->ctrl.v |= (1<<31);
864
865         /* Dpll Serial DVO High Speed IO clock Enable */
866         if(port >= PortDPA)
867                 dpll->ctrl.v |= (1<<30);
868         else
869                 dpll->ctrl.v &= ~(1<<30);
870
871         /* VGA Mode Disable */
872         dpll->ctrl.v |= (1<<28);
873
874         dpll->fp0.v &= ~(0x3f<<16);
875         dpll->fp0.v |= n << 16;
876         dpll->fp0.v &= ~(0x3f<<8);
877         dpll->fp0.v |= m1 << 8;
878         dpll->fp0.v &= ~(0x3f<<0);
879         dpll->fp0.v |= m2 << 0;
880
881         /* FP0 P1 Post Divisor */
882         dpll->ctrl.v &= ~0xFF0000;
883         dpll->ctrl.v |=  0x010000<<(p1-1);
884
885         /* FP1 P1 Post divisor */
886         if(igfx->pci->did != 0x27a2){
887                 dpll->ctrl.v &= ~0xFF;
888                 dpll->ctrl.v |=  0x01<<(p1-1);
889                 dpll->fp1.v = dpll->fp0.v;
890         }
891
892         return 0;
893 }
894
895 static int
896 needlanes(int freq, int lsclk, int bpp)
897 {
898         vlong v;
899         int n;
900
901         v = ((vlong)freq * bpp) / 8;
902         for(n=1; n<4 && v>lsclk; n<<=1, v>>=1)
903                 ;
904         return n;
905 }
906
907 static void
908 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
909 {
910         u32int m, n;
911
912         n = 0x800000;
913         m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
914
915         t->dm[0].v = (tu-1)<<25 | m;
916         t->dn[0].v = n;
917
918         n = 0x80000;
919         m = ((uvlong)n * freq) / lsclk;
920
921         t->lm[0].v = m;
922         t->ln[0].v = n;
923
924         t->dm[1].v = t->dm[0].v;
925         t->dn[1].v = t->dn[0].v;
926         t->lm[1].v = t->lm[0].v;
927         t->ln[1].v = t->ln[0].v;
928 }
929
930 static void
931 inittrans(Trans *t, Mode *m)
932 {
933         /* clear all but 27:28 frame start delay (initialized by bios) */
934         t->conf.v &= 3<<27;
935
936         /* tans/pipe enable */
937         t->conf.v |= 1<<31;
938
939         /* trans/pipe timing */
940         t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
941         t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);
942         t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
943         t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
944
945         t->hb.v = t->ht.v;
946         t->vb.v = t->vt.v;
947
948         t->vss.v = 0;
949 }
950
951 static void
952 initpipe(Igfx *igfx, Pipe *p, Mode *m, int bpc, int port)
953 {
954         static uchar bpctab[4] = { 8, 10, 6, 12 };
955         int i, tu, lanes;
956         Fdi *fdi;
957
958         /* source image size */
959         p->src.v = (m->x - 1)<<16 | (m->y - 1);
960
961         if(p->pfit != nil){
962                 /* panel fitter off */
963                 p->pfit->ctrl.v &= ~(1<<31);
964                 p->pfit->winpos.v = 0;
965                 p->pfit->winsize.v = 0;
966         }
967
968         /* enable and set monitor timings for cpu pipe */
969         inittrans(p, m);
970
971         /* default for displayport */
972         lanes = needlanes(m->frequency, 270*MHz, 3*bpc);
973         tu = 64;
974
975         fdi = p->fdi;
976         if(fdi->rxctl.a != 0){
977                 /* enable and set monitor timings for transcoder */
978                 inittrans(fdi, m);
979
980                 /* tx port width selection */
981                 fdi->txctl.v &= ~(7<<19);
982                 fdi->txctl.v |= (lanes-1)<<19;
983
984                 /* rx port width selection */
985                 fdi->rxctl.v &= ~(7<<19);
986                 fdi->rxctl.v |= (lanes-1)<<19;
987                 /* bits per color for transcoder */
988                 for(i=0; i<nelem(bpctab); i++){
989                         if(bpctab[i] == bpc){
990                                 fdi->rxctl.v &= ~(7<<16);
991                                 fdi->rxctl.v |= i<<16;
992                                 fdi->dpctl.v &= ~(7<<9);
993                                 fdi->dpctl.v |= i<<9;
994                                 break;
995                         }
996                 }
997
998                 /* enhanced framing on */
999                 fdi->rxctl.v |= (1<<6);
1000                 fdi->txctl.v |= (1<<18);
1001
1002                 /* tusize 1 and 2 */
1003                 fdi->rxtu[0].v = (tu-1)<<25;
1004                 fdi->rxtu[1].v = (tu-1)<<25;
1005                 initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1006         }else if(igfx->type == TypeHSW){
1007                 p->dpctl.v &= 0xf773733e;       /* mbz */
1008                 /* transcoder enable */
1009                 p->dpctl.v |= 1<<31;
1010                 /* DDI select (ignored by eDP) */
1011                 p->dpctl.v &= ~(7<<28);
1012                 p->dpctl.v |= (port-PortDPA)<<28;
1013                 /* displayport SST or hdmi mode */
1014                 p->dpctl.v &= ~(7<<24);
1015                 if(!igfx->dp[port-PortDPA].hdmi)
1016                         p->dpctl.v |= 2<<24;
1017                 /* sync polarity */
1018                 p->dpctl.v |= 3<<16;
1019                 if(m->hsync == '-')
1020                         p->dpctl.v ^= 1<<16;
1021                 if(m->vsync == '-')
1022                         p->dpctl.v ^= 1<<17;
1023                 /* eDP input select: always on power well */
1024                 p->dpctl.v &= ~(7<<12);
1025                 /* dp port width */
1026                 if(igfx->dp[port-PortDPA].hdmi)
1027                         lanes = 4;
1028                 else{
1029                         p->dpctl.v &= ~(7<<1);
1030                         p->dpctl.v |= lanes-1 << 1;
1031                 }
1032         }
1033
1034         /* bits per color for cpu pipe */
1035         for(i=0; i<nelem(bpctab); i++){
1036                 if(bpctab[i] == bpc){
1037                         if(igfx->type == TypeHSW){
1038                                 p->dpctl.v &= ~(7<<20);
1039                                 p->dpctl.v |= i<<20;
1040                         }else{
1041                                 p->conf.v &= ~(7<<5);
1042                                 p->conf.v |= i<<5;
1043                         }
1044                         break;
1045                 }
1046         }
1047         initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1048 }
1049
1050 static void
1051 init(Vga* vga, Ctlr* ctlr)
1052 {
1053         int x, nl, port, bpc;
1054         char *val;
1055         Igfx *igfx;
1056         Pipe *p;
1057         Mode *m;
1058         Reg *r;
1059
1060         m = vga->mode;
1061         if(m->z != 32)
1062                 error("%s: unsupported color depth %d\n", ctlr->name, m->z);
1063
1064         bpc = 8;        /* bits per color channel */
1065
1066         igfx = vga->private;
1067
1068         /* disable vga */
1069         igfx->vgacntrl.v |= (1<<31);
1070
1071         /* disable all pipes and ports */
1072         igfx->ppcontrol.v &= 10;        /* 15:4 mbz; unset 5<<0 */
1073         igfx->lvds.v &= ~(1<<31);
1074         igfx->adpa.v &= ~(1<<31);
1075         if(igfx->type == TypeG45)
1076                 igfx->adpa.v |= (3<<10);        /* Monitor DPMS: off */
1077         if(igfx->type == TypeHSW){
1078                 for(x=1; x<nelem(igfx->dpll); x++)
1079                         igfx->dpll[x].ctrl.v &= ~(1<<31);
1080                 for(x=0; x<nelem(igfx->dpllsel); x++)
1081                         igfx->dpllsel[x].v = 7<<29;
1082         }
1083         for(x=0; x<nelem(igfx->dp); x++){
1084                 igfx->dp[x].ctl.v &= ~(1<<31);
1085                 igfx->dp[x].bufctl.v &= ~(1<<31);
1086         }
1087         for(x=0; x<nelem(igfx->hdmi); x++)
1088                 igfx->hdmi[x].ctl.v &= ~(1<<31);
1089         for(x=0; x<igfx->npipe; x++){
1090                 /* disable displayport transcoders */
1091                 igfx->pipe[x].dpctl.v &= ~(1<<31);
1092                 igfx->pipe[x].fdi->dpctl.v &= ~(1<<31);
1093                 if(igfx->type == TypeHSW){
1094                         igfx->pipe[x].dpctl.v &= ~(7<<28);
1095                         igfx->pipe[x].fdi->dpctl.v &= ~(7<<28);
1096                 }else{
1097                         igfx->pipe[x].dpctl.v |= (3<<29);
1098                         igfx->pipe[x].fdi->dpctl.v |= (3<<29);
1099                 }
1100                 /* disable transcoder/pipe */
1101                 igfx->pipe[x].conf.v &= ~(1<<31);
1102                 igfx->pipe[x].fdi->conf.v &= ~(1<<31);
1103         }
1104
1105         if((val = dbattr(m->attr, "display")) != nil){
1106                 port = atoi(val)-1;
1107                 if(igfx->type == TypeHSW && !igfx->dp[port-PortDPA].hdmi)
1108                         bpc = 6;
1109         }else if(dbattr(m->attr, "lcd") != nil)
1110                 port = PortLCD;
1111         else
1112                 port = PortVGA;
1113
1114         trace("%s: display #%d\n", ctlr->name, port+1);
1115
1116         switch(port){
1117         default:
1118         Badport:
1119                 error("%s: display #%d not supported\n", ctlr->name, port+1);
1120                 break;
1121
1122         case PortVGA:
1123                 if(igfx->type == TypeHSW)       /* unimplemented */
1124                         goto Badport;
1125                 if(igfx->type == TypeG45)
1126                         x = (igfx->adpa.v >> 30) & 1;
1127                 else
1128                         x = (igfx->adpa.v >> 29) & 3;
1129                 igfx->adpa.v |= (1<<31);
1130                 if(igfx->type == TypeG45){
1131                         igfx->adpa.v &= ~(3<<10);       /* Monitor DPMS: on */
1132
1133                         igfx->adpa.v &= ~(1<<15);       /* ADPA Polarity Select */
1134                         igfx->adpa.v |= 3<<3;
1135                         if(m->hsync == '-')
1136                                 igfx->adpa.v ^= 1<<3;
1137                         if(m->vsync == '-')
1138                                 igfx->adpa.v ^= 1<<4;
1139                 }
1140                 break;
1141
1142         case PortLCD:
1143                 if(igfx->type == TypeHSW)
1144                         goto Badport;
1145                 if(igfx->type == TypeG45)
1146                         x = (igfx->lvds.v >> 30) & 1;
1147                 else
1148                         x = (igfx->lvds.v >> 29) & 3;
1149                 igfx->lvds.v |= (1<<31);
1150                 igfx->ppcontrol.v |= 5;
1151
1152                 if(igfx->type == TypeG45){
1153                         igfx->lvds.v &= ~(1<<24);       /* data format select 18/24bpc */
1154
1155                         igfx->lvds.v &= ~(3<<20);
1156                         if(m->hsync == '-')
1157                                 igfx->lvds.v ^= 1<<20;
1158                         if(m->vsync == '-')
1159                                 igfx->lvds.v ^= 1<<21;
1160
1161                         igfx->lvds.v |= (1<<15);        /* border enable */
1162                 }
1163                 break;
1164
1165         case PortDPA:
1166         case PortDPB:
1167         case PortDPC:
1168         case PortDPD:
1169         case PortDPE:
1170                 r = &igfx->dp[port - PortDPA].ctl;
1171                 if(r->a == 0)
1172                         goto Badport;
1173                 /* port enable */
1174                 r->v |= 1<<31;
1175                 /* use PIPE_A for displayport */
1176                 x = 0;
1177
1178                 if(igfx->type == TypeHSW){
1179                         if(port == PortDPA){
1180                                 /* only enable panel for eDP */
1181                                 igfx->ppcontrol.v |= 5;
1182                                 /* use eDP pipe */
1183                                 x = 3;
1184                         }
1185
1186                         /* reserved MBZ */
1187                         r->v &= ~(7<<28) & ~(1<<26) & ~(63<<19) & ~(3<<16) & ~(15<<11) & ~(1<<7) & ~31;
1188                         /* displayport SST mode */
1189                         r->v &= ~(1<<27);
1190                         /* link not in training, send normal pixels */
1191                         r->v |= 3<<8;
1192                         if(igfx->dp[port-PortDPA].hdmi){
1193                                 /* hdmi: do not configure displayport */
1194                                 r->a = 0;
1195                                 r->v &= ~(1<<31);
1196                         }
1197
1198                         r = &igfx->dp[port - PortDPA].bufctl;
1199                         /* buffer enable */
1200                         r->v |= 1<<31;
1201                         /* reserved MBZ */
1202                         r->v &= ~(7<<28) & ~(127<<17) & ~(255<<8) & ~(3<<5);
1203                         /* grab lanes shared with port e when using port a */
1204                         if(port == PortDPA)
1205                                 r->v |= 1<<4;
1206                         else if(port == PortDPE)
1207                                 igfx->dp[0].bufctl.v &= ~(1<<4);
1208                         /* dp port width */
1209                         r->v &= ~(15<<1);
1210                         if(!igfx->dp[port-PortDPA].hdmi){
1211                                 nl = needlanes(m->frequency, 270*MHz, 3*bpc);
1212                                 /* x4 unsupported on port e */
1213                                 if(nl > 2 && port == PortDPE)
1214                                         goto Badport;
1215                                 r->v |= nl-1 << 1;
1216                         }
1217                         /* port reversal: off */
1218                         r->v &= ~(1<<16);
1219
1220                         /* buffer translation (vsl/pel) */
1221                         r = igfx->dp[port - PortDPA].buftrans;
1222                         r[1].v  = 0x0006000E;   r[0].v  = 0x00FFFFFF;
1223                         r[3].v  = 0x0005000A;   r[2].v  = 0x00D75FFF;
1224                         r[5].v  = 0x00040006;   r[4].v  = 0x00C30FFF;
1225                         r[7].v  = 0x000B0000;   r[6].v  = 0x80AAAFFF;
1226                         r[9].v  = 0x0005000A;   r[8].v  = 0x00FFFFFF;
1227                         r[11].v = 0x000C0004;   r[10].v = 0x00D75FFF;
1228                         r[13].v = 0x000B0000;   r[12].v = 0x80C30FFF;
1229                         r[15].v = 0x00040006;   r[14].v = 0x00FFFFFF;
1230                         r[17].v = 0x000B0000;   r[16].v = 0x80D75FFF;
1231                         r[19].v = 0x00040006;   r[18].v = 0x00FFFFFF;
1232                         break;
1233                 }
1234
1235                 if(port == PortDPE)
1236                         goto Badport;
1237
1238                 /* port width selection */
1239                 r->v &= ~(7<<19);
1240                 r->v |= needlanes(m->frequency, 270*MHz, 3*bpc)-1 << 19;
1241
1242                 /* port reversal: off */
1243                 r->v &= ~(1<<15);
1244                 /* reserved MBZ */
1245                 r->v &= ~(15<<11);
1246                 /* displayport transcoder */
1247                 if(port == PortDPA){
1248                         /* reserved MBZ */
1249                         r->v &= ~(15<<10);
1250                         /* pll frequency: 270mhz */
1251                         r->v &= ~(3<<16);
1252                         /* pll enable */
1253                         r->v |= 1<<14;
1254                         /* pipe select */
1255                         r->v &= ~(3<<29);
1256                         r->v |= x<<29;
1257                 } else if(igfx->pipe[x].fdi->dpctl.a != 0){
1258                         /* reserved MBZ */
1259                         r->v &= ~(15<<11);
1260                         /* audio output: disable */
1261                         r->v &= ~(1<<6);
1262                         /* transcoder displayport configuration */
1263                         r = &igfx->pipe[x].fdi->dpctl;
1264                         /* transcoder enable */
1265                         r->v |= 1<<31;
1266                         /* port select: B,C,D */
1267                         r->v &= ~(3<<29);
1268                         r->v |= (port-PortDPB)<<29;
1269                 }
1270                 /* sync polarity */
1271                 r->v |= 3<<3;
1272                 if(m->hsync == '-')
1273                         r->v ^= 1<<3;
1274                 if(m->vsync == '-')
1275                         r->v ^= 1<<4;
1276                 break;
1277         }
1278         p = &igfx->pipe[x];
1279
1280         /* plane enable, 32bpp */
1281         p->dsp->cntr.v = (1<<31) | (6<<26);
1282         if(igfx->type == TypeG45)
1283                 p->dsp->cntr.v |= x<<24;        /* pipe assign */
1284         else
1285                 p->dsp->cntr.v &= ~511; /* mbz */
1286
1287         /* stride must be 64 byte aligned */
1288         p->dsp->stride.v = m->x * (m->z / 8);
1289         p->dsp->stride.v += 63;
1290         p->dsp->stride.v &= ~63;
1291
1292         /* virtual width in pixels */
1293         vga->virtx = p->dsp->stride.v / (m->z / 8);
1294
1295         /* plane position and size */
1296         p->dsp->pos.v = 0;
1297         p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1);   /* sic */
1298
1299         p->dsp->surf.v = 0;
1300         p->dsp->linoff.v = 0;
1301         p->dsp->tileoff.v = 0;
1302         p->dsp->leftsurf.v = 0;
1303
1304         /* cursor plane off */
1305         p->cur->cntr.v = 0;
1306         if(igfx->type == TypeG45)
1307                 p->cur->cntr.v |= x<<28;        /* pipe assign */
1308         p->cur->pos.v = 0;
1309         p->cur->base.v = 0;
1310
1311         if(initdpll(igfx, x, m->frequency, port) < 0)
1312                 error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
1313
1314         initpipe(igfx, p, m, bpc, port);
1315
1316         ctlr->flag |= Finit;
1317 }
1318
1319 static void
1320 loadtrans(Igfx *igfx, Trans *t)
1321 {
1322         int i;
1323
1324         if(t->conf.a == 0)
1325                 return;
1326
1327         /* program trans/pipe timings */
1328         loadreg(igfx, t->ht);
1329         loadreg(igfx, t->hb);
1330         loadreg(igfx, t->hs);
1331         loadreg(igfx, t->vt);
1332         loadreg(igfx, t->vb);
1333         loadreg(igfx, t->vs);
1334         loadreg(igfx, t->vss);
1335
1336         loadreg(igfx, t->dm[0]);
1337         loadreg(igfx, t->dn[0]);
1338         loadreg(igfx, t->lm[0]);
1339         loadreg(igfx, t->ln[0]);
1340         loadreg(igfx, t->dm[1]);
1341         loadreg(igfx, t->dn[1]);
1342         loadreg(igfx, t->lm[1]);
1343         loadreg(igfx, t->ln[1]);
1344
1345         if(t->dpll != nil && igfx->type != TypeHSW){
1346                 /* program dpll */
1347                 t->dpll->ctrl.v &= ~(1<<31);
1348                 loadreg(igfx, t->dpll->ctrl);
1349                 loadreg(igfx, t->dpll->fp0);
1350                 loadreg(igfx, t->dpll->fp1);
1351
1352                 /* enable dpll */
1353                 t->dpll->ctrl.v |= (1<<31);
1354                 loadreg(igfx, t->dpll->ctrl);
1355                 sleep(10);
1356         }
1357
1358         /* workarround: set timing override bit */
1359         csr(igfx, t->chicken.a, 0, 1<<31);
1360
1361         /* enable displayport transcoder */
1362         loadreg(igfx, t->dpctl);
1363
1364         /* enable trans/pipe */
1365         t->conf.v |= (1<<31);
1366         t->conf.v &= ~(1<<30);
1367         loadreg(igfx, t->conf);
1368         for(i=0; i<100; i++){
1369                 sleep(10);
1370                 if(rr(igfx, t->conf.a) & (1<<30))
1371                         break;
1372         }
1373 }
1374
1375 static void
1376 enablepipe(Igfx *igfx, int x)
1377 {
1378         int i;
1379         Pipe *p;
1380
1381         p = &igfx->pipe[x];
1382         if((p->conf.v & (1<<31)) == 0)
1383                 return; /* pipe is disabled, done */
1384
1385         /* select pipe clock */
1386         loadreg(igfx, p->clksel);
1387
1388         if(p->fdi->rxctl.a != 0){
1389                 p->fdi->rxctl.v &= ~(1<<31);
1390                 p->fdi->rxctl.v &= ~(1<<4);     /* rawclk */
1391                 p->fdi->rxctl.v |= (1<<13);     /* enable pll */
1392                 loadreg(igfx, p->fdi->rxctl);
1393                 sleep(5);
1394                 p->fdi->rxctl.v |= (1<<4);      /* pcdclk */
1395                 loadreg(igfx, p->fdi->rxctl);
1396                 sleep(5);
1397                 p->fdi->txctl.v &= ~(7<<8 | 1); /* clear auto training bits */
1398                 p->fdi->txctl.v &= ~(1<<31);    /* disable */
1399                 p->fdi->txctl.v |= (1<<14);     /* enable pll */
1400                 loadreg(igfx, p->fdi->txctl);
1401                 sleep(5);
1402         }
1403
1404         /* image size (vga needs to be off) */
1405         loadreg(igfx, p->src);
1406
1407         /* set panel fitter as needed */
1408         if(p->pfit != nil){
1409                 loadreg(igfx, p->pfit->ctrl);
1410                 loadreg(igfx, p->pfit->winpos);
1411                 loadreg(igfx, p->pfit->winsize);        /* arm */
1412         }
1413
1414         /* keep planes disabled while pipe comes up */
1415         if(igfx->type == TypeG45)
1416                 p->conf.v |= 3<<18;
1417
1418         /* enable cpu pipe */
1419         loadtrans(igfx, p);
1420
1421         /* program plane */
1422         loadreg(igfx, p->dsp->cntr);
1423         loadreg(igfx, p->dsp->linoff);
1424         loadreg(igfx, p->dsp->stride);
1425         loadreg(igfx, p->dsp->tileoff);
1426         loadreg(igfx, p->dsp->size);
1427         loadreg(igfx, p->dsp->pos);
1428         loadreg(igfx, p->dsp->surf);    /* arm */
1429         loadreg(igfx, p->dsp->leftsurf);
1430
1431         /* program cursor */
1432         loadreg(igfx, p->cur->cntr);
1433         loadreg(igfx, p->cur->pos);
1434         loadreg(igfx, p->cur->base);    /* arm */
1435
1436         /* enable planes */
1437         if(igfx->type == TypeG45) {
1438                 p->conf.v &= ~(3<<18);
1439                 loadreg(igfx, p->conf);
1440         }
1441
1442         if(p->fdi->rxctl.a != 0){
1443                 /* enable fdi */
1444                 loadreg(igfx, p->fdi->rxtu[1]);
1445                 loadreg(igfx, p->fdi->rxtu[0]);
1446                 loadreg(igfx, p->fdi->rxmisc);
1447
1448                 if(igfx->type == TypeSNB){
1449                         /* unmask bit lock and symbol lock bits */
1450                         csr(igfx, p->fdi->rximr.a, 3<<8, 0);
1451
1452                         p->fdi->rxctl.v &= ~(3<<8);     /* link train pattern1 */
1453                         p->fdi->rxctl.v |= 1<<31;       /* enable */
1454                         loadreg(igfx, p->fdi->rxctl);
1455
1456                         p->fdi->txctl.v &= ~(3<<8);     /* link train pattern1 */
1457                         p->fdi->txctl.v |= 1<<31;       /* enable */
1458                         loadreg(igfx, p->fdi->txctl);
1459
1460                         /* wait for bit lock */
1461                         for(i=0; i<10; i++){
1462                                 sleep(1);
1463                                 if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
1464                                         break;
1465                         }
1466                         csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
1467         
1468                         /* switch to link train pattern2 */
1469                         csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
1470                         csr(igfx, p->fdi->txctl.a, 3<<8, 1<<8);
1471
1472                         /* wait for symbol lock */
1473                         for(i=0; i<10; i++){
1474                                 sleep(1);
1475                                 if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
1476                                         break;
1477                         }
1478                         csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
1479
1480                         /* switch to link train normal */
1481                         csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
1482                         csr(igfx, p->fdi->txctl.a, 0, 3<<8);
1483
1484                         /* wait idle pattern time */
1485                         sleep(5);
1486                 } else {
1487                         p->fdi->rxctl.v &= ~(3<<8);     /* link train pattern 00 */
1488                         p->fdi->rxctl.v |= 1<<10;       /* auto train enable */
1489                         p->fdi->rxctl.v |= 1<<31;       /* enable */
1490                         loadreg(igfx, p->fdi->rxctl);
1491
1492                         p->fdi->txctl.v &= ~(3<<8);     /* link train pattern 00 */
1493                         p->fdi->txctl.v |= 1<<10;       /* auto train enable */
1494                         p->fdi->txctl.v |= 1<<31;       /* enable */
1495                         loadreg(igfx, p->fdi->txctl);
1496
1497                         /* wait for link training done */
1498                         for(i=0; i<200; i++){
1499                                 sleep(5);
1500                                 if(rr(igfx, p->fdi->txctl.a) & 2)
1501                                         break;
1502                         }
1503                 }
1504         }
1505
1506         /* enable the transcoder */
1507         loadtrans(igfx, p->fdi);
1508 }
1509
1510 static void
1511 disabletrans(Igfx *igfx, Trans *t)
1512 {
1513         int i;
1514
1515         /* deselect pipe clock */
1516         csr(igfx, t->clksel.a, 7<<29, 0);
1517
1518         /* disable displayport transcoder */
1519         if(igfx->type == TypeHSW){
1520                 csr(igfx, t->dpctl.a, 15<<28, 0);
1521                 csr(igfx, t->ht.a, ~0, 0);
1522                 csr(igfx, t->hb.a, ~0, 0);
1523                 csr(igfx, t->hs.a, ~0, 0);
1524                 csr(igfx, t->vt.a, ~0, 0);
1525                 csr(igfx, t->vb.a, ~0, 0);
1526                 csr(igfx, t->vs.a, ~0, 0);
1527                 csr(igfx, t->vss.a, ~0, 0);
1528         }else
1529                 csr(igfx, t->dpctl.a, 1<<31, 3<<29);
1530
1531         /* disable transcoder / pipe */
1532         csr(igfx, t->conf.a, 1<<31, 0);
1533         for(i=0; i<100; i++){
1534                 sleep(10);
1535                 if((rr(igfx, t->conf.a) & (1<<30)) == 0)
1536                         break;
1537         }
1538         /* workarround: clear timing override bit */
1539         csr(igfx, t->chicken.a, 1<<31, 0);
1540
1541         /* disable dpll  */
1542         if(igfx->type != TypeHSW && t->dpll != nil)
1543                 csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
1544 }
1545
1546 static void
1547 disablepipe(Igfx *igfx, int x)
1548 {
1549         Pipe *p;
1550
1551         p = &igfx->pipe[x];
1552
1553         /* planes off */
1554         csr(igfx, p->dsp->cntr.a, 1<<31, 0);
1555         wr(igfx, p->dsp->surf.a, 0);    /* arm */
1556         /* cursor off */
1557         if(igfx->type == TypeHSW)
1558                 csr(igfx, p->cur->cntr.a, 0x3F, 0);
1559         else
1560                 csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
1561         wr(igfx, p->cur->base.a, 0);    /* arm */
1562
1563         /* display/overlay/cursor planes off */
1564         if(igfx->type == TypeG45)
1565                 csr(igfx, p->conf.a, 0, 3<<18);
1566         csr(igfx, p->src.a, ~0, 0);
1567
1568         /* disable cpu pipe */
1569         disabletrans(igfx, p);
1570
1571         /* disable panel fitter */
1572         if(p->pfit != nil)
1573                 csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
1574
1575         /* disable fdi transmitter and receiver */
1576         csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
1577         csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
1578
1579         /* disable pch transcoder */
1580         disabletrans(igfx, p->fdi);
1581
1582         /* disable pch dpll enable bit */
1583         if(igfx->type != TypeHSW)
1584                 csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
1585 }
1586
1587 static void
1588 load(Vga* vga, Ctlr* ctlr)
1589 {
1590         Igfx *igfx;
1591         int x, y;
1592
1593         igfx = vga->private;
1594
1595         /* power lcd off */
1596         if(igfx->ppcontrol.a != 0){
1597                 csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
1598                 for(x=0; x<5000; x++){
1599                         sleep(10);
1600                         if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
1601                                 break;
1602                 }
1603         }
1604
1605         /* disable ports */
1606         csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
1607         csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
1608         csr(igfx, igfx->adpa.a, 1<<31, 0);
1609         csr(igfx, igfx->lvds.a, 1<<31, 0);
1610         for(x = 0; x < nelem(igfx->dp); x++){
1611                 csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
1612                 if(igfx->dp[x].bufctl.a != 0){
1613                         csr(igfx, igfx->dp[x].bufctl.a, 1<<31, 0);
1614                         /* wait for buffers to return to idle */
1615                         for(y=0; y<5; y++){
1616                                 sleep(10);
1617                                 if(rr(igfx, igfx->dp[x].bufctl.a) & 1<<7)
1618                                         break;
1619                         }
1620                 }
1621         }
1622         for(x = 0; x < nelem(igfx->hdmi); x++)
1623                 csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
1624
1625         /* disable vga plane */
1626         csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
1627
1628         /* turn off all pipes */
1629         for(x = 0; x < igfx->npipe; x++)
1630                 disablepipe(igfx, x);
1631
1632         if(igfx->type == TypeG45){
1633                 /* toggle dsp a on and off (from enable sequence) */
1634                 csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);
1635                 csr(igfx, igfx->pipe[0].dsp->cntr.a, 0, 1<<31);
1636                 wr(igfx, igfx->pipe[0].dsp->surf.a, 0);         /* arm */
1637                 csr(igfx, igfx->pipe[0].dsp->cntr.a, 1<<31, 0);
1638                 wr(igfx, igfx->pipe[0].dsp->surf.a, 0);         /* arm */
1639                 csr(igfx, igfx->pipe[0].conf.a, 0, 3<<18);
1640         }
1641
1642         if(igfx->type == TypeHSW){
1643                 /* deselect port clock */
1644                 for(x=0; x<nelem(igfx->dpllsel); x++)
1645                         csr(igfx, igfx->dpllsel[x].a, 0, 7<<29);
1646
1647                 /* disable dpll's other than LCPLL */
1648                 for(x=1; x<nelem(igfx->dpll); x++)
1649                         csr(igfx, igfx->dpll[x].ctrl.a, 1<<31, 0);
1650         }
1651
1652         /* program new clock sources */
1653         loadreg(igfx, igfx->rawclkfreq);
1654         loadreg(igfx, igfx->drefctl);
1655         /* program cpu pll */
1656         if(igfx->type == TypeHSW)
1657                 for(x=0; x<nelem(igfx->dpll); x++)
1658                         loadreg(igfx, igfx->dpll[x].ctrl);
1659         sleep(10);
1660
1661         /* set lvds before enabling dpll */
1662         loadreg(igfx, igfx->lvds);
1663
1664         /* new dpll setting */
1665         for(x=0; x<nelem(igfx->dpllsel); x++)
1666                 loadreg(igfx, igfx->dpllsel[x]);
1667
1668         /* program all pipes */
1669         for(x = 0; x < igfx->npipe; x++)
1670                 enablepipe(igfx, x);
1671
1672         /* program vga plane */
1673         loadreg(igfx, igfx->vgacntrl);
1674
1675         /* program ports */
1676         loadreg(igfx, igfx->adpa);
1677         loadreg(igfx, igfx->sdvob);
1678         loadreg(igfx, igfx->sdvoc);
1679         for(x = 0; x < nelem(igfx->dp); x++){
1680                 for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
1681                         loadreg(igfx, igfx->dp[x].buftrans[y]);
1682                 loadreg(igfx, igfx->dp[x].bufctl);
1683                 if(enabledp(igfx, &igfx->dp[x]) < 0)
1684                         ctlr->flag |= Ferror;
1685         }
1686
1687         /* program lcd power */
1688         loadreg(igfx, igfx->ppcontrol);
1689
1690         ctlr->flag |= Fload;
1691 }
1692
1693 static void
1694 dumpreg(char *name, char *item, Reg r)
1695 {
1696         if(r.a == 0)
1697                 return;
1698
1699         printitem(name, item);
1700         Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
1701 }
1702
1703 static void
1704 dumphex(char *name, char *item, uchar *data, int len)
1705 {
1706         int i;
1707
1708         for(i=0; i<len; i++){
1709                 if((i & 15) == 0){
1710                         if(i > 0)
1711                                 Bprint(&stdout, "\n");
1712                         printitem(name, item);
1713                         Bprint(&stdout, " [%.2x] =", i);
1714                 }
1715                 Bprint(&stdout, " %.2X", data[i]);
1716         }
1717         Bprint(&stdout, "\n");
1718 }
1719
1720 static void
1721 dumptiming(char *name, Trans *t)
1722 {
1723         int tu, m, n;
1724
1725         if(t->dm[0].a != 0 && t->dm[0].v != 0){
1726                 tu = 1+((t->dm[0].v >> 25) & 0x3f);
1727                 printitem(name, "dm1 tu");
1728                 Bprint(&stdout, " %d\n", tu);
1729
1730                 m = t->dm[0].v & 0xffffff;
1731                 n = t->dn[0].v;
1732                 if(n > 0){
1733                         printitem(name, "dm1/dn1");
1734                         Bprint(&stdout, " %f\n", (double)m / (double)n);
1735                 }
1736
1737                 m = t->lm[0].v;
1738                 n = t->ln[0].v;
1739                 if(n > 0){
1740                         printitem(name, "lm1/ln1");
1741                         Bprint(&stdout, " %f\n", (double)m / (double)n);
1742                 }
1743         }
1744 }
1745
1746 static void
1747 dumptrans(char *name, Trans *t)
1748 {
1749         dumpreg(name, "conf", t->conf);
1750
1751         dumpreg(name, "dm1", t->dm[0]);
1752         dumpreg(name, "dn1", t->dn[0]);
1753         dumpreg(name, "lm1", t->lm[0]);
1754         dumpreg(name, "ln1", t->ln[0]);
1755         dumpreg(name, "dm2", t->dm[1]);
1756         dumpreg(name, "dn2", t->dn[1]);
1757         dumpreg(name, "lm2", t->lm[1]);
1758         dumpreg(name, "ln2", t->ln[1]);
1759
1760         dumptiming(name, t);
1761
1762         dumpreg(name, "ht", t->ht);
1763         dumpreg(name, "hb", t->hb);
1764         dumpreg(name, "hs", t->hs);
1765
1766         dumpreg(name, "vt", t->vt);
1767         dumpreg(name, "vb", t->vb);
1768         dumpreg(name, "vs", t->vs);
1769         dumpreg(name, "vss", t->vss);
1770
1771         dumpreg(name, "dpctl", t->dpctl);
1772         dumpreg(name, "clksel", t->clksel);
1773 }
1774
1775 static void
1776 dumppipe(Igfx *igfx, int x)
1777 {
1778         char name[32];
1779         Pipe *p;
1780
1781         p = &igfx->pipe[x];
1782
1783         snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
1784         dumpreg(name, "src", p->src);
1785         dumptrans(name, p);
1786
1787         snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
1788         dumptrans(name, p->fdi);
1789         dumpreg(name, "txctl", p->fdi->txctl);
1790         dumpreg(name, "rxctl", p->fdi->rxctl);
1791         dumpreg(name, "rxmisc", p->fdi->rxmisc);
1792         dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
1793         dumpreg(name, "rxtu2", p->fdi->rxtu[1]);
1794
1795         snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
1796         dumpreg(name, "cntr", p->dsp->cntr);
1797         dumpreg(name, "linoff", p->dsp->linoff);
1798         dumpreg(name, "stride", p->dsp->stride);
1799         dumpreg(name, "surf", p->dsp->surf);
1800         dumpreg(name, "tileoff", p->dsp->tileoff);
1801         dumpreg(name, "leftsurf", p->dsp->leftsurf);
1802         dumpreg(name, "pos", p->dsp->pos);
1803         dumpreg(name, "size", p->dsp->size);
1804
1805         snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
1806         dumpreg(name, "cntr", p->cur->cntr);
1807         dumpreg(name, "base", p->cur->base);
1808         dumpreg(name, "pos", p->cur->pos);
1809 }
1810
1811 static void
1812 dumpdpll(Igfx *igfx, int x)
1813 {
1814         int cref, m1, m2, n, p1, p2;
1815         uvlong freq;
1816         char name[32];
1817         Dpll *dpll;
1818         u32int m;
1819
1820         dpll = &igfx->dpll[x];
1821         snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
1822
1823         dumpreg(name, "ctrl", dpll->ctrl);
1824         dumpreg(name, "fp0", dpll->fp0);
1825         dumpreg(name, "fp1", dpll->fp1);
1826
1827         if(igfx->type == TypeHSW)
1828                 return;
1829
1830         p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
1831         if(((dpll->ctrl.v >> 24) & 3) == 1)
1832                 p2 >>= 1;
1833         m = (dpll->ctrl.v >> 16) & 0xFF;
1834         for(p1 = 1; p1 <= 8; p1++)
1835                 if(m & (1<<(p1-1)))
1836                         break;
1837         printitem(name, "ctrl p1");
1838         Bprint(&stdout, " %d\n", p1);
1839         printitem(name, "ctrl p2");
1840         Bprint(&stdout, " %d\n", p2);
1841
1842         n = (dpll->fp0.v >> 16) & 0x3f;
1843         m1 = (dpll->fp0.v >> 8) & 0x3f;
1844         m2 = (dpll->fp0.v >> 0) & 0x3f;
1845
1846         cref = getcref(igfx, x);
1847         freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
1848
1849         printitem(name, "fp0 m1");
1850         Bprint(&stdout, " %d\n", m1);
1851         printitem(name, "fp0 m2");
1852         Bprint(&stdout, " %d\n", m2);
1853         printitem(name, "fp0 n");
1854         Bprint(&stdout, " %d\n", n);
1855
1856         printitem(name, "cref");
1857         Bprint(&stdout, " %d\n", cref);
1858         printitem(name, "fp0 freq");
1859         Bprint(&stdout, " %lld\n", freq);
1860 }
1861
1862 static void
1863 dump(Vga* vga, Ctlr* ctlr)
1864 {
1865         char name[32];
1866         Igfx *igfx;
1867         int x, y;
1868
1869         if((igfx = vga->private) == nil)
1870                 return;
1871
1872         for(x=0; x<igfx->npipe; x++)
1873                 dumppipe(igfx, x);
1874
1875         for(x=0; x<nelem(igfx->dpll); x++)
1876                 dumpdpll(igfx, x);
1877
1878         for(x=0; x<nelem(igfx->dpllsel); x++){
1879                 snprint(name, sizeof(name), "%s dpllsel %c", ctlr->name, 'a'+x);
1880                 dumpreg(name, "dpllsel", igfx->dpllsel[x]);
1881         }
1882
1883         dumpreg(ctlr->name, "drefctl", igfx->drefctl);
1884         dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
1885         dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
1886
1887         for(x=0; x<nelem(igfx->dp); x++){
1888                 if(igfx->dp[x].ctl.a == 0)
1889                         continue;
1890                 snprint(name, sizeof(name), "%s dp %c", ctlr->name, 'a'+x);
1891                 dumpreg(name, "ctl", igfx->dp[x].ctl);
1892                 dumpreg(name, "bufctl", igfx->dp[x].bufctl);
1893                 dumpreg(name, "stat", igfx->dp[x].stat);
1894                 dumphex(name, "dpcd", igfx->dp[x].dpcd, sizeof(igfx->dp[x].dpcd));
1895                 for(y=0; y<nelem(igfx->dp[x].buftrans); y++){
1896                         snprint(name, sizeof(name), "%s buftrans %c %d", ctlr->name, 'a'+x, y);
1897                         dumpreg(name, "ctl", igfx->dp[x].buftrans[y]);
1898                 }
1899         }
1900         for(x=0; x<nelem(igfx->hdmi); x++){
1901                 snprint(name, sizeof(name), "%s hdmi %c", ctlr->name, 'a'+x);
1902                 dumpreg(name, "ctl", igfx->hdmi[x].ctl);
1903         }
1904
1905         for(x=0; x<nelem(igfx->pfit); x++){
1906                 snprint(name, sizeof(name), "%s pfit %c", ctlr->name, 'a'+x);
1907                 dumpreg(name, "ctrl", igfx->pfit[x].ctrl);
1908                 dumpreg(name, "winpos", igfx->pfit[x].winpos);
1909                 dumpreg(name, "winsize", igfx->pfit[x].winsize);
1910                 dumpreg(name, "pwrgate", igfx->pfit[x].pwrgate);
1911         }
1912
1913         dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
1914         dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);
1915
1916         dumpreg(ctlr->name, "adpa", igfx->adpa);
1917         dumpreg(ctlr->name, "lvds", igfx->lvds);
1918         dumpreg(ctlr->name, "sdvob", igfx->sdvob);
1919         dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
1920
1921         dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
1922 }
1923
1924 static int
1925 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
1926 {
1927         int t, i;
1928         u32int w;
1929
1930         if(dp->auxctl.a == 0){
1931                 werrstr("not present");
1932                 return -1;
1933         }
1934
1935         t = 0;
1936         while(rr(igfx, dp->auxctl.a) & (1<<31)){
1937                 if(++t >= 10){
1938                         werrstr("busy");
1939                         return -1;
1940                 }
1941                 sleep(5);
1942         }
1943
1944         /* clear sticky bits */
1945         wr(igfx, dp->auxctl.a, (1<<28) | (1<<25) | (1<<30));
1946
1947         for(i=0; i<nelem(dp->auxdat); i++){
1948                 w  = buf[i*4+0]<<24;
1949                 w |= buf[i*4+1]<<16;
1950                 w |= buf[i*4+2]<<8;
1951                 w |= buf[i*4+3];
1952                 wr(igfx, dp->auxdat[i].a, w);
1953         }
1954
1955         /* 2X Bit Clock divider */
1956         w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3ff)) >> 1;
1957         if(w < 1 || w > 0x3fd){
1958                 werrstr("bad clock");
1959                 return -1;
1960         }
1961
1962         /* hack: slow down a bit */
1963         w += 2;
1964
1965         w |= 1<<31;     /* SendBusy */
1966         w |= 1<<29;     /* interrupt disabled */
1967         w |= 3<<26;     /* timeout 1600µs */
1968         w |= len<<20;   /* send bytes */
1969         w |= 5<<16;     /* precharge time (5*2 = 10µs) */
1970         wr(igfx, dp->auxctl.a, w);
1971
1972         t = 0;
1973         for(;;){
1974                 w = rr(igfx, dp->auxctl.a);
1975                 if((w & (1<<30)) != 0)
1976                         break;
1977                 if(++t >= 10){
1978                         werrstr("busy");
1979                         return -1;
1980                 }
1981                 sleep(5);
1982         }
1983         if(w & (1<<28)){
1984                 werrstr("receive timeout");
1985                 return -1;
1986         }
1987         if(w & (1<<25)){
1988                 werrstr("receive error");
1989                 return -1;
1990         }
1991
1992         len = (w >> 20) & 0x1f;
1993         for(i=0; i<nelem(dp->auxdat); i++){
1994                 w = rr(igfx, dp->auxdat[i].a);
1995                 buf[i*4+0] = w>>24;
1996                 buf[i*4+1] = w>>16;
1997                 buf[i*4+2] = w>>8;
1998                 buf[i*4+3] = w;
1999         }
2000
2001         return len;
2002 }
2003
2004 enum {
2005         CmdNative       = 8,
2006         CmdMot          = 4,
2007         CmdRead         = 1,
2008         CmdWrite        = 0,
2009 };
2010
2011 static int
2012 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
2013 {
2014         uchar buf[20];
2015         int r;
2016
2017         assert(len <= 16);
2018
2019         memset(buf, 0, sizeof(buf));
2020         buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
2021         buf[1] = addr >> 8;
2022         buf[2] = addr;
2023         buf[3] = len-1;
2024         r = 3;  
2025         if(data != nil && len > 0){
2026                 if((cmd & CmdRead) == 0)
2027                         memmove(buf+4, data, len);
2028                 r = 4;
2029                 if((cmd & CmdRead) == 0)
2030                         r += len;
2031         }
2032         if((r = dpauxio(igfx, dp, buf, r)) < 0){
2033                 trace("%s: dpauxio: dp %c, cmd %x, addr %x, len %d: %r\n",
2034                         igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]), cmd, addr, len);
2035                 return -1;
2036         }
2037         if(r == 0 || data == nil || len == 0)
2038                 return 0;
2039         if((cmd & CmdRead) != 0){
2040                 if(--r < len)
2041                         len = r;
2042                 memmove(data, buf+1, len);
2043         }
2044         return len;
2045 }
2046
2047 static int
2048 rdpaux(Igfx *igfx, Dp *dp, int addr)
2049 {
2050         uchar buf[1];
2051         if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
2052                 return -1;
2053         return buf[0];
2054 }
2055 static int
2056 wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
2057 {
2058         if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
2059                 return -1;
2060         return 0;
2061 }
2062
2063 static int
2064 enabledp(Igfx *igfx, Dp *dp)
2065 {
2066         int try, r;
2067         u32int w;
2068
2069         if(dp->ctl.a == 0)
2070                 return 0;
2071         if((dp->ctl.v & (1<<31)) == 0)
2072                 return 0;
2073
2074         /* FIXME: always times out */
2075         if(igfx->type == TypeHSW && dp == &igfx->dp[0])
2076                 goto Skip;
2077
2078         /* Link configuration */
2079         wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000);
2080         w = dp->ctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
2081         wdpaux(igfx, dp, 0x101, w+1);
2082
2083         r = 0;
2084
2085         /* Link training pattern 1 */
2086         dp->ctl.v &= ~(7<<8);
2087         loadreg(igfx, dp->ctl);
2088         for(try = 0;;try++){
2089                 if(try > 5)
2090                         goto Fail;
2091                 /* Link training pattern 1 */
2092                 wdpaux(igfx, dp, 0x102, 0x01);
2093                 sleep(100);
2094                 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2095                         goto Fail;
2096                 if(r & 1)       /* LANE0_CR_DONE */
2097                         break;
2098         }
2099         trace("pattern1 finished: %x\n", r);
2100
2101         /* Link training pattern 2 */
2102         dp->ctl.v &= ~(7<<8);
2103         dp->ctl.v |= 1<<8;
2104         loadreg(igfx, dp->ctl);
2105         for(try = 0;;try++){
2106                 if(try > 5)
2107                         goto Fail;
2108                 /* Link training pattern 2 */
2109                 wdpaux(igfx, dp, 0x102, 0x02);
2110                 sleep(100);
2111                 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2112                         goto Fail;
2113                 if((r & 7) == 7)
2114                         break;
2115         }
2116         trace("pattern2 finished: %x\n", r);
2117
2118         if(igfx->type == TypeHSW){
2119                 /* set link training to idle pattern and wait for 5 idle
2120                  * patterns */
2121                 dp->ctl.v &= ~(7<<8);
2122                 dp->ctl.v |= 2<<8;
2123                 loadreg(igfx, dp->ctl);
2124                 for(try=0; try<10; try++){
2125                         sleep(10);
2126                         if(rr(igfx, dp->stat.a) & (1<<25))
2127                                 break;
2128                 }
2129         }
2130 Skip:
2131         /* stop training */
2132         dp->ctl.v &= ~(7<<8);
2133         dp->ctl.v |= 3<<8;
2134         loadreg(igfx, dp->ctl);
2135         wdpaux(igfx, dp, 0x102, 0x00);
2136         return 1;
2137
2138 Fail:
2139         trace("training failed: %x\n", r);
2140
2141         /* disable port */
2142         dp->ctl.v &= ~(1<<31);
2143         loadreg(igfx, dp->ctl);
2144         wdpaux(igfx, dp, 0x102, 0x00);
2145         return -1;
2146 }
2147
2148 static uchar*
2149 edidshift(uchar buf[256])
2150 {
2151         uchar tmp[256];
2152         int i;
2153
2154         /* shift if neccesary so edid block is at the start */
2155         for(i=0; i<256-8; i++){
2156                 if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
2157                 && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
2158                         memmove(tmp, buf, i);
2159                         memmove(buf, buf + i, 256 - i);
2160                         memmove(buf + (256 - i), tmp, i);
2161                         break;
2162                 }
2163         }
2164         return buf;
2165 }
2166
2167 static Edid*
2168 snarfdpedid(Igfx *igfx, Dp *dp, int addr)
2169 {
2170         uchar buf[256];
2171         int i;
2172         Edid *e;
2173
2174         for(i=0; i<sizeof(dp->dpcd); i+=16)
2175                 if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
2176                         return nil;
2177
2178         if(dp->dpcd[0] == 0)    /* nothing there, dont try to get edid */
2179                 return nil;
2180
2181         if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
2182                 return nil;
2183
2184         for(i=0; i<sizeof(buf); i+=16){
2185                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2186                         continue;
2187                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2188                         continue;
2189                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2190                         continue;
2191                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2192                         continue;
2193                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2194                         continue;
2195                 return nil;
2196         }
2197
2198         dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
2199
2200         if((e = parseedid128(edidshift(buf))) == nil)
2201                 trace("%s: snarfdpedid: dp %c: %r\n", igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]));
2202         return e;
2203 }
2204
2205 enum {
2206         GMBUSCP = 0,    /* Clock/Port selection */
2207         GMBUSCS = 1,    /* Command/Status */
2208         GMBUSST = 2,    /* Status Register */
2209         GMBUSDB = 3,    /* Data Buffer Register */
2210         GMBUSIM = 4,    /* Interrupt Mask */
2211         GMBUSIX = 5,    /* Index Register */
2212 };
2213         
2214 static int
2215 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
2216 {
2217         u32int x, y;
2218         int n, t;
2219
2220         if(igfx->gmbus[GMBUSCP].a == 0)
2221                 return -1;
2222
2223         wr(igfx, igfx->gmbus[GMBUSCP].a, port);
2224         wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
2225
2226         /* bus cycle without index and stop, byte count, slave address, read */
2227         wr(igfx, igfx->gmbus[GMBUSCS].a, 1<<30 | 5<<25 | len<<16 | addr<<1 | 1);
2228
2229         n = 0;
2230         while(len > 0){
2231                 x = 0;
2232                 for(t=0; t<100; t++){
2233                         x = rr(igfx, igfx->gmbus[GMBUSST].a);
2234                         if(x & (1<<11))
2235                                 break;
2236                         sleep(5);
2237                 }
2238                 if((x & (1<<11)) == 0)
2239                         return -1;
2240
2241                 t = 4 - (x & 3);
2242                 if(t > len)
2243                         t = len;
2244                 len -= t;
2245
2246                 y = rr(igfx, igfx->gmbus[GMBUSDB].a);
2247                 switch(t){
2248                 case 4:
2249                         data[n++] = y & 0xff, y >>= 8;
2250                 case 3:
2251                         data[n++] = y & 0xff, y >>= 8;
2252                 case 2:
2253                         data[n++] = y & 0xff, y >>= 8;
2254                 case 1:
2255                         data[n++] = y & 0xff;
2256                 }
2257         }
2258
2259         return n;
2260 }
2261
2262 static Edid*
2263 snarfgmedid(Igfx *igfx, int port, int addr)
2264 {
2265         uchar buf[256];
2266
2267         /* read twice */
2268         if(gmbusread(igfx, port, addr, buf, 128) != 128)
2269                 return nil;
2270         if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
2271                 return nil;
2272
2273         return parseedid128(edidshift(buf));
2274 }
2275
2276 Ctlr igfx = {
2277         "igfx",                 /* name */
2278         snarf,                  /* snarf */
2279         options,                /* options */
2280         init,                   /* init */
2281         load,                   /* load */
2282         dump,                   /* dump */
2283 };
2284
2285 Ctlr igfxhwgc = {
2286         "igfxhwgc",
2287 };