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>5 #include "pci.h"6 #include "vga.h"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;20 enum {21 MHz = 1000000,22 };24 enum {25 TypeG45,26 TypeIVB, /* Ivy Bridge */27 };29 enum {30 PortVGA = 0, /* adpa */31 PortLCD = 1, /* lvds */32 PortDPA = 2,33 PortDPB = 3,34 PortDPC = 4,35 PortDPD = 5,36 };38 struct Reg {39 u32int a; /* address or 0 when invalid */40 u32int v; /* value */41 };43 struct Dpll {44 Reg ctrl; /* DPLLx_CTRL */45 Reg fp0; /* FPx0 */46 Reg fp1; /* FPx1 */47 };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 */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 */63 Reg conf; /* pipe/trans CONF_x */64 Reg chicken; /* workarround register */66 Reg dpctl; /* TRANS_DP_CTL_x */68 Dpll *dpll; /* this transcoders dpll */69 };71 struct Hdmi {72 Reg ctl;73 Reg bufctl[4];74 };76 struct Dp {77 Reg ctl;78 Reg auxctl;79 Reg auxdat[5];81 uchar dpcd[256];82 };84 struct Fdi {85 Trans;87 Reg txctl; /* FDI_TX_CTL */89 Reg rxctl; /* FDI_RX_CTL */90 Reg rxmisc; /* FDI_RX_MISC */91 Reg rxtu[2]; /* FDI_RX_TUSIZE */92 };94 struct Pfit {95 Reg ctrl;96 Reg winpos;97 Reg winsize;98 Reg pwrgate;99 };101 struct Plane {102 Reg cntr; /* DSPxCNTR */103 Reg linoff; /* DSPxLINOFF */104 Reg stride; /* DSPxSTRIDE */105 Reg surf; /* DSPxSURF */106 Reg tileoff; /* DSPxTILEOFF */108 Reg pos;109 Reg size;110 };112 struct Curs {113 Reg cntr;114 Reg base;115 Reg pos;116 };118 struct Pipe {119 Trans;121 Reg src; /* PIPExSRC */123 Fdi fdi[1]; /* fdi/dp transcoder */125 Plane dsp[1]; /* display plane */126 Curs cur[1]; /* hardware cursor */128 Pfit *pfit; /* selected panel fitter */129 };131 struct Igfx {132 Ctlr *ctlr;133 Pcidev *pci;135 u32int pio;136 u32int *mmio;138 int type;139 int cdclk; /* core display clock in mhz */141 int npipe;142 Pipe pipe[4];144 Dpll dpll[2];145 Pfit pfit[3];147 /* IVB */148 Reg dpllsel; /* DPLL_SEL */149 Reg drefctl; /* DREF_CTL */150 Reg rawclkfreq; /* RAWCLK_FREQ */151 Reg ssc4params; /* SSC4_PARAMS */153 Dp dp[4];154 Hdmi hdmi[4];156 Reg ppcontrol;157 Reg ppstatus;159 /* G45 */160 Reg gmbus[6]; /* GMBUSx */162 Reg sdvoc;163 Reg sdvob;165 /* common */166 Reg adpa;167 Reg lvds;169 Reg vgacntrl;170 };172 static u32int173 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 void184 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 void197 csr(Igfx *igfx, u32int reg, u32int clr, u32int set)198 {199 wr(igfx, reg, (rr(igfx, reg) & ~clr) | set);200 }202 static void203 loadreg(Igfx *igfx, Reg r)204 {205 wr(igfx, r.a, r.v);206 }208 static Reg209 snarfreg(Igfx *igfx, u32int a)210 {211 Reg r;213 r.a = a;214 r.v = rr(igfx, a);215 return r;216 }218 static void219 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);230 t->conf = snarfreg(igfx, o + 0x10008);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 }254 static void255 snarfpipe(Igfx *igfx, int x)256 {257 u32int o;258 Pipe *p;260 p = &igfx->pipe[x];262 o = 0x60000 + x*0x1000;263 snarftrans(igfx, p, o);265 p->src = snarfreg(igfx, o + 0x0001C);267 if(igfx->type == TypeIVB) {268 p->fdi->txctl = snarfreg(igfx, o + 0x100);270 o = 0xE0000 | x*0x1000;271 snarftrans(igfx, p->fdi, o);273 p->fdi->dpctl = snarfreg(igfx, o + 0x300);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);280 p->fdi->chicken = snarfreg(igfx, o + 0x10064);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 }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);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);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 }313 static int314 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 }329 static Edid* snarfgmedid(Igfx*, int port, int addr);330 static Edid* snarfdpedid(Igfx*, Dp *dp, int addr);332 static int enabledp(Igfx*, Dp*);334 static void335 snarf(Vga* vga, Ctlr* ctlr)336 {337 Igfx *igfx;338 int x, y;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 }368 switch(igfx->type){369 case TypeG45:370 igfx->npipe = 2; /* A,B */371 igfx->cdclk = 200; /* MHz */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);380 igfx->adpa = snarfreg(igfx, 0x061100);381 igfx->lvds = snarfreg(igfx, 0x061180);382 igfx->sdvob = snarfreg(igfx, 0x061140);383 igfx->sdvoc = snarfreg(igfx, 0x061160);385 for(x=0; x<5; x++)386 igfx->gmbus[x] = snarfreg(igfx, 0x5100 + x*4);387 igfx->gmbus[x] = snarfreg(igfx, 0x5120);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];394 igfx->ppstatus = snarfreg(igfx, 0x61200);395 igfx->ppcontrol = snarfreg(igfx, 0x61204);397 igfx->vgacntrl = snarfreg(igfx, 0x071400);398 break;400 case TypeIVB:401 igfx->npipe = 3; /* A,B,C */402 igfx->cdclk = 400; /* MHz */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);411 igfx->dpllsel = snarfreg(igfx, 0xC7000);413 igfx->drefctl = snarfreg(igfx, 0xC6200);414 igfx->rawclkfreq = snarfreg(igfx, 0xC6204);415 igfx->ssc4params = snarfreg(igfx, 0xC6210);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);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 }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);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);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 */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 */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 */468 for(x=0; x<5; x++)469 igfx->gmbus[x] = snarfreg(igfx, 0xC5100 + x*4);470 igfx->gmbus[x] = snarfreg(igfx, 0xC5120);472 igfx->adpa = snarfreg(igfx, 0x0E1100); /* DAC_CTL */473 igfx->lvds = snarfreg(igfx, 0x0E1180); /* LVDS_CTL */475 igfx->vgacntrl = snarfreg(igfx, 0x041000);476 break;477 }479 for(x=0; x<igfx->npipe; x++)480 snarfpipe(igfx, x);482 for(x=0; x<nelem(vga->edid); x++){483 Modelist *l;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 }509 ctlr->flag |= Fsnarf;510 }512 static void513 options(Vga* vga, Ctlr* ctlr)514 {515 USED(vga);516 ctlr->flag |= Hlinear|Ulinear|Foptions;517 }519 static int520 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;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 }562 static int563 getcref(Igfx *igfx, int x)564 {565 Dpll *dpll;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 }576 static int577 initdpll(Igfx *igfx, int x, int freq, int port)578 {579 int cref, m1, m2, n, p1, p2;580 Dpll *dpll;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;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;601 if(port == PortLCD){602 igfx->drefctl.v |= 2<<11;603 igfx->drefctl.v |= 1;604 } else {605 igfx->drefctl.v |= 2<<9;606 }608 /*609 * PLL Reference Input Select:610 * 000 DREFCLK (default is 120 MHz) for DAC/HDMI/DVI/DP611 * 001 Super SSC 120MHz super-spread clock612 * 011 SSC Spread spectrum input clock (120MHz default) for LVDS/DP613 */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);623 /* Dpll Mode select */624 dpll->ctrl.v &= ~(3<<26);625 dpll->ctrl.v |= (port == PortLCD ? 2 : 1)<<26;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;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 }647 /* Dpll VCO Enable */648 dpll->ctrl.v |= (1<<31);650 /* Dpll Serial DVO High Speed IO clock Enable */651 if(port >= PortDPA)652 dpll->ctrl.v |= (1<<30);653 else654 dpll->ctrl.v &= ~(1<<30);656 /* VGA Mode Disable */657 dpll->ctrl.v |= (1<<28);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;666 /* FP0 P1 Post Divisor */667 dpll->ctrl.v &= ~0xFF0000;668 dpll->ctrl.v |= 0x010000<<(p1-1);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 }677 return 0;678 }680 static void681 initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)682 {683 uvlong m, n;685 n = 0x800000;686 m = (n * ((freq * bpp)/8)) / (lsclk * lanes);688 t->dm[0].v = (tu-1)<<25 | m;689 t->dn[0].v = n;691 n = 0x80000;692 m = (n * freq) / lsclk;694 t->lm[0].v = m;695 t->ln[0].v = n;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 }703 static void704 inittrans(Trans *t, Mode *m)705 {706 /* clear all but 27:28 frame start delay (initialized by bios) */707 t->conf.v &= 3<<27;709 /* tans/pipe enable */710 t->conf.v |= 1<<31;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);718 t->hb.v = t->ht.v;719 t->vb.v = t->vt.v;721 t->vss.v = 0;722 }724 static void725 initpipe(Pipe *p, Mode *m)726 {727 static uchar bpctab[4] = { 8, 10, 6, 12 };728 int i, tu, bpc, lanes;729 Fdi *fdi;731 /* source image size */732 p->src.v = (m->x - 1)<<16 | (m->y - 1);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 }741 /* enable and set monitor timings for cpu pipe */742 inittrans(p, m);744 /* default for displayport */745 tu = 64;746 bpc = 6; /* why */747 lanes = 1;749 fdi = p->fdi;750 if(fdi->rxctl.a != 0){751 /* enable and set monitor timings for transcoder */752 inittrans(fdi, m);754 /* tx port width selection */755 fdi->txctl.v &= ~(7<<19);756 fdi->txctl.v |= (lanes-1)<<19;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 }772 /* enhanced framing on */773 fdi->rxctl.v |= (1<<6);774 fdi->txctl.v |= (1<<18);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 }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 }793 static void794 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;803 m = vga->mode;804 if(m->z != 32)805 error("%s: unsupported color depth %d\n", ctlr->name, m->z);807 igfx = vga->private;809 /* disable vga */810 igfx->vgacntrl.v |= (1<<31);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 }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 else838 port = PortVGA;840 trace("%s: display #%d\n", ctlr->name, port+1);842 switch(port){843 default:844 Badport:845 error("%s: display #%d not supported\n", ctlr->name, port+1);846 break;848 case PortVGA:849 if(igfx->npipe > 2)850 x = (igfx->adpa.v >> 29) & 3;851 else852 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 */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;866 case PortLCD:867 if(igfx->npipe > 2)868 x = (igfx->lvds.v >> 29) & 3;869 else870 x = (igfx->lvds.v >> 30) & 1;871 igfx->lvds.v |= (1<<31);872 igfx->ppcontrol.v |= 5;874 if(igfx->type == TypeG45){875 igfx->lvds.v &= ~(1<<24); /* data format select 18/24bpc */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;883 igfx->lvds.v |= (1<<15); /* border enable */884 }885 break;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);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];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 */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;945 /* virtual width in pixels */946 vga->virtx = p->dsp->stride.v / (m->z / 8);948 /* plane position and size */949 p->dsp->pos.v = 0;950 p->dsp->size.v = (m->y - 1)<<16 | (m->x - 1); /* sic */952 p->dsp->surf.v = 0;953 p->dsp->linoff.v = 0;954 p->dsp->tileoff.v = 0;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;963 if(initdpll(igfx, x, m->frequency, port) < 0)964 error("%s: frequency %d out of range\n", ctlr->name, m->frequency);966 initpipe(p, m);968 ctlr->flag |= Finit;969 }971 static void972 loadtrans(Igfx *igfx, Trans *t)973 {974 int i;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);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]);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);1001 /* enable dpll */1002 t->dpll->ctrl.v |= (1<<31);1003 loadreg(igfx, t->dpll->ctrl);1004 sleep(10);1005 }1007 /* workarround: set timing override bit */1008 csr(igfx, t->chicken.a, 0, 1<<31);1010 /* enable displayport transcoder */1011 loadreg(igfx, t->dpctl);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 }1024 static void1025 enablepipe(Igfx *igfx, int x)1026 {1027 int i;1028 Pipe *p;1030 p = &igfx->pipe[x];1031 if((p->conf.v & (1<<31)) == 0)1032 return; /* pipe is disabled, done */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 }1050 /* image size (vga needs to be off) */1051 loadreg(igfx, p->src);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 }1060 /* keep planes disabled while pipe comes up */1061 if(igfx->type == TypeG45)1062 p->conf.v |= 3<<18;1064 /* enable cpu pipe */1065 loadtrans(igfx, p);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 */1076 /* program cursor */1077 loadreg(igfx, p->cur->cntr);1078 loadreg(igfx, p->cur->pos);1079 loadreg(igfx, p->cur->base); /* arm */1081 /* enable planes */1082 if(igfx->type == TypeG45) {1083 p->conf.v &= ~(3<<18);1084 loadreg(igfx, p->conf);1085 }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);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);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);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 }1111 /* enable the transcoder */1112 loadtrans(igfx, p->fdi);1113 }1115 static void1116 disabletrans(Igfx *igfx, Trans *t)1117 {1118 int i;1120 /* disable displayport transcoder */1121 csr(igfx, t->dpctl.a, 1<<31, 3<<29);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);1133 /* disable dpll */1134 if(t->dpll != nil)1135 csr(igfx, t->dpll->ctrl.a, 1<<31, 0);1136 }1138 static void1139 disablepipe(Igfx *igfx, int x)1140 {1141 Pipe *p;1143 p = &igfx->pipe[x];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 */1152 /* display/overlay/cursor planes off */1153 if(igfx->type == TypeG45)1154 csr(igfx, p->conf.a, 0, 3<<18);1156 /* disable cpu pipe */1157 disabletrans(igfx, p);1159 /* disable panel fitter */1160 if(p->pfit != nil)1161 csr(igfx, p->pfit->ctrl.a, 1<<31, 0);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);1167 /* disable pch transcoder */1168 disabletrans(igfx, p->fdi);1170 /* disable pch dpll enable bit */1171 csr(igfx, igfx->dpllsel.a, 8<<(x*4), 0);1172 }1174 static void1175 load(Vga* vga, Ctlr* ctlr)1176 {1177 Igfx *igfx;1178 int x;1180 igfx = vga->private;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 }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);1202 /* disable vga plane */1203 csr(igfx, igfx->vgacntrl.a, 0, 1<<31);1205 /* turn off all pipes */1206 for(x = 0; x < igfx->npipe; x++)1207 disablepipe(igfx, x);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 }1219 /* program new clock sources */1220 loadreg(igfx, igfx->rawclkfreq);1221 loadreg(igfx, igfx->drefctl);1222 sleep(10);1224 /* set lvds before enabling dpll */1225 loadreg(igfx, igfx->lvds);1227 /* new dpll setting */1228 loadreg(igfx, igfx->dpllsel);1230 /* program all pipes */1231 for(x = 0; x < igfx->npipe; x++)1232 enablepipe(igfx, x);1234 /* program vga plane */1235 loadreg(igfx, igfx->vgacntrl);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 }1246 /* program lcd power */1247 loadreg(igfx, igfx->ppcontrol);1249 ctlr->flag |= Fload;1250 }1252 static void1253 dumpreg(char *name, char *item, Reg r)1254 {1255 if(r.a == 0)1256 return;1258 printitem(name, item);1259 Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);1260 }1262 static void1263 dumphex(char *name, char *item, uchar *data, int len)1264 {1265 int i;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 }1279 static void1280 dumptiming(char *name, Trans *t)1281 {1282 int tu, m, n;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);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 }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 }1305 static void1306 dumptrans(char *name, Trans *t)1307 {1308 dumpreg(name, "conf", t->conf);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]);1319 dumptiming(name, t);1321 dumpreg(name, "ht", t->ht);1322 dumpreg(name, "hb", t->hb);1323 dumpreg(name, "hs", t->hs);1325 dumpreg(name, "vt", t->vt);1326 dumpreg(name, "vb", t->vb);1327 dumpreg(name, "vs", t->vs);1328 dumpreg(name, "vss", t->vss);1330 dumpreg(name, "dpctl", t->dpctl);1331 }1333 static void1334 dumppipe(Igfx *igfx, int x)1335 {1336 char name[32];1337 Pipe *p;1339 p = &igfx->pipe[x];1341 snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);1342 dumpreg(name, "src", p->src);1343 dumptrans(name, p);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]);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);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 }1368 static void1369 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;1377 dpll = &igfx->dpll[x];1378 snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);1380 dumpreg(name, "ctrl", dpll->ctrl);1381 dumpreg(name, "fp0", dpll->fp0);1382 dumpreg(name, "fp1", dpll->fp1);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);1396 n = (dpll->fp0.v >> 16) & 0x3f;1397 m1 = (dpll->fp0.v >> 8) & 0x3f;1398 m2 = (dpll->fp0.v >> 0) & 0x3f;1400 cref = getcref(igfx, x);1401 freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);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);1410 printitem(name, "cref");1411 Bprint(&stdout, " %d\n", cref);1412 printitem(name, "fp0 freq");1413 Bprint(&stdout, " %lld\n", freq);1414 }1416 static void1417 dump(Vga* vga, Ctlr* ctlr)1418 {1419 char name[32];1420 Igfx *igfx;1421 int x;1423 if((igfx = vga->private) == nil)1424 return;1426 for(x=0; x<igfx->npipe; x++)1427 dumppipe(igfx, x);1429 for(x=0; x<nelem(igfx->dpll); x++)1430 dumpdpll(igfx, x);1432 dumpreg(ctlr->name, "dpllsel", igfx->dpllsel);1434 dumpreg(ctlr->name, "drefctl", igfx->drefctl);1435 dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);1436 dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);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 }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 }1458 dumpreg(ctlr->name, "ppcontrol", igfx->ppcontrol);1459 dumpreg(ctlr->name, "ppstatus", igfx->ppstatus);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);1466 dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);1467 }1469 static int1470 dpauxio(Igfx *igfx, Dp *dp, uchar buf[20], int len)1471 {1472 int t, i;1473 u32int w;1475 if(dp->auxctl.a == 0){1476 werrstr("not present");1477 return -1;1478 }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 }1489 /* clear sticky bits */1490 wr(igfx, dp->auxctl.a, (1<<28) | (1<25) | (1<<30));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 }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 }1507 /* hack: slow down a bit */1508 w += 2;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);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 }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 }1546 return len;1547 }1549 enum {1550 CmdNative = 8,1551 CmdMot = 4,1552 CmdRead = 1,1553 CmdWrite = 0,1554 };1556 static int1557 dpauxtra(Igfx *igfx, Dp *dp, int cmd, int addr, uchar *data, int len)1558 {1559 uchar buf[20];1560 int r;1562 assert(len <= 16);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 }1590 static int1591 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 int1599 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 }1606 static int1607 enabledp(Igfx *igfx, Dp *dp)1608 {1609 int try, r;1611 if(dp->ctl.a == 0)1612 return 0;1613 if((dp->ctl.v & (1<<31)) == 0)1614 return 0;1616 /* Link configuration */1617 wdpaux(igfx, dp, 0x100, 0x0A); /* 270Mhz */1618 wdpaux(igfx, dp, 0x101, 0x01); /* one lane */1620 r = 0;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);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);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;1662 Fail:1663 trace("training failed: %x\n", r);1665 /* disable port */1666 dp->ctl.v &= ~(1<<31);1667 loadreg(igfx, dp->ctl);1668 wdpaux(igfx, dp, 0x102, 0x00);1669 return -1;1670 }1672 static uchar*1673 edidshift(uchar buf[256])1674 {1675 uchar tmp[256];1676 int i;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] == 0xFF1681 && 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 }1691 static Edid*1692 snarfdpedid(Igfx *igfx, Dp *dp, int addr)1693 {1694 uchar buf[256];1695 int i;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;1701 if(dp->dpcd[0] == 0) /* nothing there, dont try to get edid */1702 return nil;1704 if(dpauxtra(igfx, dp, CmdMot|CmdRead, addr, nil, 0) < 0)1705 return nil;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 }1721 dpauxtra(igfx, dp, CmdRead, addr, nil, 0);1723 return parseedid128(edidshift(buf));1724 }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 };1735 static int1736 gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)1737 {1738 u32int x, y;1739 int n, t;1741 if(igfx->gmbus[GMBUSCP].a == 0)1742 return -1;1744 wr(igfx, igfx->gmbus[GMBUSCP].a, port);1745 wr(igfx, igfx->gmbus[GMBUSIX].a, 0);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);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;1762 t = 4 - (x & 3);1763 if(t > len)1764 t = len;1765 len -= t;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 }1780 return n;1781 }1783 static Edid*1784 snarfgmedid(Igfx *igfx, int port, int addr)1785 {1786 uchar buf[256];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;1794 return parseedid128(edidshift(buf));1795 }1797 Ctlr igfx = {1798 "igfx", /* name */1799 snarf, /* snarf */1800 options, /* options */1801 init, /* init */1802 load, /* load */1803 dump, /* dump */1804 };1806 Ctlr igfxhwgc = {1807 "igfxhwgc",1808 };