]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/igfx.c
igfx: fix cdclk and dpll settings for dual channel lvds on sandybridge
[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 = 400;      /* 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(freq > 112*MHz){
847                         p2 >>= 1;
848                         dpll->ctrl.v |= (1<<24);
849                 }
850                 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
851                         return -1;
852         } else {
853                 /* generate 270MHz clock for displayport */
854                 if(port >= PortDPA)
855                         freq = 270*MHz;
856
857                 p2 = 10;
858                 if(freq > 270*MHz){
859                         p2 >>= 1;
860                         dpll->ctrl.v |= (1<<24);
861                 }
862                 if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
863                         return -1;
864         }
865
866         /* Dpll VCO Enable */
867         dpll->ctrl.v |= (1<<31);
868
869         /* Dpll Serial DVO High Speed IO clock Enable */
870         if(port >= PortDPA)
871                 dpll->ctrl.v |= (1<<30);
872         else
873                 dpll->ctrl.v &= ~(1<<30);
874
875         /* VGA Mode Disable */
876         if(igfx->type == TypeG45)
877                 dpll->ctrl.v |= (1<<28);
878
879         dpll->fp0.v &= ~(0x3f<<16);
880         dpll->fp0.v |= n << 16;
881         dpll->fp0.v &= ~(0x3f<<8);
882         dpll->fp0.v |= m1 << 8;
883         dpll->fp0.v &= ~(0x3f<<0);
884         dpll->fp0.v |= m2 << 0;
885
886         /* FP0 P1 Post Divisor */
887         dpll->ctrl.v &= ~0xFF0000;
888         dpll->ctrl.v |=  0x010000<<(p1-1);
889
890         /* FP1 P1 Post divisor */
891         if(igfx->pci->did != 0x27a2){
892                 dpll->ctrl.v &= ~0xFF;
893                 dpll->ctrl.v |=  0x01<<(p1-1);
894                 dpll->fp1.v = dpll->fp0.v;
895         }
896
897         return 0;
898 }
899
900 static int
901 needlanes(int freq, int lsclk, int bpp)
902 {
903         vlong v;
904         int n;
905
906         v = ((vlong)freq * bpp) / 8;
907         for(n=1; n<4 && v>lsclk; n<<=1, v>>=1)
908                 ;
909         return n;
910 }
911
912 static void
913 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
914 {
915         u32int m, n;
916
917         n = 0x800000;
918         m = (n * (((uvlong)freq * bpp)/8)) / ((uvlong)lsclk * lanes);
919
920         t->dm[0].v = (tu-1)<<25 | m;
921         t->dn[0].v = n;
922
923         n = 0x80000;
924         m = ((uvlong)n * freq) / lsclk;
925
926         t->lm[0].v = m;
927         t->ln[0].v = n;
928
929         t->dm[1].v = t->dm[0].v;
930         t->dn[1].v = t->dn[0].v;
931         t->lm[1].v = t->lm[0].v;
932         t->ln[1].v = t->ln[0].v;
933 }
934
935 static void
936 inittrans(Trans *t, Mode *m)
937 {
938         /* clear all but 27:28 frame start delay (initialized by bios) */
939         t->conf.v &= 3<<27;
940
941         /* tans/pipe enable */
942         t->conf.v |= 1<<31;
943
944         /* trans/pipe timing */
945         t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
946         t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);
947         t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
948         t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
949
950         t->hb.v = t->ht.v;
951         t->vb.v = t->vt.v;
952
953         t->vss.v = 0;
954 }
955
956 static void
957 initpipe(Igfx *igfx, Pipe *p, Mode *m, int bpc, int port)
958 {
959         static uchar bpctab[4] = { 8, 10, 6, 12 };
960         int i, tu, lanes;
961         Fdi *fdi;
962
963         /* source image size */
964         p->src.v = (m->x - 1)<<16 | (m->y - 1);
965
966         if(p->pfit != nil){
967                 /* panel fitter off */
968                 p->pfit->ctrl.v &= ~(1<<31);
969                 p->pfit->winpos.v = 0;
970                 p->pfit->winsize.v = 0;
971         }
972
973         /* enable and set monitor timings for cpu pipe */
974         inittrans(p, m);
975
976         /* default for displayport */
977         lanes = needlanes(m->frequency, 270*MHz, 3*bpc);
978         tu = 64;
979
980         fdi = p->fdi;
981         if(fdi->rxctl.a != 0){
982                 /* enable and set monitor timings for transcoder */
983                 inittrans(fdi, m);
984
985                 /* tx port width selection */
986                 fdi->txctl.v &= ~(7<<19);
987                 fdi->txctl.v |= (lanes-1)<<19;
988
989                 /* rx port width selection */
990                 fdi->rxctl.v &= ~(7<<19);
991                 fdi->rxctl.v |= (lanes-1)<<19;
992                 /* bits per color for transcoder */
993                 for(i=0; i<nelem(bpctab); i++){
994                         if(bpctab[i] == bpc){
995                                 fdi->rxctl.v &= ~(7<<16);
996                                 fdi->rxctl.v |= i<<16;
997                                 fdi->dpctl.v &= ~(7<<9);
998                                 fdi->dpctl.v |= i<<9;
999                                 break;
1000                         }
1001                 }
1002
1003                 /* enhanced framing on */
1004                 fdi->rxctl.v |= (1<<6);
1005                 fdi->txctl.v |= (1<<18);
1006
1007                 /* tusize 1 and 2 */
1008                 fdi->rxtu[0].v = (tu-1)<<25;
1009                 fdi->rxtu[1].v = (tu-1)<<25;
1010                 initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1011         }else if(igfx->type == TypeHSW){
1012                 p->dpctl.v &= 0xf773733e;       /* mbz */
1013                 /* transcoder enable */
1014                 p->dpctl.v |= 1<<31;
1015                 /* DDI select (ignored by eDP) */
1016                 p->dpctl.v &= ~(7<<28);
1017                 p->dpctl.v |= (port-PortDPA)<<28;
1018                 /* displayport SST or hdmi mode */
1019                 p->dpctl.v &= ~(7<<24);
1020                 if(!igfx->dp[port-PortDPA].hdmi)
1021                         p->dpctl.v |= 2<<24;
1022                 /* sync polarity */
1023                 p->dpctl.v |= 3<<16;
1024                 if(m->hsync == '-')
1025                         p->dpctl.v ^= 1<<16;
1026                 if(m->vsync == '-')
1027                         p->dpctl.v ^= 1<<17;
1028                 /* eDP input select: always on power well */
1029                 p->dpctl.v &= ~(7<<12);
1030                 /* dp port width */
1031                 if(igfx->dp[port-PortDPA].hdmi)
1032                         lanes = 4;
1033                 else{
1034                         p->dpctl.v &= ~(7<<1);
1035                         p->dpctl.v |= lanes-1 << 1;
1036                 }
1037         }
1038
1039         /* bits per color for cpu pipe */
1040         for(i=0; i<nelem(bpctab); i++){
1041                 if(bpctab[i] == bpc){
1042                         if(igfx->type == TypeHSW){
1043                                 p->dpctl.v &= ~(7<<20);
1044                                 p->dpctl.v |= i<<20;
1045                         }else{
1046                                 p->conf.v &= ~(7<<5);
1047                                 p->conf.v |= i<<5;
1048                         }
1049                         break;
1050                 }
1051         }
1052         initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
1053 }
1054
1055 static void
1056 init(Vga* vga, Ctlr* ctlr)
1057 {
1058         int x, nl, port, bpc;
1059         char *val;
1060         Igfx *igfx;
1061         Pipe *p;
1062         Mode *m;
1063         Reg *r;
1064
1065         m = vga->mode;
1066         if(m->z != 32)
1067                 error("%s: unsupported color depth %d\n", ctlr->name, m->z);
1068
1069         bpc = 8;        /* bits per color channel */
1070
1071         igfx = vga->private;
1072
1073         /* disable vga */
1074         igfx->vgacntrl.v |= (1<<31);
1075
1076         /* disable all pipes and ports */
1077         igfx->ppcontrol.v &= 10;        /* 15:4 mbz; unset 5<<0 */
1078         igfx->lvds.v &= ~(1<<31);
1079         igfx->adpa.v &= ~(1<<31);
1080         if(igfx->type == TypeG45)
1081                 igfx->adpa.v |= (3<<10);        /* Monitor DPMS: off */
1082         if(igfx->type == TypeHSW){
1083                 for(x=1; x<nelem(igfx->dpll); x++)
1084                         igfx->dpll[x].ctrl.v &= ~(1<<31);
1085                 for(x=0; x<nelem(igfx->dpllsel); x++)
1086                         igfx->dpllsel[x].v = 7<<29;
1087         }
1088         for(x=0; x<nelem(igfx->dp); x++){
1089                 igfx->dp[x].ctl.v &= ~(1<<31);
1090                 igfx->dp[x].bufctl.v &= ~(1<<31);
1091         }
1092         for(x=0; x<nelem(igfx->hdmi); x++)
1093                 igfx->hdmi[x].ctl.v &= ~(1<<31);
1094         for(x=0; x<igfx->npipe; x++){
1095                 /* disable displayport transcoders */
1096                 igfx->pipe[x].dpctl.v &= ~(1<<31);
1097                 igfx->pipe[x].fdi->dpctl.v &= ~(1<<31);
1098                 if(igfx->type == TypeHSW){
1099                         igfx->pipe[x].dpctl.v &= ~(7<<28);
1100                         igfx->pipe[x].fdi->dpctl.v &= ~(7<<28);
1101                 }else{
1102                         igfx->pipe[x].dpctl.v |= (3<<29);
1103                         igfx->pipe[x].fdi->dpctl.v |= (3<<29);
1104                 }
1105                 /* disable transcoder/pipe */
1106                 igfx->pipe[x].conf.v &= ~(1<<31);
1107                 igfx->pipe[x].fdi->conf.v &= ~(1<<31);
1108         }
1109
1110         if((val = dbattr(m->attr, "display")) != nil){
1111                 port = atoi(val)-1;
1112                 if(igfx->type == TypeHSW && !igfx->dp[port-PortDPA].hdmi)
1113                         bpc = 6;
1114         }else if(dbattr(m->attr, "lcd") != nil)
1115                 port = PortLCD;
1116         else
1117                 port = PortVGA;
1118
1119         trace("%s: display #%d\n", ctlr->name, port+1);
1120
1121         switch(port){
1122         default:
1123         Badport:
1124                 error("%s: display #%d not supported\n", ctlr->name, port+1);
1125                 break;
1126
1127         case PortVGA:
1128                 if(igfx->type == TypeHSW)       /* unimplemented */
1129                         goto Badport;
1130                 if(igfx->type == TypeG45)
1131                         x = (igfx->adpa.v >> 30) & 1;
1132                 else
1133                         x = (igfx->adpa.v >> 29) & 3;
1134                 igfx->adpa.v |= (1<<31);
1135                 if(igfx->type == TypeG45){
1136                         igfx->adpa.v &= ~(3<<10);       /* Monitor DPMS: on */
1137
1138                         igfx->adpa.v &= ~(1<<15);       /* ADPA Polarity Select */
1139                         igfx->adpa.v |= 3<<3;
1140                         if(m->hsync == '-')
1141                                 igfx->adpa.v ^= 1<<3;
1142                         if(m->vsync == '-')
1143                                 igfx->adpa.v ^= 1<<4;
1144                 }
1145                 break;
1146
1147         case PortLCD:
1148                 if(igfx->type == TypeHSW)
1149                         goto Badport;
1150                 if(igfx->type == TypeG45)
1151                         x = (igfx->lvds.v >> 30) & 1;
1152                 else
1153                         x = (igfx->lvds.v >> 29) & 3;
1154                 igfx->lvds.v |= (1<<31);
1155                 igfx->ppcontrol.v |= 5;
1156
1157                 if(igfx->type == TypeG45){
1158                         igfx->lvds.v &= ~(1<<24);       /* data format select 18/24bpc */
1159
1160                         igfx->lvds.v &= ~(3<<20);
1161                         if(m->hsync == '-')
1162                                 igfx->lvds.v ^= 1<<20;
1163                         if(m->vsync == '-')
1164                                 igfx->lvds.v ^= 1<<21;
1165
1166                         igfx->lvds.v |= (1<<15);        /* border enable */
1167                 }
1168                 break;
1169
1170         case PortDPA:
1171         case PortDPB:
1172         case PortDPC:
1173         case PortDPD:
1174         case PortDPE:
1175                 r = &igfx->dp[port - PortDPA].ctl;
1176                 if(r->a == 0)
1177                         goto Badport;
1178                 /* port enable */
1179                 r->v |= 1<<31;
1180                 /* use PIPE_A for displayport */
1181                 x = 0;
1182
1183                 if(igfx->type == TypeHSW){
1184                         if(port == PortDPA){
1185                                 /* only enable panel for eDP */
1186                                 igfx->ppcontrol.v |= 5;
1187                                 /* use eDP pipe */
1188                                 x = 3;
1189                         }
1190
1191                         /* reserved MBZ */
1192                         r->v &= ~(7<<28) & ~(1<<26) & ~(63<<19) & ~(3<<16) & ~(15<<11) & ~(1<<7) & ~31;
1193                         /* displayport SST mode */
1194                         r->v &= ~(1<<27);
1195                         /* link not in training, send normal pixels */
1196                         r->v |= 3<<8;
1197                         if(igfx->dp[port-PortDPA].hdmi){
1198                                 /* hdmi: do not configure displayport */
1199                                 r->a = 0;
1200                                 r->v &= ~(1<<31);
1201                         }
1202
1203                         r = &igfx->dp[port - PortDPA].bufctl;
1204                         /* buffer enable */
1205                         r->v |= 1<<31;
1206                         /* reserved MBZ */
1207                         r->v &= ~(7<<28) & ~(127<<17) & ~(255<<8) & ~(3<<5);
1208                         /* grab lanes shared with port e when using port a */
1209                         if(port == PortDPA)
1210                                 r->v |= 1<<4;
1211                         else if(port == PortDPE)
1212                                 igfx->dp[0].bufctl.v &= ~(1<<4);
1213                         /* dp port width */
1214                         r->v &= ~(15<<1);
1215                         if(!igfx->dp[port-PortDPA].hdmi){
1216                                 nl = needlanes(m->frequency, 270*MHz, 3*bpc);
1217                                 /* x4 unsupported on port e */
1218                                 if(nl > 2 && port == PortDPE)
1219                                         goto Badport;
1220                                 r->v |= nl-1 << 1;
1221                         }
1222                         /* port reversal: off */
1223                         r->v &= ~(1<<16);
1224
1225                         /* buffer translation (vsl/pel) */
1226                         r = igfx->dp[port - PortDPA].buftrans;
1227                         r[1].v  = 0x0006000E;   r[0].v  = 0x00FFFFFF;
1228                         r[3].v  = 0x0005000A;   r[2].v  = 0x00D75FFF;
1229                         r[5].v  = 0x00040006;   r[4].v  = 0x00C30FFF;
1230                         r[7].v  = 0x000B0000;   r[6].v  = 0x80AAAFFF;
1231                         r[9].v  = 0x0005000A;   r[8].v  = 0x00FFFFFF;
1232                         r[11].v = 0x000C0004;   r[10].v = 0x00D75FFF;
1233                         r[13].v = 0x000B0000;   r[12].v = 0x80C30FFF;
1234                         r[15].v = 0x00040006;   r[14].v = 0x00FFFFFF;
1235                         r[17].v = 0x000B0000;   r[16].v = 0x80D75FFF;
1236                         r[19].v = 0x00040006;   r[18].v = 0x00FFFFFF;
1237                         break;
1238                 }
1239
1240                 if(port == PortDPE)
1241                         goto Badport;
1242
1243                 /* port width selection */
1244                 r->v &= ~(7<<19);
1245                 r->v |= needlanes(m->frequency, 270*MHz, 3*bpc)-1 << 19;
1246
1247                 /* port reversal: off */
1248                 r->v &= ~(1<<15);
1249                 /* reserved MBZ */
1250                 r->v &= ~(15<<11);
1251                 /* displayport transcoder */
1252                 if(port == PortDPA){
1253                         /* reserved MBZ */
1254                         r->v &= ~(15<<10);
1255                         /* pll frequency: 270mhz */
1256                         r->v &= ~(3<<16);
1257                         /* pll enable */
1258                         r->v |= 1<<14;
1259                         /* pipe select */
1260                         r->v &= ~(3<<29);
1261                         r->v |= x<<29;
1262                 } else if(igfx->pipe[x].fdi->dpctl.a != 0){
1263                         /* reserved MBZ */
1264                         r->v &= ~(15<<11);
1265                         /* audio output: disable */
1266                         r->v &= ~(1<<6);
1267                         /* transcoder displayport configuration */
1268                         r = &igfx->pipe[x].fdi->dpctl;
1269                         /* transcoder enable */
1270                         r->v |= 1<<31;
1271                         /* port select: B,C,D */
1272                         r->v &= ~(3<<29);
1273                         r->v |= (port-PortDPB)<<29;
1274                 }
1275                 /* sync polarity */
1276                 r->v |= 3<<3;
1277                 if(m->hsync == '-')
1278                         r->v ^= 1<<3;
1279                 if(m->vsync == '-')
1280                         r->v ^= 1<<4;
1281                 break;
1282         }
1283         p = &igfx->pipe[x];
1284
1285         /* plane enable, 32bpp */
1286         p->dsp->cntr.v = (1<<31) | (6<<26);
1287         if(igfx->type == TypeG45)
1288                 p->dsp->cntr.v |= x<<24;        /* pipe assign */
1289         else
1290                 p->dsp->cntr.v &= ~511; /* mbz */
1291
1292         /* stride must be 64 byte aligned */
1293         p->dsp->stride.v = m->x * (m->z / 8);
1294         p->dsp->stride.v += 63;
1295         p->dsp->stride.v &= ~63;
1296
1297         /* virtual width in pixels */
1298         vga->virtx = p->dsp->stride.v / (m->z / 8);
1299
1300         /* plane position and size */
1301         p->dsp->pos.v = 0;
1302         p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1);   /* sic */
1303
1304         p->dsp->surf.v = 0;
1305         p->dsp->linoff.v = 0;
1306         p->dsp->tileoff.v = 0;
1307         p->dsp->leftsurf.v = 0;
1308
1309         /* cursor plane off */
1310         p->cur->cntr.v = 0;
1311         if(igfx->type == TypeG45)
1312                 p->cur->cntr.v |= x<<28;        /* pipe assign */
1313         p->cur->pos.v = 0;
1314         p->cur->base.v = 0;
1315
1316         if(initdpll(igfx, x, m->frequency, port) < 0)
1317                 error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
1318
1319         initpipe(igfx, p, m, bpc, port);
1320
1321         ctlr->flag |= Finit;
1322 }
1323
1324 static void
1325 loadtrans(Igfx *igfx, Trans *t)
1326 {
1327         int i;
1328
1329         if(t->conf.a == 0)
1330                 return;
1331
1332         /* program trans/pipe timings */
1333         loadreg(igfx, t->ht);
1334         loadreg(igfx, t->hb);
1335         loadreg(igfx, t->hs);
1336         loadreg(igfx, t->vt);
1337         loadreg(igfx, t->vb);
1338         loadreg(igfx, t->vs);
1339         loadreg(igfx, t->vss);
1340
1341         loadreg(igfx, t->dm[0]);
1342         loadreg(igfx, t->dn[0]);
1343         loadreg(igfx, t->lm[0]);
1344         loadreg(igfx, t->ln[0]);
1345         loadreg(igfx, t->dm[1]);
1346         loadreg(igfx, t->dn[1]);
1347         loadreg(igfx, t->lm[1]);
1348         loadreg(igfx, t->ln[1]);
1349
1350         if(t->dpll != nil && igfx->type != TypeHSW){
1351                 /* program dpll */
1352                 t->dpll->ctrl.v &= ~(1<<31);
1353                 loadreg(igfx, t->dpll->ctrl);
1354                 loadreg(igfx, t->dpll->fp0);
1355                 loadreg(igfx, t->dpll->fp1);
1356
1357                 /* enable dpll */
1358                 t->dpll->ctrl.v |= (1<<31);
1359                 loadreg(igfx, t->dpll->ctrl);
1360                 sleep(10);
1361         }
1362
1363         /* workarround: set timing override bit */
1364         csr(igfx, t->chicken.a, 0, 1<<31);
1365
1366         /* enable displayport transcoder */
1367         loadreg(igfx, t->dpctl);
1368
1369         /* enable trans/pipe */
1370         t->conf.v |= (1<<31);
1371         t->conf.v &= ~(1<<30);
1372         loadreg(igfx, t->conf);
1373         for(i=0; i<100; i++){
1374                 sleep(10);
1375                 if(rr(igfx, t->conf.a) & (1<<30))
1376                         break;
1377         }
1378 }
1379
1380 static void
1381 enablepipe(Igfx *igfx, int x)
1382 {
1383         int i;
1384         Pipe *p;
1385
1386         p = &igfx->pipe[x];
1387         if((p->conf.v & (1<<31)) == 0)
1388                 return; /* pipe is disabled, done */
1389
1390         /* select pipe clock */
1391         loadreg(igfx, p->clksel);
1392
1393         if(p->fdi->rxctl.a != 0){
1394                 p->fdi->rxctl.v &= ~(1<<31);
1395                 p->fdi->rxctl.v &= ~(1<<4);     /* rawclk */
1396                 p->fdi->rxctl.v |= (1<<13);     /* enable pll */
1397                 loadreg(igfx, p->fdi->rxctl);
1398                 sleep(5);
1399                 p->fdi->rxctl.v |= (1<<4);      /* pcdclk */
1400                 loadreg(igfx, p->fdi->rxctl);
1401                 sleep(5);
1402                 /* clear auto training bits */
1403                 if(igfx->type == TypeSNB)
1404                         p->fdi->txctl.v &= ~(3<<28 | 1<<10 | 1);
1405                 else
1406                         p->fdi->txctl.v &= ~(7<<8 | 1);
1407                 p->fdi->txctl.v &= ~(1<<31);    /* disable */
1408                 p->fdi->txctl.v |= (1<<14);     /* enable pll */
1409                 loadreg(igfx, p->fdi->txctl);
1410                 sleep(5);
1411         }
1412
1413         /* image size (vga needs to be off) */
1414         loadreg(igfx, p->src);
1415
1416         /* set panel fitter as needed */
1417         if(p->pfit != nil){
1418                 loadreg(igfx, p->pfit->ctrl);
1419                 loadreg(igfx, p->pfit->winpos);
1420                 loadreg(igfx, p->pfit->winsize);        /* arm */
1421         }
1422
1423         /* keep planes disabled while pipe comes up */
1424         if(igfx->type == TypeG45)
1425                 p->conf.v |= 3<<18;
1426
1427         /* enable cpu pipe */
1428         loadtrans(igfx, p);
1429
1430         /* program plane */
1431         loadreg(igfx, p->dsp->cntr);
1432         loadreg(igfx, p->dsp->linoff);
1433         loadreg(igfx, p->dsp->stride);
1434         loadreg(igfx, p->dsp->tileoff);
1435         loadreg(igfx, p->dsp->size);
1436         loadreg(igfx, p->dsp->pos);
1437         loadreg(igfx, p->dsp->surf);    /* arm */
1438         loadreg(igfx, p->dsp->leftsurf);
1439
1440         /* program cursor */
1441         loadreg(igfx, p->cur->cntr);
1442         loadreg(igfx, p->cur->pos);
1443         loadreg(igfx, p->cur->base);    /* arm */
1444
1445         /* enable planes */
1446         if(igfx->type == TypeG45) {
1447                 p->conf.v &= ~(3<<18);
1448                 loadreg(igfx, p->conf);
1449         }
1450
1451         if(p->fdi->rxctl.a != 0){
1452                 /* enable fdi */
1453                 loadreg(igfx, p->fdi->rxtu[1]);
1454                 loadreg(igfx, p->fdi->rxtu[0]);
1455                 loadreg(igfx, p->fdi->rxmisc);
1456
1457                 if(igfx->type == TypeSNB){
1458                         /* unmask bit lock and symbol lock bits */
1459                         csr(igfx, p->fdi->rximr.a, 3<<8, 0);
1460
1461                         p->fdi->txctl.v &= ~(3<<28);    /* link train pattern1 */
1462                         p->fdi->txctl.v |= 1<<31;       /* enable */
1463                         loadreg(igfx, p->fdi->txctl);
1464
1465                         p->fdi->rxctl.v &= ~(3<<8);     /* link train pattern1 */
1466                         p->fdi->rxctl.v |= 1<<31;       /* enable */
1467                         loadreg(igfx, p->fdi->rxctl);
1468
1469                         /* wait for bit lock */
1470                         for(i=0; i<10; i++){
1471                                 sleep(1);
1472                                 if(rr(igfx, p->fdi->rxiir.a) & (1<<8))
1473                                         break;
1474                         }
1475                         csr(igfx, p->fdi->rxiir.a, 0, 1<<8);
1476         
1477                         /* switch to link train pattern2 */
1478                         csr(igfx, p->fdi->txctl.a, 3<<28, 1<<28);
1479                         csr(igfx, p->fdi->rxctl.a, 3<<8, 1<<8);
1480
1481                         /* wait for symbol lock */
1482                         for(i=0; i<10; i++){
1483                                 sleep(1);
1484                                 if(rr(igfx, p->fdi->rxiir.a) & (1<<9))
1485                                         break;
1486                         }
1487                         csr(igfx, p->fdi->rxiir.a, 0, 1<<9);
1488
1489                         /* switch to link train normal */
1490                         csr(igfx, p->fdi->txctl.a, 0, 3<<28);
1491                         csr(igfx, p->fdi->rxctl.a, 0, 3<<8);
1492
1493                         /* wait idle pattern time */
1494                         sleep(5);
1495                 } else {
1496                         p->fdi->rxctl.v &= ~(3<<8);     /* link train pattern 00 */
1497                         p->fdi->rxctl.v |= 1<<10;       /* auto train enable */
1498                         p->fdi->rxctl.v |= 1<<31;       /* enable */
1499                         loadreg(igfx, p->fdi->rxctl);
1500
1501                         p->fdi->txctl.v &= ~(3<<8);     /* link train pattern 00 */
1502                         p->fdi->txctl.v |= 1<<10;       /* auto train enable */
1503                         p->fdi->txctl.v |= 1<<31;       /* enable */
1504                         loadreg(igfx, p->fdi->txctl);
1505
1506                         /* wait for link training done */
1507                         for(i=0; i<200; i++){
1508                                 sleep(5);
1509                                 if(rr(igfx, p->fdi->txctl.a) & 2)
1510                                         break;
1511                         }
1512                 }
1513         }
1514
1515         /* enable the transcoder */
1516         loadtrans(igfx, p->fdi);
1517 }
1518
1519 static void
1520 disabletrans(Igfx *igfx, Trans *t)
1521 {
1522         int i;
1523
1524         /* deselect pipe clock */
1525         csr(igfx, t->clksel.a, 7<<29, 0);
1526
1527         /* disable displayport transcoder */
1528         if(igfx->type == TypeHSW){
1529                 csr(igfx, t->dpctl.a, 15<<28, 0);
1530                 csr(igfx, t->ht.a, ~0, 0);
1531                 csr(igfx, t->hb.a, ~0, 0);
1532                 csr(igfx, t->hs.a, ~0, 0);
1533                 csr(igfx, t->vt.a, ~0, 0);
1534                 csr(igfx, t->vb.a, ~0, 0);
1535                 csr(igfx, t->vs.a, ~0, 0);
1536                 csr(igfx, t->vss.a, ~0, 0);
1537         }else
1538                 csr(igfx, t->dpctl.a, 1<<31, 3<<29);
1539
1540         /* disable transcoder / pipe */
1541         csr(igfx, t->conf.a, 1<<31, 0);
1542         for(i=0; i<100; i++){
1543                 sleep(10);
1544                 if((rr(igfx, t->conf.a) & (1<<30)) == 0)
1545                         break;
1546         }
1547         /* workarround: clear timing override bit */
1548         csr(igfx, t->chicken.a, 1<<31, 0);
1549
1550         /* disable dpll  */
1551         if(igfx->type != TypeHSW && t->dpll != nil)
1552                 csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
1553 }
1554
1555 static void
1556 disablepipe(Igfx *igfx, int x)
1557 {
1558         Pipe *p;
1559
1560         p = &igfx->pipe[x];
1561
1562         /* planes off */
1563         csr(igfx, p->dsp->cntr.a, 1<<31, 0);
1564         wr(igfx, p->dsp->surf.a, 0);    /* arm */
1565         /* cursor off */
1566         if(igfx->type == TypeHSW)
1567                 csr(igfx, p->cur->cntr.a, 0x3F, 0);
1568         else
1569                 csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
1570         wr(igfx, p->cur->base.a, 0);    /* arm */
1571
1572         /* display/overlay/cursor planes off */
1573         if(igfx->type == TypeG45)
1574                 csr(igfx, p->conf.a, 0, 3<<18);
1575         csr(igfx, p->src.a, ~0, 0);
1576
1577         /* disable cpu pipe */
1578         disabletrans(igfx, p);
1579
1580         /* disable panel fitter */
1581         if(p->pfit != nil)
1582                 csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
1583
1584         /* disable fdi transmitter and receiver */
1585         csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
1586         csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
1587
1588         /* disable pch transcoder */
1589         disabletrans(igfx, p->fdi);
1590
1591         /* disable pch dpll enable bit */
1592         if(igfx->type != TypeHSW)
1593                 csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
1594 }
1595
1596 static void
1597 load(Vga* vga, Ctlr* ctlr)
1598 {
1599         Igfx *igfx;
1600         int x, y;
1601
1602         igfx = vga->private;
1603
1604         /* power lcd off */
1605         if(igfx->ppcontrol.a != 0){
1606                 csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
1607                 for(x=0; x<5000; x++){
1608                         sleep(10);
1609                         if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
1610                                 break;
1611                 }
1612         }
1613
1614         /* disable ports */
1615         csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
1616         csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
1617         csr(igfx, igfx->adpa.a, 1<<31, 0);
1618         csr(igfx, igfx->lvds.a, 1<<31, 0);
1619         for(x = 0; x < nelem(igfx->dp); x++){
1620                 csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
1621                 if(igfx->dp[x].bufctl.a != 0){
1622                         csr(igfx, igfx->dp[x].bufctl.a, 1<<31, 0);
1623                         /* wait for buffers to return to idle */
1624                         for(y=0; y<5; y++){
1625                                 sleep(10);
1626                                 if(rr(igfx, igfx->dp[x].bufctl.a) & 1<<7)
1627                                         break;
1628                         }
1629                 }
1630         }
1631         for(x = 0; x < nelem(igfx->hdmi); x++)
1632                 csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
1633
1634         /* disable vga plane */
1635         csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
1636
1637         /* turn off all pipes */
1638         for(x = 0; x < igfx->npipe; x++)
1639                 disablepipe(igfx, x);
1640
1641         if(igfx->type == TypeG45){
1642                 /* toggle dsp a on and off (from enable sequence) */
1643                 csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);
1644                 csr(igfx, igfx->pipe[0].dsp->cntr.a, 0, 1<<31);
1645                 wr(igfx, igfx->pipe[0].dsp->surf.a, 0);         /* arm */
1646                 csr(igfx, igfx->pipe[0].dsp->cntr.a, 1<<31, 0);
1647                 wr(igfx, igfx->pipe[0].dsp->surf.a, 0);         /* arm */
1648                 csr(igfx, igfx->pipe[0].conf.a, 0, 3<<18);
1649         }
1650
1651         if(igfx->type == TypeHSW){
1652                 /* deselect port clock */
1653                 for(x=0; x<nelem(igfx->dpllsel); x++)
1654                         csr(igfx, igfx->dpllsel[x].a, 0, 7<<29);
1655
1656                 /* disable dpll's other than LCPLL */
1657                 for(x=1; x<nelem(igfx->dpll); x++)
1658                         csr(igfx, igfx->dpll[x].ctrl.a, 1<<31, 0);
1659         }
1660
1661         /* program new clock sources */
1662         loadreg(igfx, igfx->rawclkfreq);
1663         loadreg(igfx, igfx->drefctl);
1664         /* program cpu pll */
1665         if(igfx->type == TypeHSW)
1666                 for(x=0; x<nelem(igfx->dpll); x++)
1667                         loadreg(igfx, igfx->dpll[x].ctrl);
1668         sleep(10);
1669
1670         /* set lvds before enabling dpll */
1671         loadreg(igfx, igfx->lvds);
1672
1673         /* new dpll setting */
1674         for(x=0; x<nelem(igfx->dpllsel); x++)
1675                 loadreg(igfx, igfx->dpllsel[x]);
1676
1677         /* program all pipes */
1678         for(x = 0; x < igfx->npipe; x++)
1679                 enablepipe(igfx, x);
1680
1681         /* program vga plane */
1682         loadreg(igfx, igfx->vgacntrl);
1683
1684         /* program ports */
1685         loadreg(igfx, igfx->adpa);
1686         loadreg(igfx, igfx->sdvob);
1687         loadreg(igfx, igfx->sdvoc);
1688         for(x = 0; x < nelem(igfx->dp); x++){
1689                 for(y=0; y<nelem(igfx->dp[x].buftrans); y++)
1690                         loadreg(igfx, igfx->dp[x].buftrans[y]);
1691                 loadreg(igfx, igfx->dp[x].bufctl);
1692                 if(enabledp(igfx, &igfx->dp[x]) < 0)
1693                         ctlr->flag |= Ferror;
1694         }
1695
1696         /* program lcd power */
1697         loadreg(igfx, igfx->ppcontrol);
1698
1699         ctlr->flag |= Fload;
1700 }
1701
1702 static void
1703 dumpreg(char *name, char *item, Reg r)
1704 {
1705         if(r.a == 0)
1706                 return;
1707
1708         printitem(name, item);
1709         Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
1710 }
1711
1712 static void
1713 dumphex(char *name, char *item, uchar *data, int len)
1714 {
1715         int i;
1716
1717         for(i=0; i<len; i++){
1718                 if((i & 15) == 0){
1719                         if(i > 0)
1720                                 Bprint(&stdout, "\n");
1721                         printitem(name, item);
1722                         Bprint(&stdout, " [%.2x] =", i);
1723                 }
1724                 Bprint(&stdout, " %.2X", data[i]);
1725         }
1726         Bprint(&stdout, "\n");
1727 }
1728
1729 static void
1730 dumptiming(char *name, Trans *t)
1731 {
1732         int tu, m, n;
1733
1734         if(t->dm[0].a != 0 && t->dm[0].v != 0){
1735                 tu = 1+((t->dm[0].v >> 25) & 0x3f);
1736                 printitem(name, "dm1 tu");
1737                 Bprint(&stdout, " %d\n", tu);
1738
1739                 m = t->dm[0].v & 0xffffff;
1740                 n = t->dn[0].v;
1741                 if(n > 0){
1742                         printitem(name, "dm1/dn1");
1743                         Bprint(&stdout, " %f\n", (double)m / (double)n);
1744                 }
1745
1746                 m = t->lm[0].v;
1747                 n = t->ln[0].v;
1748                 if(n > 0){
1749                         printitem(name, "lm1/ln1");
1750                         Bprint(&stdout, " %f\n", (double)m / (double)n);
1751                 }
1752         }
1753 }
1754
1755 static void
1756 dumptrans(char *name, Trans *t)
1757 {
1758         dumpreg(name, "conf", t->conf);
1759
1760         dumpreg(name, "dm1", t->dm[0]);
1761         dumpreg(name, "dn1", t->dn[0]);
1762         dumpreg(name, "lm1", t->lm[0]);
1763         dumpreg(name, "ln1", t->ln[0]);
1764         dumpreg(name, "dm2", t->dm[1]);
1765         dumpreg(name, "dn2", t->dn[1]);
1766         dumpreg(name, "lm2", t->lm[1]);
1767         dumpreg(name, "ln2", t->ln[1]);
1768
1769         dumptiming(name, t);
1770
1771         dumpreg(name, "ht", t->ht);
1772         dumpreg(name, "hb", t->hb);
1773         dumpreg(name, "hs", t->hs);
1774
1775         dumpreg(name, "vt", t->vt);
1776         dumpreg(name, "vb", t->vb);
1777         dumpreg(name, "vs", t->vs);
1778         dumpreg(name, "vss", t->vss);
1779
1780         dumpreg(name, "dpctl", t->dpctl);
1781         dumpreg(name, "clksel", t->clksel);
1782 }
1783
1784 static void
1785 dumppipe(Igfx *igfx, int x)
1786 {
1787         char name[32];
1788         Pipe *p;
1789
1790         p = &igfx->pipe[x];
1791
1792         snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
1793         dumpreg(name, "src", p->src);
1794         dumptrans(name, p);
1795
1796         snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
1797         dumptrans(name, p->fdi);
1798         dumpreg(name, "txctl", p->fdi->txctl);
1799         dumpreg(name, "rxctl", p->fdi->rxctl);
1800         dumpreg(name, "rxmisc", p->fdi->rxmisc);
1801         dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
1802         dumpreg(name, "rxtu2", p->fdi->rxtu[1]);
1803
1804         snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
1805         dumpreg(name, "cntr", p->dsp->cntr);
1806         dumpreg(name, "linoff", p->dsp->linoff);
1807         dumpreg(name, "stride", p->dsp->stride);
1808         dumpreg(name, "surf", p->dsp->surf);
1809         dumpreg(name, "tileoff", p->dsp->tileoff);
1810         dumpreg(name, "leftsurf", p->dsp->leftsurf);
1811         dumpreg(name, "pos", p->dsp->pos);
1812         dumpreg(name, "size", p->dsp->size);
1813
1814         snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
1815         dumpreg(name, "cntr", p->cur->cntr);
1816         dumpreg(name, "base", p->cur->base);
1817         dumpreg(name, "pos", p->cur->pos);
1818 }
1819
1820 static void
1821 dumpdpll(Igfx *igfx, int x)
1822 {
1823         int cref, m1, m2, n, p1, p2;
1824         uvlong freq;
1825         char name[32];
1826         Dpll *dpll;
1827         u32int m;
1828
1829         dpll = &igfx->dpll[x];
1830         snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
1831
1832         dumpreg(name, "ctrl", dpll->ctrl);
1833         dumpreg(name, "fp0", dpll->fp0);
1834         dumpreg(name, "fp1", dpll->fp1);
1835
1836         if(igfx->type == TypeHSW)
1837                 return;
1838
1839         p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
1840         if(((dpll->ctrl.v >> 24) & 3) == 1)
1841                 p2 >>= 1;
1842         m = (dpll->ctrl.v >> 16) & 0xFF;
1843         for(p1 = 1; p1 <= 8; p1++)
1844                 if(m & (1<<(p1-1)))
1845                         break;
1846         printitem(name, "ctrl p1");
1847         Bprint(&stdout, " %d\n", p1);
1848         printitem(name, "ctrl p2");
1849         Bprint(&stdout, " %d\n", p2);
1850
1851         n = (dpll->fp0.v >> 16) & 0x3f;
1852         m1 = (dpll->fp0.v >> 8) & 0x3f;
1853         m2 = (dpll->fp0.v >> 0) & 0x3f;
1854
1855         cref = getcref(igfx, x);
1856         freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
1857
1858         printitem(name, "fp0 m1");
1859         Bprint(&stdout, " %d\n", m1);
1860         printitem(name, "fp0 m2");
1861         Bprint(&stdout, " %d\n", m2);
1862         printitem(name, "fp0 n");
1863         Bprint(&stdout, " %d\n", n);
1864
1865         printitem(name, "cref");
1866         Bprint(&stdout, " %d\n", cref);
1867         printitem(name, "fp0 freq");
1868         Bprint(&stdout, " %lld\n", freq);
1869 }
1870
1871 static void
1872 dump(Vga* vga, Ctlr* ctlr)
1873 {
1874         char name[32];
1875         Igfx *igfx;
1876         int x, y;
1877
1878         if((igfx = vga->private) == nil)
1879                 return;
1880
1881         for(x=0; x<igfx->npipe; x++)
1882                 dumppipe(igfx, x);
1883
1884         for(x=0; x<nelem(igfx->dpll); x++)
1885                 dumpdpll(igfx, x);
1886
1887         for(x=0; x<nelem(igfx->dpllsel); x++){
1888                 snprint(name, sizeof(name), "%s dpllsel %c", ctlr->name, 'a'+x);
1889                 dumpreg(name, "dpllsel", igfx->dpllsel[x]);
1890         }
1891
1892         dumpreg(ctlr->name, "drefctl", igfx->drefctl);
1893         dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
1894         dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
1895
1896         for(x=0; x<nelem(igfx->dp); x++){
1897                 if(igfx->dp[x].ctl.a == 0)
1898                         continue;
1899                 snprint(name, sizeof(name), "%s dp %c", ctlr->name, 'a'+x);
1900                 dumpreg(name, "ctl", igfx->dp[x].ctl);
1901                 dumpreg(name, "bufctl", igfx->dp[x].bufctl);
1902                 dumpreg(name, "stat", igfx->dp[x].stat);
1903                 dumphex(name, "dpcd", igfx->dp[x].dpcd, sizeof(igfx->dp[x].dpcd));
1904                 for(y=0; y<nelem(igfx->dp[x].buftrans); y++){
1905                         snprint(name, sizeof(name), "%s buftrans %c %d", ctlr->name, 'a'+x, y);
1906                         dumpreg(name, "ctl", igfx->dp[x].buftrans[y]);
1907                 }
1908         }
1909         for(x=0; x<nelem(igfx->hdmi); x++){
1910                 snprint(name, sizeof(name), "%s hdmi %c", ctlr->name, 'a'+x);
1911                 dumpreg(name, "ctl", igfx->hdmi[x].ctl);
1912         }
1913
1914         for(x=0; x<nelem(igfx->pfit); x++){
1915                 snprint(name, sizeof(name), "%s pfit %c", ctlr->name, 'a'+x);
1916                 dumpreg(name, "ctrl", igfx->pfit[x].ctrl);
1917                 dumpreg(name, "winpos", igfx->pfit[x].winpos);
1918                 dumpreg(name, "winsize", igfx->pfit[x].winsize);
1919                 dumpreg(name, "pwrgate", igfx->pfit[x].pwrgate);
1920         }
1921
1922         dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
1923         dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);
1924
1925         dumpreg(ctlr->name, "adpa", igfx->adpa);
1926         dumpreg(ctlr->name, "lvds", igfx->lvds);
1927         dumpreg(ctlr->name, "sdvob", igfx->sdvob);
1928         dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
1929
1930         dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
1931 }
1932
1933 static int
1934 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
1935 {
1936         int t, i;
1937         u32int w;
1938
1939         if(dp->auxctl.a == 0){
1940                 werrstr("not present");
1941                 return -1;
1942         }
1943
1944         t = 0;
1945         while(rr(igfx, dp->auxctl.a) & (1<<31)){
1946                 if(++t >= 10){
1947                         werrstr("busy");
1948                         return -1;
1949                 }
1950                 sleep(5);
1951         }
1952
1953         /* clear sticky bits */
1954         wr(igfx, dp->auxctl.a, (1<<28) | (1<<25) | (1<<30));
1955
1956         for(i=0; i<nelem(dp->auxdat); i++){
1957                 w  = buf[i*4+0]<<24;
1958                 w |= buf[i*4+1]<<16;
1959                 w |= buf[i*4+2]<<8;
1960                 w |= buf[i*4+3];
1961                 wr(igfx, dp->auxdat[i].a, w);
1962         }
1963
1964         /* 2X Bit Clock divider */
1965         w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3ff)) >> 1;
1966         if(w < 1 || w > 0x3fd){
1967                 werrstr("bad clock");
1968                 return -1;
1969         }
1970
1971         /* hack: slow down a bit */
1972         w += 2;
1973
1974         w |= 1<<31;     /* SendBusy */
1975         w |= 1<<29;     /* interrupt disabled */
1976         w |= 3<<26;     /* timeout 1600µs */
1977         w |= len<<20;   /* send bytes */
1978         w |= 5<<16;     /* precharge time (5*2 = 10µs) */
1979         wr(igfx, dp->auxctl.a, w);
1980
1981         t = 0;
1982         for(;;){
1983                 w = rr(igfx, dp->auxctl.a);
1984                 if((w & (1<<30)) != 0)
1985                         break;
1986                 if(++t >= 10){
1987                         werrstr("busy");
1988                         return -1;
1989                 }
1990                 sleep(5);
1991         }
1992         if(w & (1<<28)){
1993                 werrstr("receive timeout");
1994                 return -1;
1995         }
1996         if(w & (1<<25)){
1997                 werrstr("receive error");
1998                 return -1;
1999         }
2000
2001         len = (w >> 20) & 0x1f;
2002         for(i=0; i<nelem(dp->auxdat); i++){
2003                 w = rr(igfx, dp->auxdat[i].a);
2004                 buf[i*4+0] = w>>24;
2005                 buf[i*4+1] = w>>16;
2006                 buf[i*4+2] = w>>8;
2007                 buf[i*4+3] = w;
2008         }
2009
2010         return len;
2011 }
2012
2013 enum {
2014         CmdNative       = 8,
2015         CmdMot          = 4,
2016         CmdRead         = 1,
2017         CmdWrite        = 0,
2018 };
2019
2020 static int
2021 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
2022 {
2023         uchar buf[20];
2024         int r;
2025
2026         assert(len <= 16);
2027
2028         memset(buf, 0, sizeof(buf));
2029         buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
2030         buf[1] = addr >> 8;
2031         buf[2] = addr;
2032         buf[3] = len-1;
2033         r = 3;  
2034         if(data != nil && len > 0){
2035                 if((cmd & CmdRead) == 0)
2036                         memmove(buf+4, data, len);
2037                 r = 4;
2038                 if((cmd & CmdRead) == 0)
2039                         r += len;
2040         }
2041         if((r = dpauxio(igfx, dp, buf, r)) < 0){
2042                 trace("%s: dpauxio: dp %c, cmd %x, addr %x, len %d: %r\n",
2043                         igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]), cmd, addr, len);
2044                 return -1;
2045         }
2046         if(r == 0 || data == nil || len == 0)
2047                 return 0;
2048         if((cmd & CmdRead) != 0){
2049                 if(--r < len)
2050                         len = r;
2051                 memmove(data, buf+1, len);
2052         }
2053         return len;
2054 }
2055
2056 static int
2057 rdpaux(Igfx *igfx, Dp *dp, int addr)
2058 {
2059         uchar buf[1];
2060         if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
2061                 return -1;
2062         return buf[0];
2063 }
2064 static int
2065 wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
2066 {
2067         if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
2068                 return -1;
2069         return 0;
2070 }
2071
2072 static int
2073 enabledp(Igfx *igfx, Dp *dp)
2074 {
2075         int try, r;
2076         u32int w;
2077
2078         if(dp->ctl.a == 0)
2079                 return 0;
2080         if((dp->ctl.v & (1<<31)) == 0)
2081                 return 0;
2082
2083         /* FIXME: always times out */
2084         if(igfx->type == TypeHSW && dp == &igfx->dp[0])
2085                 goto Skip;
2086
2087         /* Link configuration */
2088         wdpaux(igfx, dp, 0x100, (270*MHz) / 27000000);
2089         w = dp->ctl.v >> (igfx->type == TypeHSW ? 1 : 19) & 7;
2090         wdpaux(igfx, dp, 0x101, w+1);
2091
2092         r = 0;
2093
2094         /* Link training pattern 1 */
2095         dp->ctl.v &= ~(7<<8);
2096         loadreg(igfx, dp->ctl);
2097         for(try = 0;;try++){
2098                 if(try > 5)
2099                         goto Fail;
2100                 /* Link training pattern 1 */
2101                 wdpaux(igfx, dp, 0x102, 0x01);
2102                 sleep(100);
2103                 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2104                         goto Fail;
2105                 if(r & 1)       /* LANE0_CR_DONE */
2106                         break;
2107         }
2108         trace("pattern1 finished: %x\n", r);
2109
2110         /* Link training pattern 2 */
2111         dp->ctl.v &= ~(7<<8);
2112         dp->ctl.v |= 1<<8;
2113         loadreg(igfx, dp->ctl);
2114         for(try = 0;;try++){
2115                 if(try > 5)
2116                         goto Fail;
2117                 /* Link training pattern 2 */
2118                 wdpaux(igfx, dp, 0x102, 0x02);
2119                 sleep(100);
2120                 if((r = rdpaux(igfx, dp, 0x202)) < 0)
2121                         goto Fail;
2122                 if((r & 7) == 7)
2123                         break;
2124         }
2125         trace("pattern2 finished: %x\n", r);
2126
2127         if(igfx->type == TypeHSW){
2128                 /* set link training to idle pattern and wait for 5 idle
2129                  * patterns */
2130                 dp->ctl.v &= ~(7<<8);
2131                 dp->ctl.v |= 2<<8;
2132                 loadreg(igfx, dp->ctl);
2133                 for(try=0; try<10; try++){
2134                         sleep(10);
2135                         if(rr(igfx, dp->stat.a) & (1<<25))
2136                                 break;
2137                 }
2138         }
2139 Skip:
2140         /* stop training */
2141         dp->ctl.v &= ~(7<<8);
2142         dp->ctl.v |= 3<<8;
2143         loadreg(igfx, dp->ctl);
2144         wdpaux(igfx, dp, 0x102, 0x00);
2145         return 1;
2146
2147 Fail:
2148         trace("training failed: %x\n", r);
2149
2150         /* disable port */
2151         dp->ctl.v &= ~(1<<31);
2152         loadreg(igfx, dp->ctl);
2153         wdpaux(igfx, dp, 0x102, 0x00);
2154         return -1;
2155 }
2156
2157 static uchar*
2158 edidshift(uchar buf[256])
2159 {
2160         uchar tmp[256];
2161         int i;
2162
2163         /* shift if neccesary so edid block is at the start */
2164         for(i=0; i<256-8; i++){
2165                 if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
2166                 && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
2167                         memmove(tmp, buf, i);
2168                         memmove(buf, buf + i, 256 - i);
2169                         memmove(buf + (256 - i), tmp, i);
2170                         break;
2171                 }
2172         }
2173         return buf;
2174 }
2175
2176 static Edid*
2177 snarfdpedid(Igfx *igfx, Dp *dp, int addr)
2178 {
2179         uchar buf[256];
2180         int i;
2181         Edid *e;
2182
2183         for(i=0; i<sizeof(dp->dpcd); i+=16)
2184                 if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
2185                         return nil;
2186
2187         if(dp->dpcd[0] == 0)    /* nothing there, dont try to get edid */
2188                 return nil;
2189
2190         if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
2191                 return nil;
2192
2193         for(i=0; i<sizeof(buf); i+=16){
2194                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2195                         continue;
2196                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2197                         continue;
2198                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2199                         continue;
2200                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2201                         continue;
2202                 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
2203                         continue;
2204                 return nil;
2205         }
2206
2207         dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
2208
2209         if((e = parseedid128(edidshift(buf))) == nil)
2210                 trace("%s: snarfdpedid: dp %c: %r\n", igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]));
2211         return e;
2212 }
2213
2214 enum {
2215         GMBUSCP = 0,    /* Clock/Port selection */
2216         GMBUSCS = 1,    /* Command/Status */
2217         GMBUSST = 2,    /* Status Register */
2218         GMBUSDB = 3,    /* Data Buffer Register */
2219         GMBUSIM = 4,    /* Interrupt Mask */
2220         GMBUSIX = 5,    /* Index Register */
2221 };
2222         
2223 static int
2224 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
2225 {
2226         u32int x, y;
2227         int n, t;
2228
2229         if(igfx->gmbus[GMBUSCP].a == 0)
2230                 return -1;
2231
2232         wr(igfx, igfx->gmbus[GMBUSCP].a, port);
2233         wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
2234
2235         /* bus cycle without index and stop, byte count, slave address, read */
2236         wr(igfx, igfx->gmbus[GMBUSCS].a, 1<<30 | 5<<25 | len<<16 | addr<<1 | 1);
2237
2238         n = 0;
2239         while(len > 0){
2240                 x = 0;
2241                 for(t=0; t<100; t++){
2242                         x = rr(igfx, igfx->gmbus[GMBUSST].a);
2243                         if(x & (1<<11))
2244                                 break;
2245                         sleep(5);
2246                 }
2247                 if((x & (1<<11)) == 0)
2248                         return -1;
2249
2250                 t = 4 - (x & 3);
2251                 if(t > len)
2252                         t = len;
2253                 len -= t;
2254
2255                 y = rr(igfx, igfx->gmbus[GMBUSDB].a);
2256                 switch(t){
2257                 case 4:
2258                         data[n++] = y & 0xff, y >>= 8;
2259                 case 3:
2260                         data[n++] = y & 0xff, y >>= 8;
2261                 case 2:
2262                         data[n++] = y & 0xff, y >>= 8;
2263                 case 1:
2264                         data[n++] = y & 0xff;
2265                 }
2266         }
2267
2268         return n;
2269 }
2270
2271 static Edid*
2272 snarfgmedid(Igfx *igfx, int port, int addr)
2273 {
2274         uchar buf[256];
2275
2276         /* read twice */
2277         if(gmbusread(igfx, port, addr, buf, 128) != 128)
2278                 return nil;
2279         if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
2280                 return nil;
2281
2282         return parseedid128(edidshift(buf));
2283 }
2284
2285 Ctlr igfx = {
2286         "igfx",                 /* name */
2287         snarf,                  /* snarf */
2288         options,                /* options */
2289         init,                   /* init */
2290         load,                   /* load */
2291         dump,                   /* dump */
2292 };
2293
2294 Ctlr igfxhwgc = {
2295         "igfxhwgc",
2296 };