changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/aux/vga/igfx.c

changeset 4350: 1f9d7811d546
parent: eeef5069dd14
child: 4ca4a7b1282e
author: cinap_lenrek@felloff.net
date: Mon, 16 Mar 2015 05:46:08 +0100
permissions: -rw-r--r--
description: kernel: get rid of auxpage() and preserve cache index bits in Page.va in mount cache

the mount cache uses Page.va to store cached range offset and
limit, but mips kernel uses cache index bits from Page.va to
maintain page coloring. Page.va was not initialized by auxpage().

this change removes auxpage() which was primarily used only
by the mount cache and use newpage() with cache file offset
page as va so we will get a page of the right color.

mount cache keeps the index bits intact by only using the top
and buttom PGSHIFT bits of Page.va for the range offset/limit.
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 };
28 
29 enum {
30  PortVGA = 0, /* adpa */
31  PortLCD = 1, /* lvds */
32  PortDPA = 2,
33  PortDPB = 3,
34  PortDPC = 4,
35  PortDPD = 5,
36 };
37 
38 struct Reg {
39  u32int a; /* address or 0 when invalid */
40  u32int v; /* value */
41 };
42 
43 struct Dpll {
44  Reg ctrl; /* DPLLx_CTRL */
45  Reg fp0; /* FPx0 */
46  Reg fp1; /* FPx1 */
47 };
48 
49 struct Trans {
50  Reg dm[2]; /* pipe/trans DATAM */
51  Reg dn[2]; /* pipe/trans DATAN */
52  Reg lm[2]; /* pipe/trans LINKM */
53  Reg ln[2]; /* pipe/trans LINKN */
54 
55  Reg ht; /* pipe/trans HTOTAL_x */
56  Reg hb; /* pipe/trans HBLANK_x */
57  Reg hs; /* pipe/trans HSYNC_x */
58  Reg vt; /* pipe/trans VTOTAL_x */
59  Reg vb; /* pipe/trans VBLANK_x */
60  Reg vs; /* pipe/trans VSYNC_x */
61  Reg vss; /* pipe/trans VSYNCSHIFT_x */
62 
63  Reg conf; /* pipe/trans CONF_x */
64  Reg chicken; /* workarround register */
65 
66  Reg dpctl; /* TRANS_DP_CTL_x */
67 
68  Dpll *dpll; /* this transcoders dpll */
69 };
70 
71 struct Hdmi {
72  Reg ctl;
73  Reg bufctl[4];
74 };
75 
76 struct Dp {
77  Reg ctl;
78  Reg auxctl;
79  Reg auxdat[5];
80 
81  uchar dpcd[256];
82 };
83 
84 struct Fdi {
85  Trans;
86 
87  Reg txctl; /* FDI_TX_CTL */
88 
89  Reg rxctl; /* FDI_RX_CTL */
90  Reg rxmisc; /* FDI_RX_MISC */
91  Reg rxtu[2]; /* FDI_RX_TUSIZE */
92 };
93 
94 struct Pfit {
95  Reg ctrl;
96  Reg winpos;
97  Reg winsize;
98  Reg pwrgate;
99 };
100 
101 struct Plane {
102  Reg cntr; /* DSPxCNTR */
103  Reg linoff; /* DSPxLINOFF */
104  Reg stride; /* DSPxSTRIDE */
105  Reg surf; /* DSPxSURF */
106  Reg tileoff; /* DSPxTILEOFF */
107 
108  Reg pos;
109  Reg size;
110 };
111 
112 struct Curs {
113  Reg cntr;
114  Reg base;
115  Reg pos;
116 };
117 
118 struct Pipe {
119  Trans;
120 
121  Reg src; /* PIPExSRC */
122 
123  Fdi fdi[1]; /* fdi/dp transcoder */
124 
125  Plane dsp[1]; /* display plane */
126  Curs cur[1]; /* hardware cursor */
127 
128  Pfit *pfit; /* selected panel fitter */
129 };
130 
131 struct Igfx {
132  Ctlr *ctlr;
133  Pcidev *pci;
134 
135  u32int pio;
136  u32int *mmio;
137 
138  int type;
139  int cdclk; /* core display clock in mhz */
140 
141  int npipe;
142  Pipe pipe[4];
143 
144  Dpll dpll[2];
145  Pfit pfit[3];
146 
147  /* IVB */
148  Reg dpllsel; /* DPLL_SEL */
149  Reg drefctl; /* DREF_CTL */
150  Reg rawclkfreq; /* RAWCLK_FREQ */
151  Reg ssc4params; /* SSC4_PARAMS */
152 
153  Dp dp[4];
154  Hdmi hdmi[4];
155 
156  Reg ppcontrol;
157  Reg ppstatus;
158 
159  /* G45 */
160  Reg gmbus[6]; /* GMBUSx */
161 
162  Reg sdvoc;
163  Reg sdvob;
164 
165  /* common */
166  Reg adpa;
167  Reg lvds;
168 
169  Reg vgacntrl;
170 };
171 
172 static u32int
173 rr(Igfx *igfx, u32int a)
174 {
175  if(a == 0)
176  return 0;
177  assert((a & 3) == 0);
178  if(igfx->mmio != nil)
179  return igfx->mmio[a/4];
180  outportl(igfx->pio, a);
181  return inportl(igfx->pio + 4);
182 }
183 static void
184 wr(Igfx *igfx, u32int a, u32int v)
185 {
186  if(a == 0) /* invalid */
187  return;
188  assert((a & 3) == 0);
189  if(igfx->mmio != nil){
190  igfx->mmio[a/4] = v;
191  return;
192  }
193  outportl(igfx->pio, a);
194  outportl(igfx->pio + 4, v);
195 }
196 static void
197 csr(Igfx *igfx, u32int reg, u32int clr, u32int set)
198 {
199  wr(igfx, reg, (rr(igfx, reg) & ~clr) | set);
200 }
201 
202 static void
203 loadreg(Igfx *igfx, Reg r)
204 {
205  wr(igfx, r.a, r.v);
206 }
207 
208 static Reg
209 snarfreg(Igfx *igfx, u32int a)
210 {
211  Reg r;
212 
213  r.a = a;
214  r.v = rr(igfx, a);
215  return r;
216 }
217 
218 static void
219 snarftrans(Igfx *igfx, Trans *t, u32int o)
220 {
221  /* pipe timing */
222  t->ht = snarfreg(igfx, o + 0x00000);
223  t->hb = snarfreg(igfx, o + 0x00004);
224  t->hs = snarfreg(igfx, o + 0x00008);
225  t->vt = snarfreg(igfx, o + 0x0000C);
226  t->vb = snarfreg(igfx, o + 0x00010);
227  t->vs = snarfreg(igfx, o + 0x00014);
228  t->vss = snarfreg(igfx, o + 0x00028);
229 
230  t->conf = snarfreg(igfx, o + 0x10008);
231 
232  switch(igfx->type){
233  case TypeG45:
234  if(t == &igfx->pipe[0]){ /* PIPEA */
235  t->dm[0] = snarfreg(igfx, 0x70050); /* GMCHDataM */
236  t->dn[0] = snarfreg(igfx, 0x70054); /* GMCHDataN */
237  t->lm[0] = snarfreg(igfx, 0x70060); /* DPLinkM */
238  t->ln[0] = snarfreg(igfx, 0x70064); /* DPLinkN */
239  }
240  break;
241  case TypeIVB:
242  t->dm[0] = snarfreg(igfx, o + 0x30);
243  t->dn[0] = snarfreg(igfx, o + 0x34);
244  t->dm[1] = snarfreg(igfx, o + 0x38);
245  t->dn[1] = snarfreg(igfx, o + 0x3c);
246  t->lm[0] = snarfreg(igfx, o + 0x40);
247  t->ln[0] = snarfreg(igfx, o + 0x44);
248  t->lm[1] = snarfreg(igfx, o + 0x48);
249  t->ln[1] = snarfreg(igfx, o + 0x4c);
250  break;
251  }
252 }
253 
254 static void
255 snarfpipe(Igfx *igfx, int x)
256 {
257  u32int o;
258  Pipe *p;
259 
260  p = &igfx->pipe[x];
261 
262  o = 0x60000 + x*0x1000;
263  snarftrans(igfx, p, o);
264 
265  p->src = snarfreg(igfx, o + 0x0001C);
266 
267  if(igfx->type == TypeIVB) {
268  p->fdi->txctl = snarfreg(igfx, o + 0x100);
269 
270  o = 0xE0000 | x*0x1000;
271  snarftrans(igfx, p->fdi, o);
272 
273  p->fdi->dpctl = snarfreg(igfx, o + 0x300);
274 
275  p->fdi->rxctl = snarfreg(igfx, o + 0x1000c);
276  p->fdi->rxmisc = snarfreg(igfx, o + 0x10010);
277  p->fdi->rxtu[0] = snarfreg(igfx, o + 0x10030);
278  p->fdi->rxtu[1] = snarfreg(igfx, o + 0x10038);
279 
280  p->fdi->chicken = snarfreg(igfx, o + 0x10064);
281 
282  p->fdi->dpll = &igfx->dpll[(igfx->dpllsel.v>>(x*4)) & 1];
283  p->dpll = nil;
284  } else {
285  p->dpll = &igfx->dpll[x & 1];
286  }
287 
288  /* display plane */
289  p->dsp->cntr = snarfreg(igfx, 0x70180 + x*0x1000);
290  p->dsp->linoff = snarfreg(igfx, 0x70184 + x*0x1000);
291  p->dsp->stride = snarfreg(igfx, 0x70188 + x*0x1000);
292  p->dsp->tileoff = snarfreg(igfx, 0x701A4 + x*0x1000);
293  p->dsp->surf = snarfreg(igfx, 0x7019C + x*0x1000);
294 
295  /* cursor plane */
296  switch(igfx->type){
297  case TypeIVB:
298  p->cur->cntr = snarfreg(igfx, 0x70080 + x*0x1000);
299  p->cur->base = snarfreg(igfx, 0x70084 + x*0x1000);
300  p->cur->pos = snarfreg(igfx, 0x70088 + x*0x1000);
301  break;
302  case TypeG45:
303  p->dsp->pos = snarfreg(igfx, 0x7018C + x*0x1000);
304  p->dsp->size = snarfreg(igfx, 0x70190 + x*0x1000);
305 
306  p->cur->cntr = snarfreg(igfx, 0x70080 + x*0x40);
307  p->cur->base = snarfreg(igfx, 0x70084 + x*0x40);
308  p->cur->pos = snarfreg(igfx, 0x70088 + x*0x40);
309  break;
310  }
311 }
312 
313 static int
314 devtype(Igfx *igfx)
315 {
316  if(igfx->pci->vid != 0x8086)
317  return -1;
318  switch(igfx->pci->did){
319  case 0x0166: /* 3rd Gen Core - ThinkPad X230 */
320  return TypeIVB;
321  case 0x27a2: /* GM945/82940GML - ThinkPad X60 Tablet */
322  case 0x2a02: /* GM965/GL960/X3100 - ThinkPad X61 Tablet */
323  case 0x2a42: /* 4 Series Mobile - ThinkPad X200 */
324  return TypeG45;
325  }
326  return -1;
327 }
328 
329 static Edid* snarfgmedid(Igfx*, int port, int addr);
330 static Edid* snarfdpedid(Igfx*, Dp *dp, int addr);
331 
332 static int enabledp(Igfx*, Dp*);
333 
334 static void
335 snarf(Vga* vga, Ctlr* ctlr)
336 {
337  Igfx *igfx;
338  int x, y;
339 
340  igfx = vga->private;
341  if(igfx == nil) {
342  igfx = alloc(sizeof(Igfx));
343  igfx->ctlr = ctlr;
344  igfx->pci = vga->pci;
345  if(igfx->pci == nil){
346  error("%s: no pci device\n", ctlr->name);
347  return;
348  }
349  igfx->type = devtype(igfx);
350  if(igfx->type < 0){
351  error("%s: unrecognized device\n", ctlr->name);
352  return;
353  }
354  vgactlpci(igfx->pci);
355  if(1){
356  vgactlw("type", ctlr->name);
357  igfx->mmio = segattach(0, "igfxmmio", 0, igfx->pci->mem[0].size);
358  if(igfx->mmio == (u32int*)-1)
359  error("%s: attaching mmio: %r\n", ctlr->name);
360  } else {
361  if((igfx->pci->mem[4].bar & 1) == 0)
362  error("%s: no pio bar\n", ctlr->name);
363  igfx->pio = igfx->pci->mem[4].bar & ~1;
364  }
365  vga->private = igfx;
366  }
367 
368  switch(igfx->type){
369  case TypeG45:
370  igfx->npipe = 2; /* A,B */
371  igfx->cdclk = 200; /* MHz */
372 
373  igfx->dpll[0].ctrl = snarfreg(igfx, 0x06014);
374  igfx->dpll[0].fp0 = snarfreg(igfx, 0x06040);
375  igfx->dpll[0].fp1 = snarfreg(igfx, 0x06044);
376  igfx->dpll[1].ctrl = snarfreg(igfx, 0x06018);
377  igfx->dpll[1].fp0 = snarfreg(igfx, 0x06048);
378  igfx->dpll[1].fp1 = snarfreg(igfx, 0x0604c);
379 
380  igfx->adpa = snarfreg(igfx, 0x061100);
381  igfx->lvds = snarfreg(igfx, 0x061180);
382  igfx->sdvob = snarfreg(igfx, 0x061140);
383  igfx->sdvoc = snarfreg(igfx, 0x061160);
384 
385  for(x=0; x<5; x++)
386  igfx->gmbus[x] = snarfreg(igfx, 0x5100 + x*4);
387  igfx->gmbus[x] = snarfreg(igfx, 0x5120);
388 
389  igfx->pfit[0].ctrl = snarfreg(igfx, 0x061230);
390  y = (igfx->pfit[0].ctrl.v >> 29) & 3;
391  if(igfx->pipe[y].pfit == nil)
392  igfx->pipe[y].pfit = &igfx->pfit[0];
393 
394  igfx->ppstatus = snarfreg(igfx, 0x61200);
395  igfx->ppcontrol = snarfreg(igfx, 0x61204);
396 
397  igfx->vgacntrl = snarfreg(igfx, 0x071400);
398  break;
399 
400  case TypeIVB:
401  igfx->npipe = 3; /* A,B,C */
402  igfx->cdclk = 400; /* MHz */
403 
404  igfx->dpll[0].ctrl = snarfreg(igfx, 0xC6014);
405  igfx->dpll[0].fp0 = snarfreg(igfx, 0xC6040);
406  igfx->dpll[0].fp1 = snarfreg(igfx, 0xC6044);
407  igfx->dpll[1].ctrl = snarfreg(igfx, 0xC6018);
408  igfx->dpll[1].fp0 = snarfreg(igfx, 0xC6048);
409  igfx->dpll[1].fp1 = snarfreg(igfx, 0xC604c);
410 
411  igfx->dpllsel = snarfreg(igfx, 0xC7000);
412 
413  igfx->drefctl = snarfreg(igfx, 0xC6200);
414  igfx->rawclkfreq = snarfreg(igfx, 0xC6204);
415  igfx->ssc4params = snarfreg(igfx, 0xC6210);
416 
417  /* cpu displayport A */
418  igfx->dp[0].ctl = snarfreg(igfx, 0x64000);
419  igfx->dp[0].auxctl = snarfreg(igfx, 0x64010);
420  igfx->dp[0].auxdat[0] = snarfreg(igfx, 0x64014);
421  igfx->dp[0].auxdat[1] = snarfreg(igfx, 0x64018);
422  igfx->dp[0].auxdat[2] = snarfreg(igfx, 0x6401C);
423  igfx->dp[0].auxdat[3] = snarfreg(igfx, 0x64020);
424  igfx->dp[0].auxdat[4] = snarfreg(igfx, 0x64024);
425 
426  /* pch displayport B,C,D */
427  for(x=1; x<4; x++){
428  igfx->dp[x].ctl = snarfreg(igfx, 0xE4000 + 0x100*x);
429  igfx->dp[x].auxctl = snarfreg(igfx, 0xE4010 + 0x100*x);
430  igfx->dp[x].auxdat[0] = snarfreg(igfx, 0xE4014 + 0x100*x);
431  igfx->dp[x].auxdat[1] = snarfreg(igfx, 0xE4018 + 0x100*x);
432  igfx->dp[x].auxdat[2] = snarfreg(igfx, 0xE401C + 0x100*x);
433  igfx->dp[x].auxdat[3] = snarfreg(igfx, 0xE4020 + 0x100*x);
434  igfx->dp[x].auxdat[4] = snarfreg(igfx, 0xE4024 + 0x100*x);
435  }
436 
437  for(x=0; x<3; x++){
438  igfx->pfit[x].pwrgate = snarfreg(igfx, 0x68060 + 0x800*x);
439  igfx->pfit[x].winpos = snarfreg(igfx, 0x68070 + 0x800*x);
440  igfx->pfit[x].winsize = snarfreg(igfx, 0x68074 + 0x800*x);
441  igfx->pfit[x].ctrl = snarfreg(igfx, 0x68080 + 0x800*x);
442 
443  y = (igfx->pfit[x].ctrl.v >> 29) & 3;
444  if(igfx->pipe[y].pfit == nil)
445  igfx->pipe[y].pfit = &igfx->pfit[x];
446  }
447  igfx->ppstatus = snarfreg(igfx, 0xC7200);
448  igfx->ppcontrol = snarfreg(igfx, 0xC7204);
449 
450  igfx->hdmi[1].ctl = snarfreg(igfx, 0x0E1140); /* HDMI_CTL_B */
451  igfx->hdmi[1].bufctl[0] = snarfreg(igfx, 0x0FC810); /* HTMI_BUF_CTL_0 */
452  igfx->hdmi[1].bufctl[1] = snarfreg(igfx, 0x0FC81C); /* HTMI_BUF_CTL_1 */
453  igfx->hdmi[1].bufctl[2] = snarfreg(igfx, 0x0FC828); /* HTMI_BUF_CTL_2 */
454  igfx->hdmi[1].bufctl[3] = snarfreg(igfx, 0x0FC834); /* HTMI_BUF_CTL_3 */
455 
456  igfx->hdmi[2].ctl = snarfreg(igfx, 0x0E1150); /* HDMI_CTL_C */
457  igfx->hdmi[2].bufctl[0] = snarfreg(igfx, 0x0FCC00); /* HTMI_BUF_CTL_4 */
458  igfx->hdmi[2].bufctl[1] = snarfreg(igfx, 0x0FCC0C); /* HTMI_BUF_CTL_5 */
459  igfx->hdmi[2].bufctl[2] = snarfreg(igfx, 0x0FCC18); /* HTMI_BUF_CTL_6 */
460  igfx->hdmi[2].bufctl[3] = snarfreg(igfx, 0x0FCC24); /* HTMI_BUF_CTL_7 */
461 
462  igfx->hdmi[3].ctl = snarfreg(igfx, 0x0E1160); /* HDMI_CTL_D */
463  igfx->hdmi[3].bufctl[0] = snarfreg(igfx, 0x0FD000); /* HTMI_BUF_CTL_8 */
464  igfx->hdmi[3].bufctl[1] = snarfreg(igfx, 0x0FD00C); /* HTMI_BUF_CTL_9 */
465  igfx->hdmi[3].bufctl[2] = snarfreg(igfx, 0x0FD018); /* HTMI_BUF_CTL_10 */
466  igfx->hdmi[3].bufctl[3] = snarfreg(igfx, 0x0FD024); /* HTMI_BUF_CTL_11 */
467 
468  for(x=0; x<5; x++)
469  igfx->gmbus[x] = snarfreg(igfx, 0xC5100 + x*4);
470  igfx->gmbus[x] = snarfreg(igfx, 0xC5120);
471 
472  igfx->adpa = snarfreg(igfx, 0x0E1100); /* DAC_CTL */
473  igfx->lvds = snarfreg(igfx, 0x0E1180); /* LVDS_CTL */
474 
475  igfx->vgacntrl = snarfreg(igfx, 0x041000);
476  break;
477  }
478 
479  for(x=0; x<igfx->npipe; x++)
480  snarfpipe(igfx, x);
481 
482  for(x=0; x<nelem(vga->edid); x++){
483  Modelist *l;
484 
485  switch(x){
486  case PortVGA:
487  vga->edid[x] = snarfgmedid(igfx, 2, 0x50);
488  break;
489  case PortLCD:
490  vga->edid[x] = snarfgmedid(igfx, 3, 0x50);
491  if(vga->edid[x] == nil)
492  continue;
493  for(l = vga->edid[x]->modelist; l != nil; l = l->next)
494  l->attr = mkattr(l->attr, "lcd", "1");
495  break;
496  case PortDPA:
497  case PortDPB:
498  case PortDPC:
499  case PortDPD:
500  vga->edid[x] = snarfdpedid(igfx, &igfx->dp[x-PortDPA], 0x50);
501  break;
502  }
503  if(vga->edid[x] == nil)
504  continue;
505  for(l = vga->edid[x]->modelist; l != nil; l = l->next)
506  l->attr = mkattr(l->attr, "display", "%d", x+1);
507  }
508 
509  ctlr->flag |= Fsnarf;
510 }
511 
512 static void
513 options(Vga* vga, Ctlr* ctlr)
514 {
515  USED(vga);
516  ctlr->flag |= Hlinear|Ulinear|Foptions;
517 }
518 
519 static int
520 genpll(int freq, int cref, int P2, int *m1, int *m2, int *n, int *p1)
521 {
522  int M1, M2, M, N, P, P1;
523  int best, error;
524  vlong a;
525 
526  best = -1;
527  for(N=3; N<=8; N++)
528  for(M2=5; M2<=9; M2++)
529 // for(M1=10; M1<=20; M1++){
530  for(M1=12; M1<=22; M1++){
531  M = 5*(M1+2) + (M2+2);
532  if(M < 79 || M > 127)
533 // if(M < 70 || M > 120)
534  continue;
535  for(P1=1; P1<=8; P1++){
536  P = P1 * P2;
537  if(P < 5 || P > 98)
538 // if(P < 4 || P > 98)
539  continue;
540  a = cref;
541  a *= M;
542  a /= N+2;
543  a /= P;
544  if(a < 20*MHz || a > 400*MHz)
545  continue;
546  error = a;
547  error -= freq;
548  if(error < 0)
549  error = -error;
550  if(best < 0 || error < best){
551  best = error;
552  *m1 = M1;
553  *m2 = M2;
554  *n = N;
555  *p1 = P1;
556  }
557  }
558  }
559  return best;
560 }
561 
562 static int
563 getcref(Igfx *igfx, int x)
564 {
565  Dpll *dpll;
566 
567  dpll = &igfx->dpll[x];
568  if(igfx->type == TypeG45){
569  if(((dpll->ctrl.v >> 13) & 3) == 3)
570  return 100*MHz;
571  return 96*MHz;
572  }
573  return 120*MHz;
574 }
575 
576 static int
577 initdpll(Igfx *igfx, int x, int freq, int port)
578 {
579  int cref, m1, m2, n, p1, p2;
580  Dpll *dpll;
581 
582  switch(igfx->type){
583  case TypeG45:
584  /* PLL Reference Input Select */
585  dpll = igfx->pipe[x].dpll;
586  dpll->ctrl.v &= ~(3<<13);
587  dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
588  break;
589  case TypeIVB:
590  /* transcoder dpll enable */
591  igfx->dpllsel.v |= 8<<(x*4);
592  /* program rawclock to 125MHz */
593  igfx->rawclkfreq.v = 125;
594 
595  igfx->drefctl.v &= ~(3<<13);
596  igfx->drefctl.v &= ~(3<<11);
597  igfx->drefctl.v &= ~(3<<9);
598  igfx->drefctl.v &= ~(3<<7);
599  igfx->drefctl.v &= ~3;
600 
601  if(port == PortLCD){
602  igfx->drefctl.v |= 2<<11;
603  igfx->drefctl.v |= 1;
604  } else {
605  igfx->drefctl.v |= 2<<9;
606  }
607 
608  /*
609  * PLL Reference Input Select:
610  * 000 DREFCLK (default is 120 MHz) for DAC/HDMI/DVI/DP
611  * 001 Super SSC 120MHz super-spread clock
612  * 011 SSC Spread spectrum input clock (120MHz default) for LVDS/DP
613  */
614  dpll = igfx->pipe[x].fdi->dpll;
615  dpll->ctrl.v &= ~(7<<13);
616  dpll->ctrl.v |= (port == PortLCD ? 3 : 0) << 13;
617  break;
618  default:
619  return -1;
620  }
621  cref = getcref(igfx, x);
622 
623  /* Dpll Mode select */
624  dpll->ctrl.v &= ~(3<<26);
625  dpll->ctrl.v |= (port == PortLCD ? 2 : 1)<<26;
626 
627  /* P2 Clock Divide */
628  dpll->ctrl.v &= ~(3<<24);
629  if(port == PortLCD){
630  p2 = 14;
631  if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
632  return -1;
633  } else {
634  /* generate 270MHz clock for displayport */
635  if(port >= PortDPA)
636  freq = 270*MHz;
637 
638  p2 = 10;
639  if(freq > 270*MHz){
640  p2 >>= 1;
641  dpll->ctrl.v |= (1<<24);
642  }
643  if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
644  return -1;
645  }
646 
647  /* Dpll VCO Enable */
648  dpll->ctrl.v |= (1<<31);
649 
650  /* Dpll Serial DVO High Speed IO clock Enable */
651  if(port >= PortDPA)
652  dpll->ctrl.v |= (1<<30);
653  else
654  dpll->ctrl.v &= ~(1<<30);
655 
656  /* VGA Mode Disable */
657  dpll->ctrl.v |= (1<<28);
658 
659  dpll->fp0.v &= ~(0x3f<<16);
660  dpll->fp0.v |= n << 16;
661  dpll->fp0.v &= ~(0x3f<<8);
662  dpll->fp0.v |= m1 << 8;
663  dpll->fp0.v &= ~(0x3f<<0);
664  dpll->fp0.v |= m2 << 0;
665 
666  /* FP0 P1 Post Divisor */
667  dpll->ctrl.v &= ~0xFF0000;
668  dpll->ctrl.v |= 0x010000<<(p1-1);
669 
670  /* FP1 P1 Post divisor */
671  if(igfx->pci->did != 0x27a2){
672  dpll->ctrl.v &= ~0xFF;
673  dpll->ctrl.v |= 0x01<<(p1-1);
674  dpll->fp1.v = dpll->fp0.v;
675  }
676 
677  return 0;
678 }
679 
680 static void
681 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
682 {
683  uvlong m, n;
684 
685  n = 0x800000;
686  m = (n * ((freq * bpp)/8)) / (lsclk * lanes);
687 
688  t->dm[0].v = (tu-1)<<25 | m;
689  t->dn[0].v = n;
690 
691  n = 0x80000;
692  m = (n * freq) / lsclk;
693 
694  t->lm[0].v = m;
695  t->ln[0].v = n;
696 
697  t->dm[1].v = t->dm[0].v;
698  t->dn[1].v = t->dn[0].v;
699  t->lm[1].v = t->lm[0].v;
700  t->ln[1].v = t->ln[0].v;
701 }
702 
703 static void
704 inittrans(Trans *t, Mode *m)
705 {
706  /* clear all but 27:28 frame start delay (initialized by bios) */
707  t->conf.v &= 3<<27;
708 
709  /* tans/pipe enable */
710  t->conf.v |= 1<<31;
711 
712  /* trans/pipe timing */
713  t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
714  t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);
715  t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
716  t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
717 
718  t->hb.v = t->ht.v;
719  t->vb.v = t->vt.v;
720 
721  t->vss.v = 0;
722 }
723 
724 static void
725 initpipe(Pipe *p, Mode *m)
726 {
727  static uchar bpctab[4] = { 8, 10, 6, 12 };
728  int i, tu, bpc, lanes;
729  Fdi *fdi;
730 
731  /* source image size */
732  p->src.v = (m->x - 1)<<16 | (m->y - 1);
733 
734  if(p->pfit != nil){
735  /* panel fitter off */
736  p->pfit->ctrl.v &= ~(1<<31);
737  p->pfit->winpos.v = 0;
738  p->pfit->winsize.v = 0;
739  }
740 
741  /* enable and set monitor timings for cpu pipe */
742  inittrans(p, m);
743 
744  /* default for displayport */
745  tu = 64;
746  bpc = 6; /* why */
747  lanes = 1;
748 
749  fdi = p->fdi;
750  if(fdi->rxctl.a != 0){
751  /* enable and set monitor timings for transcoder */
752  inittrans(fdi, m);
753 
754  /* tx port width selection */
755  fdi->txctl.v &= ~(7<<19);
756  fdi->txctl.v |= (lanes-1)<<19;
757 
758  /* rx port width selection */
759  fdi->rxctl.v &= ~(7<<19);
760  fdi->rxctl.v |= (lanes-1)<<19;
761  /* bits per color for transcoder */
762  for(i=0; i<nelem(bpctab); i++){
763  if(bpctab[i] == bpc){
764  fdi->rxctl.v &= ~(7<<16);
765  fdi->rxctl.v |= i<<16;
766  fdi->dpctl.v &= ~(7<<9);
767  fdi->dpctl.v |= i<<9;
768  break;
769  }
770  }
771 
772  /* enhanced framing on */
773  fdi->rxctl.v |= (1<<6);
774  fdi->txctl.v |= (1<<18);
775 
776  /* tusize 1 and 2 */
777  fdi->rxtu[0].v = (tu-1)<<25;
778  fdi->rxtu[1].v = (tu-1)<<25;
779  initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
780  }
781 
782  /* bits per color for cpu pipe */
783  for(i=0; i<nelem(bpctab); i++){
784  if(bpctab[i] == bpc){
785  p->conf.v &= ~(7<<5);
786  p->conf.v |= i<<5;
787  break;
788  }
789  }
790  initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
791 }
792 
793 static void
794 init(Vga* vga, Ctlr* ctlr)
795 {
796  int x, port;
797  char *val;
798  Igfx *igfx;
799  Pipe *p;
800  Mode *m;
801  Reg *r;
802 
803  m = vga->mode;
804  if(m->z != 32)
805  error("%s: unsupported color depth %d\n", ctlr->name, m->z);
806 
807  igfx = vga->private;
808 
809  /* disable vga */
810  igfx->vgacntrl.v |= (1<<31);
811 
812  /* disable all pipes and ports */
813  igfx->ppcontrol.v &= 0xFFFF;
814  igfx->ppcontrol.v &= ~5;
815  igfx->lvds.v &= ~(1<<31);
816  igfx->adpa.v &= ~(1<<31);
817  if(igfx->type == TypeG45)
818  igfx->adpa.v |= (3<<10); /* Monitor DPMS: off */
819  for(x=0; x<nelem(igfx->dp); x++)
820  igfx->dp[x].ctl.v &= ~(1<<31);
821  for(x=0; x<nelem(igfx->hdmi); x++)
822  igfx->hdmi[x].ctl.v &= ~(1<<31);
823  for(x=0; x<igfx->npipe; x++){
824  /* disable displayport transcoders */
825  igfx->pipe[x].dpctl.v &= ~(1<<31);
826  igfx->pipe[x].dpctl.v |= (3<<29);
827  igfx->pipe[x].fdi->dpctl.v &= ~(1<<31);
828  igfx->pipe[x].fdi->dpctl.v |= (3<<29);
829  /* disable transcoder/pipe */
830  igfx->pipe[x].conf.v &= ~(1<<31);
831  }
832 
833  if((val = dbattr(m->attr, "display")) != nil)
834  port = atoi(val)-1;
835  else if(dbattr(m->attr, "lcd") != nil)
836  port = PortLCD;
837  else
838  port = PortVGA;
839 
840  trace("%s: display #%d\n", ctlr->name, port+1);
841 
842  switch(port){
843  default:
844  Badport:
845  error("%s: display #%d not supported\n", ctlr->name, port+1);
846  break;
847 
848  case PortVGA:
849  if(igfx->npipe > 2)
850  x = (igfx->adpa.v >> 29) & 3;
851  else
852  x = (igfx->adpa.v >> 30) & 1;
853  igfx->adpa.v |= (1<<31);
854  if(igfx->type == TypeG45){
855  igfx->adpa.v &= ~(3<<10); /* Monitor DPMS: on */
856 
857  igfx->adpa.v &= ~(1<<15); /* ADPA Polarity Select */
858  igfx->adpa.v |= 3<<3;
859  if(m->hsync == '-')
860  igfx->adpa.v ^= 1<<3;
861  if(m->vsync == '-')
862  igfx->adpa.v ^= 1<<4;
863  }
864  break;
865 
866  case PortLCD:
867  if(igfx->npipe > 2)
868  x = (igfx->lvds.v >> 29) & 3;
869  else
870  x = (igfx->lvds.v >> 30) & 1;
871  igfx->lvds.v |= (1<<31);
872  igfx->ppcontrol.v |= 5;
873 
874  if(igfx->type == TypeG45){
875  igfx->lvds.v &= ~(1<<24); /* data format select 18/24bpc */
876 
877  igfx->lvds.v &= ~(3<<20);
878  if(m->hsync == '-')
879  igfx->lvds.v ^= 1<<20;
880  if(m->vsync == '-')
881  igfx->lvds.v ^= 1<<21;
882 
883  igfx->lvds.v |= (1<<15); /* border enable */
884  }
885  break;
886 
887  case PortDPA:
888  case PortDPB:
889  case PortDPC:
890  case PortDPD:
891  r = &igfx->dp[port - PortDPA].ctl;
892  if(r->a == 0)
893  goto Badport;
894  /* port enable */
895  r->v |= 1<<31;
896  /* port width selection: x1 Mode */
897  r->v &= ~(7<<19);
898 
899  /* port reversal: off */
900  r->v &= ~(1<<15);
901  /* reserved MBZ */
902  r->v &= ~(15<<11);
903  /* use PIPE_A for displayport */
904  x = 0;
905  /* displayport transcoder */
906  if(port == PortDPA){
907  /* pll frequency: 270mhz */
908  r->v &= ~(3<<16);
909  /* pll enable */
910  r->v |= 1<<14;
911  /* pipe select */
912  r->v &= ~(3<<29);
913  r->v |= x<<29;
914  } else if(igfx->pipe[x].fdi->dpctl.a != 0){
915  /* audio output: disable */
916  r->v &= ~(1<<6);
917  /* transcoder displayport configuration */
918  r = &igfx->pipe[x].fdi->dpctl;
919  /* transcoder enable */
920  r->v |= 1<<31;
921  /* port select: B,C,D */
922  r->v &= ~(3<<29);
923  r->v |= (port-PortDPB)<<29;
924  }
925  /* sync polarity */
926  r->v |= 3<<3;
927  if(m->hsync == '-')
928  r->v ^= 1<<3;
929  if(m->vsync == '-')
930  r->v ^= 1<<4;
931  break;
932  }
933  p = &igfx->pipe[x];
934 
935  /* plane enable, 32bpp */
936  p->dsp->cntr.v = (1<<31) | (6<<26);
937  if(igfx->type == TypeG45)
938  p->dsp->cntr.v |= x<<24; /* pipe assign */
939 
940  /* stride must be 64 byte aligned */
941  p->dsp->stride.v = m->x * (m->z / 8);
942  p->dsp->stride.v += 63;
943  p->dsp->stride.v &= ~63;
944 
945  /* virtual width in pixels */
946  vga->virtx = p->dsp->stride.v / (m->z / 8);
947 
948  /* plane position and size */
949  p->dsp->pos.v = 0;
950  p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1); /* sic */
951 
952  p->dsp->surf.v = 0;
953  p->dsp->linoff.v = 0;
954  p->dsp->tileoff.v = 0;
955 
956  /* cursor plane off */
957  p->cur->cntr.v = 0;
958  if(igfx->type == TypeG45)
959  p->cur->cntr.v |= x<<28; /* pipe assign */
960  p->cur->pos.v = 0;
961  p->cur->base.v = 0;
962 
963  if(initdpll(igfx, x, m->frequency, port) < 0)
964  error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
965 
966  initpipe(p, m);
967 
968  ctlr->flag |= Finit;
969 }
970 
971 static void
972 loadtrans(Igfx *igfx, Trans *t)
973 {
974  int i;
975 
976  /* program trans/pipe timings */
977  loadreg(igfx, t->ht);
978  loadreg(igfx, t->hb);
979  loadreg(igfx, t->hs);
980  loadreg(igfx, t->vt);
981  loadreg(igfx, t->vb);
982  loadreg(igfx, t->vs);
983  loadreg(igfx, t->vss);
984 
985  loadreg(igfx, t->dm[0]);
986  loadreg(igfx, t->dn[0]);
987  loadreg(igfx, t->lm[0]);
988  loadreg(igfx, t->ln[0]);
989  loadreg(igfx, t->dm[1]);
990  loadreg(igfx, t->dn[1]);
991  loadreg(igfx, t->lm[1]);
992  loadreg(igfx, t->ln[1]);
993 
994  if(t->dpll != nil){
995  /* program dpll */
996  t->dpll->ctrl.v &= ~(1<<31);
997  loadreg(igfx, t->dpll->ctrl);
998  loadreg(igfx, t->dpll->fp0);
999  loadreg(igfx, t->dpll->fp1);
1000 
1001  /* enable dpll */
1002  t->dpll->ctrl.v |= (1<<31);
1003  loadreg(igfx, t->dpll->ctrl);
1004  sleep(10);
1005  }
1006 
1007  /* workarround: set timing override bit */
1008  csr(igfx, t->chicken.a, 0, 1<<31);
1009 
1010  /* enable displayport transcoder */
1011  loadreg(igfx, t->dpctl);
1012 
1013  /* enable trans/pipe */
1014  t->conf.v |= (1<<31);
1015  t->conf.v &= ~(1<<30);
1016  loadreg(igfx, t->conf);
1017  for(i=0; i<100; i++){
1018  sleep(10);
1019  if(rr(igfx, t->conf.a) & (1<<30))
1020  break;
1021  }
1022 }
1023 
1024 static void
1025 enablepipe(Igfx *igfx, int x)
1026 {
1027  int i;
1028  Pipe *p;
1029 
1030  p = &igfx->pipe[x];
1031  if((p->conf.v & (1<<31)) == 0)
1032  return; /* pipe is disabled, done */
1033 
1034  if(p->fdi->rxctl.a != 0){
1035  p->fdi->rxctl.v &= ~(1<<31);
1036  p->fdi->rxctl.v &= ~(1<<4); /* rawclk */
1037  p->fdi->rxctl.v |= (1<<13); /* enable pll */
1038  loadreg(igfx, p->fdi->rxctl);
1039  sleep(5);
1040  p->fdi->rxctl.v |= (1<<4); /* pcdclk */
1041  loadreg(igfx, p->fdi->rxctl);
1042  sleep(5);
1043  p->fdi->txctl.v &= ~(7<<8 | 1); /* clear auto training bits */
1044  p->fdi->txctl.v &= ~(1<<31);
1045  p->fdi->rxctl.v |= (1<<14); /* enable pll */
1046  loadreg(igfx, p->fdi->txctl);
1047  sleep(5);
1048  }
1049 
1050  /* image size (vga needs to be off) */
1051  loadreg(igfx, p->src);
1052 
1053  /* set panel fitter as needed */
1054  if(p->pfit != nil){
1055  loadreg(igfx, p->pfit->ctrl);
1056  loadreg(igfx, p->pfit->winpos);
1057  loadreg(igfx, p->pfit->winsize); /* arm */
1058  }
1059 
1060  /* keep planes disabled while pipe comes up */
1061  if(igfx->type == TypeG45)
1062  p->conf.v |= 3<<18;
1063 
1064  /* enable cpu pipe */
1065  loadtrans(igfx, p);
1066 
1067  /* program plane */
1068  loadreg(igfx, p->dsp->cntr);
1069  loadreg(igfx, p->dsp->linoff);
1070  loadreg(igfx, p->dsp->stride);
1071  loadreg(igfx, p->dsp->tileoff);
1072  loadreg(igfx, p->dsp->size);
1073  loadreg(igfx, p->dsp->pos);
1074  loadreg(igfx, p->dsp->surf); /* arm */
1075 
1076  /* program cursor */
1077  loadreg(igfx, p->cur->cntr);
1078  loadreg(igfx, p->cur->pos);
1079  loadreg(igfx, p->cur->base); /* arm */
1080 
1081  /* enable planes */
1082  if(igfx->type == TypeG45) {
1083  p->conf.v &= ~(3<<18);
1084  loadreg(igfx, p->conf);
1085  }
1086 
1087  if(p->fdi->rxctl.a != 0){
1088  /* enable fdi */
1089  loadreg(igfx, p->fdi->rxtu[1]);
1090  loadreg(igfx, p->fdi->rxtu[0]);
1091  loadreg(igfx, p->fdi->rxmisc);
1092 
1093  p->fdi->rxctl.v &= ~(3<<8); /* link train pattern 00 */
1094  p->fdi->rxctl.v |= 1<<10; /* auto train enable */
1095  p->fdi->rxctl.v |= 1<<31; /* enable */
1096  loadreg(igfx, p->fdi->rxctl);
1097 
1098  p->fdi->txctl.v &= ~(3<<8); /* link train pattern 00 */
1099  p->fdi->txctl.v |= 1<<10; /* auto train enable */
1100  p->fdi->txctl.v |= 1<<31; /* enable */
1101  loadreg(igfx, p->fdi->txctl);
1102 
1103  /* wait for link training done */
1104  for(i=0; i<200; i++){
1105  sleep(5);
1106  if(rr(igfx, p->fdi->txctl.a) & 2)
1107  break;
1108  }
1109  }
1110 
1111  /* enable the transcoder */
1112  loadtrans(igfx, p->fdi);
1113 }
1114 
1115 static void
1116 disabletrans(Igfx *igfx, Trans *t)
1117 {
1118  int i;
1119 
1120  /* disable displayport transcoder */
1121  csr(igfx, t->dpctl.a, 1<<31, 3<<29);
1122 
1123  /* disable transcoder / pipe */
1124  csr(igfx, t->conf.a, 1<<31, 0);
1125  for(i=0; i<100; i++){
1126  sleep(10);
1127  if((rr(igfx, t->conf.a) & (1<<30)) == 0)
1128  break;
1129  }
1130  /* workarround: clear timing override bit */
1131  csr(igfx, t->chicken.a, 1<<31, 0);
1132 
1133  /* disable dpll */
1134  if(t->dpll != nil)
1135  csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
1136 }
1137 
1138 static void
1139 disablepipe(Igfx *igfx, int x)
1140 {
1141  Pipe *p;
1142 
1143  p = &igfx->pipe[x];
1144 
1145  /* planes off */
1146  csr(igfx, p->dsp->cntr.a, 1<<31, 0);
1147  wr(igfx, p->dsp->surf.a, 0); /* arm */
1148  /* cursor off */
1149  csr(igfx, p->cur->cntr.a, 1<<5 | 7, 0);
1150  wr(igfx, p->cur->base.a, 0); /* arm */
1151 
1152  /* display/overlay/cursor planes off */
1153  if(igfx->type == TypeG45)
1154  csr(igfx, p->conf.a, 0, 3<<18);
1155 
1156  /* disable cpu pipe */
1157  disabletrans(igfx, p);
1158 
1159  /* disable panel fitter */
1160  if(p->pfit != nil)
1161  csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
1162 
1163  /* disable fdi transmitter and receiver */
1164  csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
1165  csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
1166 
1167  /* disable pch transcoder */
1168  disabletrans(igfx, p->fdi);
1169 
1170  /* disable pch dpll enable bit */
1171  csr(igfx, igfx->dpllsel.a, 8<<(x*4), 0);
1172 }
1173 
1174 static void
1175 load(Vga* vga, Ctlr* ctlr)
1176 {
1177  Igfx *igfx;
1178  int x;
1179 
1180  igfx = vga->private;
1181 
1182  /* power lcd off */
1183  if(igfx->ppcontrol.a != 0){
1184  csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
1185  for(x=0; x<5000; x++){
1186  sleep(10);
1187  if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
1188  break;
1189  }
1190  }
1191 
1192  /* disable ports */
1193  csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
1194  csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
1195  csr(igfx, igfx->adpa.a, 1<<31, 0);
1196  csr(igfx, igfx->lvds.a, 1<<31, 0);
1197  for(x = 0; x < nelem(igfx->dp); x++)
1198  csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
1199  for(x = 0; x < nelem(igfx->hdmi); x++)
1200  csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
1201 
1202  /* disable vga plane */
1203  csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
1204 
1205  /* turn off all pipes */
1206  for(x = 0; x < igfx->npipe; x++)
1207  disablepipe(igfx, x);
1208 
1209  if(igfx->type == TypeG45){
1210  /* toggle dsp a on and off (from enable sequence) */
1211  csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);
1212  csr(igfx, igfx->pipe[0].dsp->cntr.a, 0, 1<<31);
1213  wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1214  csr(igfx, igfx->pipe[0].dsp->cntr.a, 1<<31, 0);
1215  wr(igfx, igfx->pipe[0].dsp->surf.a, 0); /* arm */
1216  csr(igfx, igfx->pipe[0].conf.a, 0, 3<<18);
1217  }
1218 
1219  /* program new clock sources */
1220  loadreg(igfx, igfx->rawclkfreq);
1221  loadreg(igfx, igfx->drefctl);
1222  sleep(10);
1223 
1224  /* set lvds before enabling dpll */
1225  loadreg(igfx, igfx->lvds);
1226 
1227  /* new dpll setting */
1228  loadreg(igfx, igfx->dpllsel);
1229 
1230  /* program all pipes */
1231  for(x = 0; x < igfx->npipe; x++)
1232  enablepipe(igfx, x);
1233 
1234  /* program vga plane */
1235  loadreg(igfx, igfx->vgacntrl);
1236 
1237  /* program ports */
1238  loadreg(igfx, igfx->adpa);
1239  loadreg(igfx, igfx->sdvob);
1240  loadreg(igfx, igfx->sdvoc);
1241  for(x = 0; x < nelem(igfx->dp); x++){
1242  if(enabledp(igfx, &igfx->dp[x]) < 0)
1243  ctlr->flag |= Ferror;
1244  }
1245 
1246  /* program lcd power */
1247  loadreg(igfx, igfx->ppcontrol);
1248 
1249  ctlr->flag |= Fload;
1250 }
1251 
1252 static void
1253 dumpreg(char *name, char *item, Reg r)
1254 {
1255  if(r.a == 0)
1256  return;
1257 
1258  printitem(name, item);
1259  Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
1260 }
1261 
1262 static void
1263 dumphex(char *name, char *item, uchar *data, int len)
1264 {
1265  int i;
1266 
1267  for(i=0; i<len; i++){
1268  if((i & 15) == 0){
1269  if(i > 0)
1270  Bprint(&stdout, "\n");
1271  printitem(name, item);
1272  Bprint(&stdout, " [%.2x] =", i);
1273  }
1274  Bprint(&stdout, " %.2X", data[i]);
1275  }
1276  Bprint(&stdout, "\n");
1277 }
1278 
1279 static void
1280 dumptiming(char *name, Trans *t)
1281 {
1282  int tu, m, n;
1283 
1284  if(t->dm[0].a != 0 && t->dm[0].v != 0){
1285  tu = 1+((t->dm[0].v >> 25) & 0x3f);
1286  printitem(name, "dm1 tu");
1287  Bprint(&stdout, " %d\n", tu);
1288 
1289  m = t->dm[0].v & 0xffffff;
1290  n = t->dn[0].v;
1291  if(n > 0){
1292  printitem(name, "dm1/dn1");
1293  Bprint(&stdout, " %f\n", (double)m / (double)n);
1294  }
1295 
1296  m = t->lm[0].v;
1297  n = t->ln[0].v;
1298  if(n > 0){
1299  printitem(name, "lm1/ln1");
1300  Bprint(&stdout, " %f\n", (double)m / (double)n);
1301  }
1302  }
1303 }
1304 
1305 static void
1306 dumptrans(char *name, Trans *t)
1307 {
1308  dumpreg(name, "conf", t->conf);
1309 
1310  dumpreg(name, "dm1", t->dm[0]);
1311  dumpreg(name, "dn1", t->dn[0]);
1312  dumpreg(name, "lm1", t->lm[0]);
1313  dumpreg(name, "ln1", t->ln[0]);
1314  dumpreg(name, "dm2", t->dm[1]);
1315  dumpreg(name, "dn2", t->dn[1]);
1316  dumpreg(name, "lm2", t->lm[1]);
1317  dumpreg(name, "ln2", t->ln[1]);
1318 
1319  dumptiming(name, t);
1320 
1321  dumpreg(name, "ht", t->ht);
1322  dumpreg(name, "hb", t->hb);
1323  dumpreg(name, "hs", t->hs);
1324 
1325  dumpreg(name, "vt", t->vt);
1326  dumpreg(name, "vb", t->vb);
1327  dumpreg(name, "vs", t->vs);
1328  dumpreg(name, "vss", t->vss);
1329 
1330  dumpreg(name, "dpctl", t->dpctl);
1331 }
1332 
1333 static void
1334 dumppipe(Igfx *igfx, int x)
1335 {
1336  char name[32];
1337  Pipe *p;
1338 
1339  p = &igfx->pipe[x];
1340 
1341  snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
1342  dumpreg(name, "src", p->src);
1343  dumptrans(name, p);
1344 
1345  snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
1346  dumptrans(name, p->fdi);
1347  dumpreg(name, "txctl", p->fdi->txctl);
1348  dumpreg(name, "rxctl", p->fdi->rxctl);
1349  dumpreg(name, "rxmisc", p->fdi->rxmisc);
1350  dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
1351  dumpreg(name, "rxtu2", p->fdi->rxtu[1]);
1352 
1353  snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
1354  dumpreg(name, "cntr", p->dsp->cntr);
1355  dumpreg(name, "linoff", p->dsp->linoff);
1356  dumpreg(name, "stride", p->dsp->stride);
1357  dumpreg(name, "surf", p->dsp->surf);
1358  dumpreg(name, "tileoff", p->dsp->tileoff);
1359  dumpreg(name, "pos", p->dsp->pos);
1360  dumpreg(name, "size", p->dsp->size);
1361 
1362  snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
1363  dumpreg(name, "cntr", p->cur->cntr);
1364  dumpreg(name, "base", p->cur->base);
1365  dumpreg(name, "pos", p->cur->pos);
1366 }
1367 
1368 static void
1369 dumpdpll(Igfx *igfx, int x)
1370 {
1371  int cref, m1, m2, n, p1, p2;
1372  uvlong freq;
1373  char name[32];
1374  Dpll *dpll;
1375  u32int m;
1376 
1377  dpll = &igfx->dpll[x];
1378  snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
1379 
1380  dumpreg(name, "ctrl", dpll->ctrl);
1381  dumpreg(name, "fp0", dpll->fp0);
1382  dumpreg(name, "fp1", dpll->fp1);
1383 
1384  p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
1385  if(((dpll->ctrl.v >> 24) & 3) == 1)
1386  p2 >>= 1;
1387  m = (dpll->ctrl.v >> 16) & 0xFF;
1388  for(p1 = 1; p1 <= 8; p1++)
1389  if(m & (1<<(p1-1)))
1390  break;
1391  printitem(name, "ctrl p1");
1392  Bprint(&stdout, " %d\n", p1);
1393  printitem(name, "ctrl p2");
1394  Bprint(&stdout, " %d\n", p2);
1395 
1396  n = (dpll->fp0.v >> 16) & 0x3f;
1397  m1 = (dpll->fp0.v >> 8) & 0x3f;
1398  m2 = (dpll->fp0.v >> 0) & 0x3f;
1399 
1400  cref = getcref(igfx, x);
1401  freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
1402 
1403  printitem(name, "fp0 m1");
1404  Bprint(&stdout, " %d\n", m1);
1405  printitem(name, "fp0 m2");
1406  Bprint(&stdout, " %d\n", m2);
1407  printitem(name, "fp0 n");
1408  Bprint(&stdout, " %d\n", n);
1409 
1410  printitem(name, "cref");
1411  Bprint(&stdout, " %d\n", cref);
1412  printitem(name, "fp0 freq");
1413  Bprint(&stdout, " %lld\n", freq);
1414 }
1415 
1416 static void
1417 dump(Vga* vga, Ctlr* ctlr)
1418 {
1419  char name[32];
1420  Igfx *igfx;
1421  int x;
1422 
1423  if((igfx = vga->private) == nil)
1424  return;
1425 
1426  for(x=0; x<igfx->npipe; x++)
1427  dumppipe(igfx, x);
1428 
1429  for(x=0; x<nelem(igfx->dpll); x++)
1430  dumpdpll(igfx, x);
1431 
1432  dumpreg(ctlr->name, "dpllsel", igfx->dpllsel);
1433 
1434  dumpreg(ctlr->name, "drefctl", igfx->drefctl);
1435  dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
1436  dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
1437 
1438  for(x=0; x<nelem(igfx->dp); x++){
1439  if(igfx->dp[x].ctl.a == 0)
1440  continue;
1441  snprint(name, sizeof(name), "%s dp %c", ctlr->name, 'a'+x);
1442  dumpreg(name, "ctl", igfx->dp[x].ctl);
1443  dumphex(name, "dpcd", igfx->dp[x].dpcd, sizeof(igfx->dp[x].dpcd));
1444  }
1445  for(x=0; x<nelem(igfx->hdmi); x++){
1446  snprint(name, sizeof(name), "%s hdmi %c", ctlr->name, 'a'+x);
1447  dumpreg(name, "ctl", igfx->hdmi[x].ctl);
1448  }
1449 
1450  for(x=0; x<nelem(igfx->pfit); x++){
1451  snprint(name, sizeof(name), "%s pfit %c", ctlr->name, 'a'+x);
1452  dumpreg(name, "ctrl", igfx->pfit[x].ctrl);
1453  dumpreg(name, "winpos", igfx->pfit[x].winpos);
1454  dumpreg(name, "winsize", igfx->pfit[x].winsize);
1455  dumpreg(name, "pwrgate", igfx->pfit[x].pwrgate);
1456  }
1457 
1458  dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);
1459  dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);
1460 
1461  dumpreg(ctlr->name, "adpa", igfx->adpa);
1462  dumpreg(ctlr->name, "lvds", igfx->lvds);
1463  dumpreg(ctlr->name, "sdvob", igfx->sdvob);
1464  dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
1465 
1466  dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
1467 }
1468 
1469 static int
1470 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)
1471 {
1472  int t, i;
1473  u32int w;
1474 
1475  if(dp->auxctl.a == 0){
1476  werrstr("not present");
1477  return -1;
1478  }
1479 
1480  t = 0;
1481  while(rr(igfx, dp->auxctl.a) & (1<<31)){
1482  if(++t >= 10){
1483  werrstr("busy");
1484  return -1;
1485  }
1486  sleep(5);
1487  }
1488 
1489  /* clear sticky bits */
1490  wr(igfx, dp->auxctl.a, (1<<28) | (1<25) | (1<<30));
1491 
1492  for(i=0; i<nelem(dp->auxdat); i++){
1493  w = buf[i*4+0]<<24;
1494  w |= buf[i*4+1]<<16;
1495  w |= buf[i*4+2]<<8;
1496  w |= buf[i*4+3];
1497  wr(igfx, dp->auxdat[i].a, w);
1498  }
1499 
1500  /* 2X Bit Clock divider */
1501  w = ((dp == &igfx->dp[0]) ? igfx->cdclk : (igfx->rawclkfreq.v & 0x3ff)) >> 1;
1502  if(w < 1 || w > 0x3fd){
1503  werrstr("bad clock");
1504  return -1;
1505  }
1506 
1507  /* hack: slow down a bit */
1508  w += 2;
1509 
1510  w |= 1<<31; /* SendBusy */
1511  w |= 1<<29; /* interrupt disabled */
1512  w |= 3<<26; /* timeout 1600µs */
1513  w |= len<<20; /* send bytes */
1514  w |= 5<<16; /* precharge time (5*2 = 10µs) */
1515  wr(igfx, dp->auxctl.a, w);
1516 
1517  t = 0;
1518  for(;;){
1519  w = rr(igfx, dp->auxctl.a);
1520  if((w & (1<<30)) != 0)
1521  break;
1522  if(++t >= 10){
1523  werrstr("busy");
1524  return -1;
1525  }
1526  sleep(5);
1527  }
1528  if(w & (1<28)){
1529  werrstr("receive timeout");
1530  return -1;
1531  }
1532  if(w & (1<<25)){
1533  werrstr("receive error");
1534  return -1;
1535  }
1536 
1537  len = (w >> 20) & 0x1f;
1538  for(i=0; i<nelem(dp->auxdat); i++){
1539  w = rr(igfx, dp->auxdat[i].a);
1540  buf[i*4+0] = w>>24;
1541  buf[i*4+1] = w>>16;
1542  buf[i*4+2] = w>>8;
1543  buf[i*4+3] = w;
1544  }
1545 
1546  return len;
1547 }
1548 
1549 enum {
1550  CmdNative = 8,
1551  CmdMot = 4,
1552  CmdRead = 1,
1553  CmdWrite = 0,
1554 };
1555 
1556 static int
1557 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)
1558 {
1559  uchar buf[20];
1560  int r;
1561 
1562  assert(len <= 16);
1563 
1564  memset(buf, 0, sizeof(buf));
1565  buf[0] = (cmd << 4) | ((addr >> 16) & 0xF);
1566  buf[1] = addr >> 8;
1567  buf[2] = addr;
1568  buf[3] = len-1;
1569  r = 3;
1570  if(data != nil && len > 0){
1571  if((cmd & CmdRead) == 0)
1572  memmove(buf+4, data, len);
1573  r = 4 + len;
1574  }
1575  if((r = dpauxio(igfx, dp, buf, r)) < 0){
1576  trace("%s: dpauxio: dp %c, cmd %x, addr %x, len %d: %r\n",
1577  igfx->ctlr->name, 'a'+(int)(dp - &igfx->dp[0]), cmd, addr, len);
1578  return -1;
1579  }
1580  if(r == 0 || data == nil || len == 0)
1581  return 0;
1582  if((cmd & CmdRead) != 0){
1583  if(--r < len)
1584  len = r;
1585  memmove(data, buf+1, len);
1586  }
1587  return len;
1588 }
1589 
1590 static int
1591 rdpaux(Igfx *igfx, Dp *dp, int addr)
1592 {
1593  uchar buf[1];
1594  if(dpauxtra(igfx, dp, CmdNative|CmdRead, addr, buf, 1) != 1)
1595  return -1;
1596  return buf[0];
1597 }
1598 static int
1599 wdpaux(Igfx *igfx, Dp *dp, int addr, uchar val)
1600 {
1601  if(dpauxtra(igfx, dp, CmdNative|CmdWrite, addr, &val, 1) != 1)
1602  return -1;
1603  return 0;
1604 }
1605 
1606 static int
1607 enabledp(Igfx *igfx, Dp *dp)
1608 {
1609  int try, r;
1610 
1611  if(dp->ctl.a == 0)
1612  return 0;
1613  if((dp->ctl.v & (1<<31)) == 0)
1614  return 0;
1615 
1616  /* Link configuration */
1617  wdpaux(igfx, dp, 0x100, 0x0A); /* 270Mhz */
1618  wdpaux(igfx, dp, 0x101, 0x01); /* one lane */
1619 
1620  r = 0;
1621 
1622  /* Link training pattern 1 */
1623  dp->ctl.v &= ~(7<<8);
1624  loadreg(igfx, dp->ctl);
1625  for(try = 0;;try++){
1626  if(try > 5)
1627  goto Fail;
1628  /* Link training pattern 1 */
1629  wdpaux(igfx, dp, 0x102, 0x01);
1630  sleep(100);
1631  if((r = rdpaux(igfx, dp, 0x202)) < 0)
1632  goto Fail;
1633  if(r & 1) /* LANE0_CR_DONE */
1634  break;
1635  }
1636  trace("pattern1 finished: %x\n", r);
1637 
1638  /* Link training pattern 2 */
1639  dp->ctl.v &= ~(7<<8);
1640  dp->ctl.v |= 1<<8;
1641  loadreg(igfx, dp->ctl);
1642  for(try = 0;;try++){
1643  if(try > 5)
1644  goto Fail;
1645  /* Link training pattern 2 */
1646  wdpaux(igfx, dp, 0x102, 0x02);
1647  sleep(100);
1648  if((r = rdpaux(igfx, dp, 0x202)) < 0)
1649  goto Fail;
1650  if((r & 7) == 7)
1651  break;
1652  }
1653  trace("pattern2 finished: %x\n", r);
1654 
1655  /* stop training */
1656  dp->ctl.v &= ~(7<<8);
1657  dp->ctl.v |= 3<<8;
1658  loadreg(igfx, dp->ctl);
1659  wdpaux(igfx, dp, 0x102, 0x00);
1660  return 1;
1661 
1662 Fail:
1663  trace("training failed: %x\n", r);
1664 
1665  /* disable port */
1666  dp->ctl.v &= ~(1<<31);
1667  loadreg(igfx, dp->ctl);
1668  wdpaux(igfx, dp, 0x102, 0x00);
1669  return -1;
1670 }
1671 
1672 static uchar*
1673 edidshift(uchar buf[256])
1674 {
1675  uchar tmp[256];
1676  int i;
1677 
1678  /* shift if neccesary so edid block is at the start */
1679  for(i=0; i<256-8; i++){
1680  if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
1681  && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
1682  memmove(tmp, buf, i);
1683  memmove(buf, buf + i, 256 - i);
1684  memmove(buf + (256 - i), tmp, i);
1685  break;
1686  }
1687  }
1688  return buf;
1689 }
1690 
1691 static Edid*
1692 snarfdpedid(Igfx *igfx, Dp *dp, int addr)
1693 {
1694  uchar buf[256];
1695  int i;
1696 
1697  for(i=0; i<sizeof(dp->dpcd); i+=16)
1698  if(dpauxtra(igfx, dp, CmdNative|CmdRead, i, dp->dpcd+i, 16) != 16)
1699  return nil;
1700 
1701  if(dp->dpcd[0] == 0) /* nothing there, dont try to get edid */
1702  return nil;
1703 
1704  if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)
1705  return nil;
1706 
1707  for(i=0; i<sizeof(buf); i+=16){
1708  if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
1709  continue;
1710  if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
1711  continue;
1712  if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
1713  continue;
1714  if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
1715  continue;
1716  if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, buf+i, 16) == 16)
1717  continue;
1718  return nil;
1719  }
1720 
1721  dpauxtra(igfx, dp, CmdRead, addr, nil, 0);
1722 
1723  return parseedid128(edidshift(buf));
1724 }
1725 
1726 enum {
1727  GMBUSCP = 0, /* Clock/Port selection */
1728  GMBUSCS = 1, /* Command/Status */
1729  GMBUSST = 2, /* Status Register */
1730  GMBUSDB = 3, /* Data Buffer Register */
1731  GMBUSIM = 4, /* Interrupt Mask */
1732  GMBUSIX = 5, /* Index Register */
1733 };
1734 
1735 static int
1736 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
1737 {
1738  u32int x, y;
1739  int n, t;
1740 
1741  if(igfx->gmbus[GMBUSCP].a == 0)
1742  return -1;
1743 
1744  wr(igfx, igfx->gmbus[GMBUSCP].a, port);
1745  wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
1746 
1747  /* bus cycle without index and stop, byte count, slave address, read */
1748  wr(igfx, igfx->gmbus[GMBUSCS].a, 1<<30 | 5<<25 | len<<16 | addr<<1 | 1);
1749 
1750  n = 0;
1751  while(len > 0){
1752  x = 0;
1753  for(t=0; t<100; t++){
1754  x = rr(igfx, igfx->gmbus[GMBUSST].a);
1755  if(x & (1<<11))
1756  break;
1757  sleep(5);
1758  }
1759  if((x & (1<<11)) == 0)
1760  return -1;
1761 
1762  t = 4 - (x & 3);
1763  if(t > len)
1764  t = len;
1765  len -= t;
1766 
1767  y = rr(igfx, igfx->gmbus[GMBUSDB].a);
1768  switch(t){
1769  case 4:
1770  data[n++] = y & 0xff, y >>= 8;
1771  case 3:
1772  data[n++] = y & 0xff, y >>= 8;
1773  case 2:
1774  data[n++] = y & 0xff, y >>= 8;
1775  case 1:
1776  data[n++] = y & 0xff;
1777  }
1778  }
1779 
1780  return n;
1781 }
1782 
1783 static Edid*
1784 snarfgmedid(Igfx *igfx, int port, int addr)
1785 {
1786  uchar buf[256];
1787 
1788  /* read twice */
1789  if(gmbusread(igfx, port, addr, buf, 128) != 128)
1790  return nil;
1791  if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
1792  return nil;
1793 
1794  return parseedid128(edidshift(buf));
1795 }
1796 
1797 Ctlr igfx = {
1798  "igfx", /* name */
1799  snarf, /* snarf */
1800  options, /* options */
1801  init, /* init */
1802  load, /* load */
1803  dump, /* dump */
1804 };
1805 
1806 Ctlr igfxhwgc = {
1807  "igfxhwgc",
1808 };