changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: igfx: just kidding, heres the code :)

changeset 4183: 1f534b6b703b
parent 4182: 21c4f525c530
child 4184: 0070b7f7588e
author: cinap_lenrek@felloff.net
date: Fri, 09 Jan 2015 02:58:14 +0100
files: sys/src/cmd/aux/vga/igfx.c
description: igfx: just kidding, heres the code :)
     1.1new file mode 100644
     1.2--- /dev/null
     1.3+++ b/sys/src/cmd/aux/vga/igfx.c
     1.4@@ -0,0 +1,1155 @@
     1.5+#include <u.h>
     1.6+#include <libc.h>
     1.7+#include <bio.h>
     1.8+
     1.9+#include "pci.h"
    1.10+#include "vga.h"
    1.11+
    1.12+typedef struct Reg Reg;
    1.13+typedef struct Dpll Dpll;
    1.14+typedef struct Hdmi Hdmi;
    1.15+typedef struct Dp Dp;
    1.16+typedef struct Fdi Fdi;
    1.17+typedef struct Pfit Pfit;
    1.18+typedef struct Plane Plane;
    1.19+typedef struct Trans Trans;
    1.20+typedef struct Pipe Pipe;
    1.21+
    1.22+enum {
    1.23+	MHz = 1000000,
    1.24+};
    1.25+
    1.26+enum {
    1.27+	TypeG45,
    1.28+	TypeIVB,		/* Ivy Bdige */
    1.29+};
    1.30+
    1.31+struct Reg {
    1.32+	u32int	a;		/* address or 0 when invalid */
    1.33+	u32int	v;		/* value */
    1.34+};
    1.35+
    1.36+struct Dpll {
    1.37+	Reg	ctrl;		/* DPLLx_CTRL */
    1.38+	Reg	fp0;		/* FPx0 */
    1.39+	Reg	fp1;		/* FPx1 */
    1.40+};
    1.41+
    1.42+struct Trans {
    1.43+	Reg	dm[2];		/* pipe/trans DATAM */
    1.44+	Reg	dn[2];		/* pipe/trans DATAN */
    1.45+	Reg	lm[2];		/* pipe/trans LINKM */
    1.46+	Reg	ln[2];		/* pipe/trans LINKN */
    1.47+
    1.48+	Reg	ht;		/* pipe/trans HTOTAL_x */
    1.49+	Reg	hb;		/* pipe/trans HBLANK_x */
    1.50+	Reg	hs;		/* pipe/trans HSYNC_x */
    1.51+	Reg	vt;		/* pipe/trans VTOTAL_x */
    1.52+	Reg	vb;		/* pipe/trans VBLANK_x */
    1.53+	Reg	vs;		/* pipe/trans VSYNC_x */
    1.54+	Reg	vss;		/* pipe/trans VSYNCSHIFT_x */
    1.55+
    1.56+	Reg	conf;		/* pipe/trans CONF_x */
    1.57+	Reg	chicken;	/* workarround register */
    1.58+
    1.59+	Dpll	*dpll;		/* this transcoders dpll */
    1.60+};
    1.61+
    1.62+struct Hdmi {
    1.63+	Reg	ctl;
    1.64+	Reg	bufctl[4];
    1.65+};
    1.66+
    1.67+struct Dp {
    1.68+	Reg	ctl;
    1.69+	Reg	auxctl;
    1.70+	Reg	auxdat[5];
    1.71+};
    1.72+
    1.73+struct Fdi {
    1.74+	Trans;
    1.75+
    1.76+	Reg	txctl;		/* FDI_TX_CTL */
    1.77+
    1.78+	Reg	rxctl;		/* FDI_RX_CTL */
    1.79+	Reg	rxmisc;		/* FDI_RX_MISC */
    1.80+	Reg	rxtu[2];	/* FDI_RX_TUSIZE */
    1.81+
    1.82+	Reg	dpctl;		/* TRANS_DP_CTL_x */
    1.83+};
    1.84+
    1.85+struct Pfit {
    1.86+	Reg	ctrl;
    1.87+	Reg	winpos;
    1.88+	Reg	winsize;
    1.89+	Reg	pwrgate;
    1.90+};
    1.91+
    1.92+struct Plane {
    1.93+	Reg	cntr;		/* DSPxCNTR */
    1.94+	Reg	linoff;		/* DSPxLINOFF */
    1.95+	Reg	stride;		/* DSPxSTRIDE */
    1.96+	Reg	surf;		/* DSPxSURF */
    1.97+	Reg	tileoff;	/* DSPxTILEOFF */
    1.98+};
    1.99+
   1.100+struct Pipe {
   1.101+	Trans;
   1.102+
   1.103+	Reg	src;		/* PIPExSRC */
   1.104+
   1.105+	Fdi	fdi[1];		/* fdi/dp transcoder */
   1.106+
   1.107+	Plane	dsp[1];		/* display plane */
   1.108+	Plane	cur[1];		/* cursor plane */
   1.109+
   1.110+	Pfit	*pfit;		/* selected pfit */
   1.111+};
   1.112+
   1.113+typedef struct Igfx Igfx;
   1.114+struct Igfx {
   1.115+	Ctlr	*ctlr;
   1.116+	Pcidev	*pci;
   1.117+
   1.118+	u32int	pio;
   1.119+
   1.120+	int	type;
   1.121+
   1.122+	int	npipe;
   1.123+	Pipe	pipe[4];
   1.124+
   1.125+	Dpll	dpll[2];
   1.126+	Pfit	pfit[3];
   1.127+
   1.128+	/* IVB */
   1.129+	Reg	dpllsel;	/* DPLL_SEL */
   1.130+	Reg	drefctl;	/* DREF_CTL */
   1.131+	Reg	rawclkfreq;	/* RAWCLK_FREQ */
   1.132+	Reg	ssc4params;	/* SSC4_PARAMS */
   1.133+
   1.134+	Dp	dp[4];
   1.135+	Hdmi	hdmi[4];
   1.136+
   1.137+	Reg	ppcontrol;
   1.138+	Reg	ppstatus;
   1.139+
   1.140+	/* G45 */
   1.141+	Reg	sdvoc;
   1.142+	Reg	sdvob;
   1.143+
   1.144+	/* common */
   1.145+	Reg	adpa;
   1.146+	Reg	lvds;
   1.147+
   1.148+	Reg	vgacntrl;
   1.149+};
   1.150+
   1.151+static u32int
   1.152+rr(Igfx *igfx, u32int a)
   1.153+{
   1.154+	if(a == 0)
   1.155+		return 0;
   1.156+	assert((a & 3) == 0);
   1.157+	outportl(igfx->pio, a);
   1.158+	return inportl(igfx->pio + 4);
   1.159+}
   1.160+static void
   1.161+wr(Igfx *igfx, u32int a, u32int v)
   1.162+{
   1.163+	if(a == 0)	/* invalid */
   1.164+		return;
   1.165+
   1.166+	assert((a & 3) == 0);
   1.167+	outportl(igfx->pio, a);
   1.168+	outportl(igfx->pio + 4, v);
   1.169+}
   1.170+static void
   1.171+csr(Igfx *igfx, u32int reg, u32int clr, u32int set)
   1.172+{
   1.173+	wr(igfx, reg, (rr(igfx, reg) & ~clr) | set);
   1.174+}
   1.175+
   1.176+static void
   1.177+loadreg(Igfx *igfx, Reg r)
   1.178+{
   1.179+	wr(igfx, r.a, r.v);
   1.180+}
   1.181+
   1.182+static Reg
   1.183+snarfreg(Igfx *igfx, u32int a)
   1.184+{
   1.185+	Reg r;
   1.186+
   1.187+	r.a = a;
   1.188+	r.v = rr(igfx, a);
   1.189+	return r;
   1.190+}
   1.191+
   1.192+static void
   1.193+snarftrans(Igfx *igfx, Trans *t, u32int o)
   1.194+{
   1.195+	/* pipe timing */
   1.196+	t->ht	= snarfreg(igfx, o + 0x00000);
   1.197+	t->hb	= snarfreg(igfx, o + 0x00004);
   1.198+	t->hs	= snarfreg(igfx, o + 0x00008);
   1.199+	t->vt	= snarfreg(igfx, o + 0x0000C);
   1.200+	t->vb	= snarfreg(igfx, o + 0x00010);
   1.201+	t->vs	= snarfreg(igfx, o + 0x00014);
   1.202+	t->vss	= snarfreg(igfx, o + 0x00028);
   1.203+
   1.204+	t->conf	= snarfreg(igfx, o + 0x10008);
   1.205+
   1.206+	switch(igfx->type){
   1.207+	case TypeG45:
   1.208+		if(t == &igfx->pipe[0]){			/* PIPEA */
   1.209+			t->dm[0] = snarfreg(igfx, 0x70050);	/* GMCHDataM */
   1.210+			t->dn[0] = snarfreg(igfx, 0x70054);	/* GMCHDataN */
   1.211+			t->lm[0] = snarfreg(igfx, 0x70060);	/* DPLinkM */
   1.212+			t->ln[0] = snarfreg(igfx, 0x70064);	/* DPLinkN */
   1.213+		}
   1.214+		break;
   1.215+	case TypeIVB:
   1.216+		t->dm[0] = snarfreg(igfx, o + 0x30);
   1.217+		t->dn[0] = snarfreg(igfx, o + 0x34);
   1.218+		t->dm[1] = snarfreg(igfx, o + 0x38);
   1.219+		t->dn[1] = snarfreg(igfx, o + 0x3c);
   1.220+		t->lm[0] = snarfreg(igfx, o + 0x40);
   1.221+		t->ln[0] = snarfreg(igfx, o + 0x44);
   1.222+		t->lm[1] = snarfreg(igfx, o + 0x48);
   1.223+		t->ln[1] = snarfreg(igfx, o + 0x4c);
   1.224+		break;
   1.225+	}
   1.226+}
   1.227+
   1.228+static void
   1.229+snarfpipe(Igfx *igfx, int x)
   1.230+{
   1.231+	u32int o;
   1.232+	Pipe *p;
   1.233+
   1.234+	p = &igfx->pipe[x];
   1.235+
   1.236+	o = 0x60000 | x*0x1000;
   1.237+	snarftrans(igfx, p, o);
   1.238+
   1.239+	p->src = snarfreg(igfx, o + 0x0001C);
   1.240+
   1.241+	if(igfx->type == TypeIVB) {
   1.242+		p->fdi->txctl = snarfreg(igfx, o + 0x100);
   1.243+
   1.244+		o = 0xE0000 | x*0x1000;
   1.245+		snarftrans(igfx, p->fdi, o);
   1.246+
   1.247+		p->fdi->dpctl = snarfreg(igfx, o + 0x300);
   1.248+
   1.249+		p->fdi->rxctl = snarfreg(igfx, o + 0x1000c);
   1.250+		p->fdi->rxmisc = snarfreg(igfx, o + 0x10010);
   1.251+		p->fdi->rxtu[0] = snarfreg(igfx, o + 0x10030);
   1.252+		p->fdi->rxtu[1] = snarfreg(igfx, o + 0x10038);
   1.253+
   1.254+		p->fdi->chicken = snarfreg(igfx, o + 0x10064);
   1.255+
   1.256+		p->fdi->dpll = &igfx->dpll[(igfx->dpllsel.v>>(x*4)) & 1];
   1.257+		p->dpll = nil;
   1.258+	} else {
   1.259+		p->dpll = &igfx->dpll[x & 1];
   1.260+	}
   1.261+
   1.262+	/* display plane */
   1.263+	p->dsp->cntr		= snarfreg(igfx, 0x70180 | x*0x1000);
   1.264+	p->dsp->linoff		= snarfreg(igfx, 0x70184 | x*0x1000);
   1.265+	p->dsp->stride		= snarfreg(igfx, 0x70188 | x*0x1000);
   1.266+	p->dsp->tileoff		= snarfreg(igfx, 0x701A4 | x*0x1000);
   1.267+	p->dsp->surf		= snarfreg(igfx, 0x7019C | x*0x1000);
   1.268+
   1.269+	/* cursor plane */
   1.270+	switch(igfx->type){
   1.271+	case TypeIVB:
   1.272+		p->cur->cntr	= snarfreg(igfx, 0x70080 | x*0x1000);
   1.273+		p->cur->surf	= snarfreg(igfx, 0x70084 | x*0x1000);
   1.274+		break;
   1.275+	case TypeG45:
   1.276+		p->cur->cntr	= snarfreg(igfx, 0x70080 | x*0x40);
   1.277+		p->cur->surf	= snarfreg(igfx, 0x70084 | x*0x40);
   1.278+		break;
   1.279+	}
   1.280+}
   1.281+
   1.282+static int
   1.283+devtype(Igfx *igfx)
   1.284+{
   1.285+	if(igfx->pci->vid != 0x8086)
   1.286+		return -1;
   1.287+	switch(igfx->pci->did){
   1.288+	case 0x0166:	/* X230 */
   1.289+		return TypeIVB;
   1.290+
   1.291+	case 0x2a42:	/* X200s */
   1.292+		return TypeG45;
   1.293+	}
   1.294+	return -1;
   1.295+}
   1.296+
   1.297+static void
   1.298+snarf(Vga* vga, Ctlr* ctlr)
   1.299+{
   1.300+	Igfx *igfx;
   1.301+	int x, y;
   1.302+
   1.303+	igfx = vga->private;
   1.304+	if(igfx == nil) {
   1.305+		igfx = alloc(sizeof(Igfx));
   1.306+		igfx->ctlr = ctlr;
   1.307+		igfx->pci = vga->pci;
   1.308+		if(igfx->pci == nil){
   1.309+			error("%s: no pci device\n", ctlr->name);
   1.310+			return;
   1.311+		}
   1.312+		igfx->type = devtype(igfx);
   1.313+		if(igfx->type < 0){
   1.314+			error("%s: unrecognized device\n", ctlr->name);
   1.315+			return;
   1.316+		}
   1.317+		if((igfx->pci->mem[4].bar & 1) == 0){
   1.318+			error("%s: no pio bar\n", ctlr->name);
   1.319+			return;
   1.320+		}
   1.321+		igfx->pio = igfx->pci->mem[4].bar & ~1;
   1.322+		vga->private = igfx;
   1.323+	}
   1.324+
   1.325+	switch(igfx->type){
   1.326+	case TypeG45:
   1.327+		igfx->npipe = 2;	/* A,B */
   1.328+
   1.329+		igfx->dpll[0].ctrl	= snarfreg(igfx, 0x06014);
   1.330+		igfx->dpll[0].fp0	= snarfreg(igfx, 0x06040);
   1.331+		igfx->dpll[0].fp1	= snarfreg(igfx, 0x06044);
   1.332+		igfx->dpll[1].ctrl	= snarfreg(igfx, 0x06018);
   1.333+		igfx->dpll[1].fp0	= snarfreg(igfx, 0x06048);
   1.334+		igfx->dpll[1].fp1	= snarfreg(igfx, 0x0604c);
   1.335+
   1.336+		igfx->adpa		= snarfreg(igfx, 0x061100);
   1.337+		igfx->lvds		= snarfreg(igfx, 0x061180);
   1.338+		igfx->sdvob		= snarfreg(igfx, 0x061140);
   1.339+		igfx->sdvoc		= snarfreg(igfx, 0x061160);
   1.340+
   1.341+		igfx->pfit[0].ctrl	= snarfreg(igfx, 0x061230);
   1.342+		y = (igfx->pfit[0].ctrl.v >> 29) & 3;
   1.343+		if(igfx->pipe[y].pfit == nil)
   1.344+			igfx->pipe[y].pfit = &igfx->pfit[0];
   1.345+
   1.346+		igfx->vgacntrl		= snarfreg(igfx, 0x071400);
   1.347+		break;
   1.348+
   1.349+	case TypeIVB:
   1.350+		igfx->npipe = 3;	/* A,B,C */
   1.351+
   1.352+		igfx->dpll[0].ctrl	= snarfreg(igfx, 0xC6014);
   1.353+		igfx->dpll[0].fp0	= snarfreg(igfx, 0xC6040);
   1.354+		igfx->dpll[0].fp1	= snarfreg(igfx, 0xC6044);
   1.355+		igfx->dpll[1].ctrl	= snarfreg(igfx, 0xC6018);
   1.356+		igfx->dpll[1].fp0	= snarfreg(igfx, 0xC6048);
   1.357+		igfx->dpll[1].fp1	= snarfreg(igfx, 0xC604c);
   1.358+
   1.359+		igfx->dpllsel		= snarfreg(igfx, 0xC7000);
   1.360+
   1.361+		igfx->drefctl		= snarfreg(igfx, 0xC6200);
   1.362+		igfx->rawclkfreq	= snarfreg(igfx, 0xC6204);
   1.363+		igfx->ssc4params	= snarfreg(igfx, 0xC6210);
   1.364+
   1.365+		/* cpu displayport A*/
   1.366+		igfx->dp[0].ctl		= snarfreg(igfx, 0x64000);
   1.367+		igfx->dp[0].auxctl	= snarfreg(igfx, 0x64010);
   1.368+		igfx->dp[0].auxdat[0]	= snarfreg(igfx, 0x64014);
   1.369+		igfx->dp[0].auxdat[1]	= snarfreg(igfx, 0x64018);
   1.370+		igfx->dp[0].auxdat[2]	= snarfreg(igfx, 0x6401C);
   1.371+		igfx->dp[0].auxdat[3]	= snarfreg(igfx, 0x64020);
   1.372+		igfx->dp[0].auxdat[4]	= snarfreg(igfx, 0x64024);
   1.373+
   1.374+		/* pch displayport B,C,D */
   1.375+		for(x=1; x<4; x++){
   1.376+			igfx->dp[x].ctl		= snarfreg(igfx, 0xE4000 + 0x100*x);
   1.377+			igfx->dp[x].auxctl	= snarfreg(igfx, 0xE4010 + 0x100*x);
   1.378+			igfx->dp[x].auxdat[0]	= snarfreg(igfx, 0xE4014 + 0x100*x);
   1.379+			igfx->dp[x].auxdat[1]	= snarfreg(igfx, 0xE4018 + 0x100*x);
   1.380+			igfx->dp[x].auxdat[2]	= snarfreg(igfx, 0xE401C + 0x100*x);
   1.381+			igfx->dp[x].auxdat[3]	= snarfreg(igfx, 0xE4020 + 0x100*x);
   1.382+			igfx->dp[x].auxdat[4]	= snarfreg(igfx, 0xE4024 + 0x100*x);
   1.383+		}
   1.384+
   1.385+		for(x=0; x<3; x++){
   1.386+			igfx->pfit[x].pwrgate	= snarfreg(igfx, 0x68060 + 0x800*x);
   1.387+			igfx->pfit[x].winpos	= snarfreg(igfx, 0x68070 + 0x800*x);
   1.388+			igfx->pfit[x].winsize	= snarfreg(igfx, 0x68074 + 0x800*x);
   1.389+			igfx->pfit[x].ctrl	= snarfreg(igfx, 0x68080 + 0x800*x);
   1.390+
   1.391+			y = (igfx->pfit[x].ctrl.v >> 29) & 3;
   1.392+			if(igfx->pipe[y].pfit == nil)
   1.393+				igfx->pipe[y].pfit = &igfx->pfit[x];
   1.394+		}
   1.395+		igfx->ppstatus		= snarfreg(igfx, 0xC7200);
   1.396+		igfx->ppcontrol		= snarfreg(igfx, 0xC7204);
   1.397+
   1.398+		igfx->hdmi[1].ctl	= snarfreg(igfx, 0x0E1140);	/* HDMI_CTL_B */
   1.399+		igfx->hdmi[1].bufctl[0]	= snarfreg(igfx, 0x0FC810);	/* HTMI_BUF_CTL_0 */
   1.400+		igfx->hdmi[1].bufctl[1]	= snarfreg(igfx, 0x0FC81C);	/* HTMI_BUF_CTL_1 */
   1.401+		igfx->hdmi[1].bufctl[2]	= snarfreg(igfx, 0x0FC828);	/* HTMI_BUF_CTL_2 */
   1.402+		igfx->hdmi[1].bufctl[3]	= snarfreg(igfx, 0x0FC834);	/* HTMI_BUF_CTL_3 */
   1.403+
   1.404+		igfx->hdmi[2].ctl	= snarfreg(igfx, 0x0E1150);	/* HDMI_CTL_C */
   1.405+		igfx->hdmi[2].bufctl[0]	= snarfreg(igfx, 0x0FCC00);	/* HTMI_BUF_CTL_4 */
   1.406+		igfx->hdmi[2].bufctl[1]	= snarfreg(igfx, 0x0FCC0C);	/* HTMI_BUF_CTL_5 */
   1.407+		igfx->hdmi[2].bufctl[2]	= snarfreg(igfx, 0x0FCC18);	/* HTMI_BUF_CTL_6 */
   1.408+		igfx->hdmi[2].bufctl[3]	= snarfreg(igfx, 0x0FCC24);	/* HTMI_BUF_CTL_7 */
   1.409+
   1.410+		igfx->hdmi[3].ctl	= snarfreg(igfx, 0x0E1160);	/* HDMI_CTL_D */
   1.411+		igfx->hdmi[3].bufctl[0]	= snarfreg(igfx, 0x0FD000);	/* HTMI_BUF_CTL_8 */
   1.412+		igfx->hdmi[3].bufctl[1]	= snarfreg(igfx, 0x0FD00C);	/* HTMI_BUF_CTL_9 */
   1.413+		igfx->hdmi[3].bufctl[2]	= snarfreg(igfx, 0x0FD018);	/* HTMI_BUF_CTL_10 */
   1.414+		igfx->hdmi[3].bufctl[3]	= snarfreg(igfx, 0x0FD024);	/* HTMI_BUF_CTL_11 */
   1.415+
   1.416+		igfx->adpa		= snarfreg(igfx, 0x0E1100);	/* DAC_CTL */
   1.417+		igfx->lvds		= snarfreg(igfx, 0x0E1180);	/* LVDS_CTL */
   1.418+
   1.419+		igfx->vgacntrl		= snarfreg(igfx, 0x041000);
   1.420+		break;
   1.421+	}
   1.422+
   1.423+	for(x=0; x<igfx->npipe; x++)
   1.424+		snarfpipe(igfx, x);
   1.425+
   1.426+	ctlr->flag |= Fsnarf;
   1.427+}
   1.428+
   1.429+static void
   1.430+options(Vga* vga, Ctlr* ctlr)
   1.431+{
   1.432+	USED(vga);
   1.433+	ctlr->flag |= Hlinear|Ulinear|Foptions;
   1.434+}
   1.435+
   1.436+static int
   1.437+genpll(int freq, int cref, int P2, int *m1, int *m2, int *n, int *p1)
   1.438+{
   1.439+	int M1, M2, M, N, P, P1;
   1.440+	int best, error;
   1.441+	vlong a;
   1.442+
   1.443+	best = -1;
   1.444+	for(N=3; N<=8; N++)
   1.445+	for(M2=5; M2<=9; M2++)
   1.446+	for(M1=10; M1<=20; M1++){
   1.447+		M = 5*(M1+2) + (M2+2);
   1.448+		if(M < 70 || M > 120)
   1.449+			continue;
   1.450+		for(P1=1; P1<=8; P1++){
   1.451+			P = P1 * P2;
   1.452+			if(P < 4 || P > 98)
   1.453+				continue;
   1.454+			a = cref;
   1.455+			a *= M;
   1.456+			a /= N+2;
   1.457+			a /= P;
   1.458+			if(a < 20*MHz || a > 400*MHz)
   1.459+				continue;
   1.460+			error = a;
   1.461+			error -= freq;
   1.462+			if(error < 0)
   1.463+				error = -error;
   1.464+			if(best < 0 || error < best){
   1.465+				best = error;
   1.466+				*m1 = M1;
   1.467+				*m2 = M2;
   1.468+				*n = N;
   1.469+				*p1 = P1;
   1.470+			}
   1.471+		}
   1.472+	}
   1.473+	return best;
   1.474+}
   1.475+
   1.476+static int
   1.477+initdpll(Igfx *igfx, int x, int freq, int islvds, int ishdmi)
   1.478+{
   1.479+	int cref, m1, m2, n, p1, p2;
   1.480+	Dpll *dpll;
   1.481+
   1.482+	switch(igfx->type){
   1.483+	case TypeG45:
   1.484+		/* PLL Reference Input Select */
   1.485+		dpll = igfx->pipe[x].dpll;
   1.486+		dpll->ctrl.v &= ~(3<<13);
   1.487+		dpll->ctrl.v |= (islvds ? 2 : 0) << 13;
   1.488+		cref = islvds ? 100*MHz : 96*MHz;
   1.489+		break;
   1.490+	case TypeIVB:
   1.491+		/* transcoder dpll enable */
   1.492+		igfx->dpllsel.v |= 8<<(x*4);
   1.493+		/* program rawclock to 125MHz */
   1.494+		igfx->rawclkfreq.v = 125;
   1.495+		if(islvds){
   1.496+			/* 120MHz SSC integrated source enable */
   1.497+			igfx->drefctl.v &= ~(3<<11);
   1.498+			igfx->drefctl.v |= 2<<11;
   1.499+
   1.500+			/* 120MHz SSC4 modulation en */	
   1.501+			igfx->drefctl.v |= 2;
   1.502+		}
   1.503+		/*
   1.504+		 * PLL Reference Input Select:
   1.505+		 * 000	DREFCLK		(default is 120 MHz) for DAC/HDMI/DVI/DP
   1.506+		 * 001	Super SSC	120MHz super-spread clock
   1.507+		 * 011	SSC		Spread spectrum input clock (120MHz default) for LVDS/DP
   1.508+		 */
   1.509+		dpll = igfx->pipe[x].fdi->dpll;
   1.510+		dpll->ctrl.v &= ~(7<<13);
   1.511+		dpll->ctrl.v |= (islvds ? 3 : 0) << 13;
   1.512+		cref = 120*MHz;
   1.513+		break;
   1.514+	default:
   1.515+		return -1;
   1.516+	}
   1.517+
   1.518+	/* Dpll Mode select */
   1.519+	dpll->ctrl.v &= ~(3<<26);
   1.520+	dpll->ctrl.v |= (islvds ? 2 : 1)<<26;
   1.521+
   1.522+	/* P2 Clock Divide */
   1.523+	dpll->ctrl.v &= ~(3<<24);	
   1.524+	if(islvds){
   1.525+		p2 = 14;
   1.526+		if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
   1.527+			return -1;
   1.528+	} else {
   1.529+		p2 = 10;
   1.530+		if(freq > 270*MHz){
   1.531+			p2 >>= 1;
   1.532+			dpll->ctrl.v |= (1<<24);
   1.533+		}
   1.534+		if(genpll(freq, cref, p2, &m1, &m2, &n, &p1) < 0)
   1.535+			return -1;
   1.536+	}
   1.537+
   1.538+	/* Dpll VCO Enable */
   1.539+	dpll->ctrl.v |= (1<<31);
   1.540+
   1.541+	/* Dpll Serial DVO High Speed IO clock Enable */
   1.542+	if(ishdmi)
   1.543+		dpll->ctrl.v |= (1<<30);
   1.544+	else
   1.545+		dpll->ctrl.v &= ~(1<<30);
   1.546+
   1.547+	/* VGA Mode Disable */
   1.548+	dpll->ctrl.v |= (1<<28);
   1.549+
   1.550+	/* P1 Post Divisor */
   1.551+	dpll->ctrl.v &= ~0xFF00FF;
   1.552+	dpll->ctrl.v |= 0x10001<<(p1-1);
   1.553+
   1.554+	dpll->fp0.v &= ~(0x3f<<16);
   1.555+	dpll->fp0.v |= n << 16;
   1.556+	dpll->fp0.v &= ~(0x3f<<8);
   1.557+	dpll->fp0.v |= m1 << 8;
   1.558+	dpll->fp0.v &= ~(0x3f<<0);
   1.559+	dpll->fp0.v |= m2 << 0;
   1.560+
   1.561+	dpll->fp1.v = dpll->fp0.v;
   1.562+
   1.563+	return 0;
   1.564+}
   1.565+
   1.566+static void
   1.567+initdatalinkmn(Trans *t, int freq, int lsclk, int lanes, int tu, int bpp)
   1.568+{
   1.569+	uvlong m, n;
   1.570+
   1.571+	n = 0x800000;
   1.572+	m = (n * ((freq * bpp)/8)) / (lsclk * lanes);
   1.573+	t->dm[0].v = (tu-1)<<25 | m;
   1.574+	t->dn[0].v = n;
   1.575+
   1.576+	n = 0x80000;
   1.577+	m = (n * freq) / lsclk;
   1.578+	t->lm[0].v = m;
   1.579+	t->ln[0].v = n;
   1.580+
   1.581+	t->dm[1].v = t->dm[0].v;
   1.582+	t->dn[1].v = t->dn[0].v;
   1.583+	t->lm[1].v = t->lm[0].v;
   1.584+	t->ln[1].v = t->ln[0].v;
   1.585+}
   1.586+
   1.587+static void
   1.588+inittrans(Trans *t, Mode *m)
   1.589+{
   1.590+	/* tans/pipe enable */
   1.591+	t->conf.v = 1<<31;
   1.592+
   1.593+	/* trans/pipe timing */
   1.594+	t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
   1.595+	t->hb.v = t->ht.v;
   1.596+	t->hs.v = (m->ehs - 1)<<16 | (m->shs - 1);
   1.597+	t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
   1.598+	t->vb.v = t->vt.v;
   1.599+	t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
   1.600+	t->vss.v = 0;
   1.601+}
   1.602+
   1.603+static void
   1.604+initpipe(Pipe *p, Mode *m)
   1.605+{
   1.606+	static uchar bpctab[4] = { 8, 10, 6, 12 };
   1.607+	int i, tu, bpc, lanes;
   1.608+	Fdi *fdi;
   1.609+
   1.610+	/* source image size */
   1.611+	p->src.v = (m->x - 1)<<16 | (m->y - 1);
   1.612+
   1.613+	if(p->pfit != nil){
   1.614+		/* panel fitter enable, hardcoded coefficients */
   1.615+		p->pfit->ctrl.v = 1<<31 | 1<<23;
   1.616+		p->pfit->winpos.v = 0;
   1.617+		p->pfit->winsize.v = (m->x << 16) | m->y;
   1.618+	}
   1.619+
   1.620+	/* enable and set monitor timings for cpu pipe */
   1.621+	inittrans(p, m);
   1.622+
   1.623+	/* default for displayport */
   1.624+	tu = 64;
   1.625+	bpc = 8;
   1.626+	lanes = 1;
   1.627+
   1.628+	fdi = p->fdi;
   1.629+	if(fdi->rxctl.a != 0){
   1.630+		/* enable and set monitor timings for transcoder */
   1.631+		inittrans(fdi, m);
   1.632+
   1.633+		/*
   1.634+		 * hack:
   1.635+		 * we do not program fdi in load(), so use
   1.636+		 * snarfed bios initialized values for now.
   1.637+		 */
   1.638+		if(fdi->rxctl.v & (1<<31)){
   1.639+			tu = 1+(fdi->rxtu[0].v >> 25);
   1.640+			bpc = bpctab[(fdi->rxctl.v >> 16) & 3];
   1.641+			lanes = 1+((fdi->rxctl.v >> 19) & 7);
   1.642+		}
   1.643+
   1.644+		/* fdi tx enable */
   1.645+		fdi->txctl.v |= (1<<31);
   1.646+		/* tx port width selection */
   1.647+		fdi->txctl.v &= ~(7<<19);
   1.648+		fdi->txctl.v |= (lanes-1)<<19;
   1.649+		/* tx fdi pll enable */
   1.650+		fdi->txctl.v |= (1<<14);
   1.651+		/* clear auto training bits */
   1.652+		fdi->txctl.v &= ~(7<<8 | 1);
   1.653+
   1.654+		/* fdi rx enable */
   1.655+		fdi->rxctl.v |= (1<<31);
   1.656+		/* rx port width selection */
   1.657+		fdi->rxctl.v &= ~(7<<19);
   1.658+		fdi->rxctl.v |= (lanes-1)<<19;
   1.659+		/* bits per color for transcoder */
   1.660+		for(i=0; i<nelem(bpctab); i++){
   1.661+			if(bpctab[i] == bpc){
   1.662+				fdi->rxctl.v &= ~(7<<16);
   1.663+				fdi->rxctl.v |= i<<16;
   1.664+				fdi->dpctl.v &= ~(7<<9);
   1.665+				fdi->dpctl.v |= i<<9;
   1.666+				break;
   1.667+			}
   1.668+		}
   1.669+		/* rx fdi pll enable */
   1.670+		fdi->rxctl.v |= (1<<13);
   1.671+		/* rx fdi rawclk to pcdclk selection */
   1.672+		fdi->rxctl.v |= (1<<4);
   1.673+
   1.674+		/* tusize 1 and 2 */
   1.675+		fdi->rxtu[0].v = (tu-1)<<25;
   1.676+		fdi->rxtu[1].v = (tu-1)<<25;
   1.677+		initdatalinkmn(fdi, m->frequency, 270*MHz, lanes, tu, 3*bpc);
   1.678+	}
   1.679+
   1.680+	/* bits per color for cpu pipe */
   1.681+	for(i=0; i<nelem(bpctab); i++){
   1.682+		if(bpctab[i] == bpc){
   1.683+			p->conf.v &= ~(7<<5);
   1.684+			p->conf.v |= i<<5;
   1.685+			break;
   1.686+		}
   1.687+	}
   1.688+	initdatalinkmn(p, m->frequency, 270*MHz, lanes, tu, 3*bpc);
   1.689+}
   1.690+
   1.691+static void
   1.692+init(Vga* vga, Ctlr* ctlr)
   1.693+{
   1.694+	int x, islvds;
   1.695+	char *val;
   1.696+	Igfx *igfx;
   1.697+	Pipe *p;
   1.698+	Mode *m;
   1.699+
   1.700+	m = vga->mode;
   1.701+	if(m->z != 32)
   1.702+		error("%s: unsupported color depth %d\n", ctlr->name, m->z);
   1.703+
   1.704+	igfx = vga->private;
   1.705+
   1.706+	/* disable vga */
   1.707+	igfx->vgacntrl.v |= (1<<31);
   1.708+
   1.709+	x = 0;
   1.710+	islvds = 0;
   1.711+	if((val = dbattr(m->attr, "lcd")) != nil && atoi(val) != 0){
   1.712+		islvds = 1;
   1.713+
   1.714+		if(igfx->npipe > 2)
   1.715+			x = (igfx->lvds.v >> 29) & 3;
   1.716+		else
   1.717+			x = (igfx->lvds.v >> 30) & 1;
   1.718+		igfx->lvds.v |= (1<<31);
   1.719+
   1.720+		igfx->ppcontrol.v &= ~0xFFFF0000;
   1.721+		igfx->ppcontrol.v |= 5;
   1.722+	}
   1.723+	p = &igfx->pipe[x];
   1.724+
   1.725+	/* plane enable, 32bpp and assign pipe */
   1.726+	p->dsp->cntr.v = (1<<31) | (6<<26) | (x<<24);
   1.727+
   1.728+	/* stride must be 64 byte aligned */
   1.729+	p->dsp->stride.v = m->x * (m->z / 8);
   1.730+	p->dsp->stride.v += 63;
   1.731+	p->dsp->stride.v &= ~63;
   1.732+
   1.733+	/* virtual width in pixels */
   1.734+	vga->virtx = p->dsp->stride.v / (m->z / 8);
   1.735+
   1.736+	p->dsp->surf.v = 0;
   1.737+	p->dsp->linoff.v = 0;
   1.738+	p->dsp->tileoff.v = 0;
   1.739+
   1.740+	/* cursor plane off */
   1.741+	p->cur->cntr.v = 0;
   1.742+	p->cur->surf.v = 0;
   1.743+
   1.744+	if(initdpll(igfx, x, m->frequency, islvds, 0) < 0)
   1.745+		error("%s: frequency %d out of range\n", ctlr->name, m->frequency);
   1.746+
   1.747+	initpipe(p, m);
   1.748+
   1.749+	/*
   1.750+	 * undocumented magic that makes the flickering
   1.751+	 * top bar go away on x230 on lcd. found by
   1.752+	 * comparing registers set by vesa bios.
   1.753+	 */
   1.754+	if(igfx->type == TypeIVB && islvds)
   1.755+		p->conf.v |= 3<<27;
   1.756+
   1.757+	ctlr->flag |= Finit;
   1.758+}
   1.759+
   1.760+static void
   1.761+loadtrans(Igfx *igfx, Trans *t)
   1.762+{
   1.763+	int i;
   1.764+
   1.765+	/* program trans/pipe timings */
   1.766+	loadreg(igfx, t->ht);
   1.767+	loadreg(igfx, t->hb);
   1.768+	loadreg(igfx, t->hs);
   1.769+	loadreg(igfx, t->vt);
   1.770+	loadreg(igfx, t->vb);
   1.771+	loadreg(igfx, t->vs);
   1.772+	loadreg(igfx, t->vss);
   1.773+
   1.774+	loadreg(igfx, t->dm[0]);
   1.775+	loadreg(igfx, t->dn[0]);
   1.776+	loadreg(igfx, t->lm[0]);
   1.777+	loadreg(igfx, t->ln[0]);
   1.778+	loadreg(igfx, t->dm[1]);
   1.779+	loadreg(igfx, t->dn[1]);
   1.780+	loadreg(igfx, t->lm[1]);
   1.781+	loadreg(igfx, t->ln[1]);
   1.782+
   1.783+	if(t->dpll != nil){
   1.784+		/* program dpll */
   1.785+		t->dpll->ctrl.v &= ~(1<<31);
   1.786+		loadreg(igfx, t->dpll->ctrl);
   1.787+		loadreg(igfx, t->dpll->fp0);
   1.788+		loadreg(igfx, t->dpll->fp1);
   1.789+
   1.790+		/* enable dpll */
   1.791+		t->dpll->ctrl.v |= (1<<31);
   1.792+		loadreg(igfx, t->dpll->ctrl);
   1.793+		sleep(10);
   1.794+	}
   1.795+
   1.796+	/* workarround: set timing override bit */
   1.797+	csr(igfx, t->chicken.a, 0, 1<<31);
   1.798+
   1.799+	/* enable trans/pipe */
   1.800+	t->conf.v |= (1<<31);
   1.801+	t->conf.v &= ~(1<<30);
   1.802+	loadreg(igfx, t->conf);
   1.803+	for(i=0; i<100; i++){
   1.804+		sleep(10);
   1.805+		if(rr(igfx, t->conf.a) & (1<<30))
   1.806+			break;
   1.807+	}
   1.808+}
   1.809+
   1.810+static void
   1.811+enablepipe(Igfx *igfx, int x)
   1.812+{
   1.813+	Pipe *p;
   1.814+
   1.815+	p = &igfx->pipe[x];
   1.816+	if((p->conf.v & (1<<31)) == 0)
   1.817+		return;	/* pipe is disabled, done */
   1.818+
   1.819+	if(0){
   1.820+		p->fdi->rxctl.v &= ~(1<<31);
   1.821+		loadreg(igfx, p->fdi->rxctl);
   1.822+		sleep(5);
   1.823+		p->fdi->txctl.v &= ~(1<<31);
   1.824+		loadreg(igfx, p->fdi->txctl);
   1.825+		sleep(5);
   1.826+	}
   1.827+
   1.828+	/* image size (vga needs to be off) */
   1.829+	loadreg(igfx, p->src);
   1.830+
   1.831+	/* set panel fitter as needed */
   1.832+	if(p->pfit != nil){
   1.833+		loadreg(igfx, p->pfit->ctrl);
   1.834+		loadreg(igfx, p->pfit->winpos);
   1.835+		loadreg(igfx, p->pfit->winsize);	/* arm */
   1.836+	}
   1.837+
   1.838+	/* enable cpu pipe */
   1.839+	loadtrans(igfx, p);
   1.840+
   1.841+	/* program plane */
   1.842+	loadreg(igfx, p->dsp->cntr);
   1.843+	loadreg(igfx, p->dsp->linoff);
   1.844+	loadreg(igfx, p->dsp->stride);
   1.845+	loadreg(igfx, p->dsp->tileoff);
   1.846+	loadreg(igfx, p->dsp->surf);	/* arm */
   1.847+
   1.848+	loadreg(igfx, p->cur->cntr);
   1.849+	loadreg(igfx, p->cur->surf);	/* arm */
   1.850+
   1.851+	if(0){
   1.852+		/* enable fdi */
   1.853+		loadreg(igfx, p->fdi->rxtu[1]);
   1.854+		loadreg(igfx, p->fdi->rxtu[0]);
   1.855+		loadreg(igfx, p->fdi->rxmisc);
   1.856+		p->fdi->rxctl.v &= ~(3<<8 | 1<<10 | 3);
   1.857+		p->fdi->rxctl.v |= (1<<31);
   1.858+		loadreg(igfx, p->fdi->rxctl);
   1.859+
   1.860+		p->fdi->txctl.v &= ~(3<<8 | 1<<10 | 2);
   1.861+		p->fdi->txctl.v |= (1<<31);
   1.862+		loadreg(igfx, p->fdi->txctl);
   1.863+	}
   1.864+
   1.865+	/* enable the transcoder */
   1.866+	loadtrans(igfx, p->fdi);
   1.867+}
   1.868+
   1.869+static void
   1.870+disabletrans(Igfx *igfx, Trans *t)
   1.871+{
   1.872+	int i;
   1.873+
   1.874+	/* the front fell off on x230 */
   1.875+	if(igfx->type == TypeIVB && t == &igfx->pipe[0])
   1.876+		goto skippipe;
   1.877+
   1.878+	/* disable transcoder / pipe */
   1.879+	csr(igfx, t->conf.a, 1<<31, 0);
   1.880+	for(i=0; i<100; i++){
   1.881+		sleep(10);
   1.882+		if((rr(igfx, t->conf.a) & (1<<30)) == 0)
   1.883+			break;
   1.884+	}
   1.885+	/* workarround: clear timing override bit */
   1.886+	csr(igfx, t->chicken.a, 1<<31, 0);
   1.887+
   1.888+skippipe:
   1.889+	/* disable dpll  */
   1.890+	if(t->dpll != nil)
   1.891+		csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
   1.892+}
   1.893+
   1.894+static void
   1.895+disablepipe(Igfx *igfx, int x)
   1.896+{
   1.897+	Pipe *p;
   1.898+
   1.899+	p = &igfx->pipe[x];
   1.900+
   1.901+	/* planes off */
   1.902+	csr(igfx, p->dsp->cntr.a, 1<<31, 0);
   1.903+	csr(igfx, p->dsp->surf.a, ~0, 0);	/* arm */
   1.904+	csr(igfx, p->cur->cntr.a, 1<<31, 0);
   1.905+	csr(igfx, p->cur->surf.a, ~0, 0);	/* arm */
   1.906+
   1.907+	/* disable cpu pipe */
   1.908+	disabletrans(igfx, p);
   1.909+
   1.910+	/* disable panel fitter */
   1.911+	if(p->pfit != nil)
   1.912+		csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
   1.913+
   1.914+	if(0){
   1.915+		/* disable fdi transmitter and receiver */
   1.916+		csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
   1.917+		csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
   1.918+	}
   1.919+
   1.920+	/* disable displayport transcoder */
   1.921+	csr(igfx, p->fdi->dpctl.a, 1<<31, 3<<29);
   1.922+
   1.923+	/* disable pch transcoder */
   1.924+	disabletrans(igfx, p->fdi);
   1.925+
   1.926+	/* disable pch dpll enable bit */
   1.927+	csr(igfx, igfx->dpllsel.a, 8<<(x*4), 0);
   1.928+}
   1.929+
   1.930+static void
   1.931+load(Vga* vga, Ctlr* ctlr)
   1.932+{
   1.933+	Igfx *igfx;
   1.934+	int x;
   1.935+
   1.936+	igfx = vga->private;
   1.937+
   1.938+	/* power lcd off */
   1.939+	if(igfx->ppcontrol.a != 0){
   1.940+		csr(igfx, igfx->ppcontrol.a, 0xFFFF0005, 0xABCD0000);
   1.941+		for(x=0; x<5000; x++){
   1.942+			sleep(10);
   1.943+			if((rr(igfx, igfx->ppstatus.a) & (1<<31)) == 0)
   1.944+				break;
   1.945+		}
   1.946+	}
   1.947+
   1.948+	/* disable ports */
   1.949+	csr(igfx, igfx->sdvob.a, (1<<29) | (1<<31), 0);
   1.950+	csr(igfx, igfx->sdvoc.a, (1<<29) | (1<<31), 0);
   1.951+	csr(igfx, igfx->adpa.a, 1<<31, 0);
   1.952+	csr(igfx, igfx->lvds.a, 1<<31, 0);
   1.953+	for(x = 0; x < nelem(igfx->dp); x++)
   1.954+		csr(igfx, igfx->dp[x].ctl.a, 1<<31, 0);
   1.955+	for(x = 0; x < nelem(igfx->hdmi); x++)
   1.956+		csr(igfx, igfx->hdmi[x].ctl.a, 1<<31, 0);
   1.957+
   1.958+	/* disable vga plane */
   1.959+	csr(igfx, igfx->vgacntrl.a, 0, 1<<31);
   1.960+
   1.961+	/* turn off all pipes */
   1.962+	for(x = 0; x < igfx->npipe; x++)
   1.963+		disablepipe(igfx, x);
   1.964+
   1.965+	/* program new clock sources */
   1.966+	loadreg(igfx, igfx->rawclkfreq);
   1.967+	loadreg(igfx, igfx->drefctl);
   1.968+	sleep(10);
   1.969+
   1.970+	/* set lvds before enabling dpll */
   1.971+	loadreg(igfx, igfx->lvds);
   1.972+
   1.973+	/* new dpll setting */
   1.974+	loadreg(igfx, igfx->dpllsel);
   1.975+
   1.976+	/* program all pipes */
   1.977+	for(x = 0; x < igfx->npipe; x++)
   1.978+		enablepipe(igfx, x);
   1.979+
   1.980+	/* program vga plane */
   1.981+	loadreg(igfx, igfx->vgacntrl);
   1.982+
   1.983+	/* program ports */
   1.984+	loadreg(igfx, igfx->adpa);
   1.985+	loadreg(igfx, igfx->sdvob);
   1.986+	loadreg(igfx, igfx->sdvoc);
   1.987+	for(x = 0; x < nelem(igfx->dp); x++)
   1.988+		loadreg(igfx, igfx->dp[x].ctl);
   1.989+	for(x=0; x<nelem(igfx->hdmi); x++){
   1.990+		loadreg(igfx, igfx->hdmi[x].bufctl[0]);
   1.991+		loadreg(igfx, igfx->hdmi[x].bufctl[1]);
   1.992+		loadreg(igfx, igfx->hdmi[x].bufctl[2]);
   1.993+		loadreg(igfx, igfx->hdmi[x].bufctl[3]);
   1.994+		loadreg(igfx, igfx->hdmi[x].ctl);
   1.995+	}
   1.996+
   1.997+	/* turn on lcd pfit */
   1.998+	loadreg(igfx, igfx->ppcontrol);
   1.999+
  1.1000+	ctlr->flag |= Fload;
  1.1001+}
  1.1002+
  1.1003+static void
  1.1004+dumpreg(char *name, char *item, Reg r)
  1.1005+{
  1.1006+	if(r.a == 0)
  1.1007+		return;
  1.1008+
  1.1009+	printitem(name, item);
  1.1010+	Bprint(&stdout, " [%.8ux] = %.8ux\n", r.a, r.v);
  1.1011+}
  1.1012+
  1.1013+static void
  1.1014+dumptiming(char *name, Trans *t)
  1.1015+{
  1.1016+	int tu, m, n;
  1.1017+
  1.1018+	if(t->dm[0].a != 0 && t->dm[0].v != 0){
  1.1019+		tu = (t->dm[0].v >> 25)+1;
  1.1020+		printitem(name, "dm1 tu");
  1.1021+		Bprint(&stdout, " %d\n", tu);
  1.1022+
  1.1023+		m = t->dm[0].v & 0xffffff;
  1.1024+		n = t->dn[0].v;
  1.1025+		if(n > 0){
  1.1026+			printitem(name, "dm1/dn1");
  1.1027+			Bprint(&stdout, " %f\n", (double)m / (double)n);
  1.1028+		}
  1.1029+
  1.1030+		m = t->lm[0].v;
  1.1031+		n = t->ln[0].v;
  1.1032+		if(n > 0){
  1.1033+			printitem(name, "lm1/ln1");
  1.1034+			Bprint(&stdout, " %f\n", (double)m / (double)n);
  1.1035+		}
  1.1036+	}
  1.1037+}
  1.1038+
  1.1039+static void
  1.1040+dumptrans(char *name, Trans *t)
  1.1041+{
  1.1042+	dumpreg(name, "conf", t->conf);
  1.1043+
  1.1044+	dumpreg(name, "dm1", t->dm[0]);
  1.1045+	dumpreg(name, "dn1", t->dn[0]);
  1.1046+	dumpreg(name, "lm1", t->lm[0]);
  1.1047+	dumpreg(name, "ln1", t->ln[0]);
  1.1048+	dumpreg(name, "dm2", t->dm[1]);
  1.1049+	dumpreg(name, "dn2", t->dn[1]);
  1.1050+	dumpreg(name, "lm2", t->lm[1]);
  1.1051+	dumpreg(name, "ln2", t->ln[1]);
  1.1052+
  1.1053+	dumptiming(name, t);
  1.1054+
  1.1055+	dumpreg(name, "ht", t->ht);
  1.1056+	dumpreg(name, "hb", t->hb);
  1.1057+	dumpreg(name, "hs", t->hs);
  1.1058+
  1.1059+	dumpreg(name, "vt", t->vt);
  1.1060+	dumpreg(name, "vb", t->vb);
  1.1061+	dumpreg(name, "vs", t->vs);
  1.1062+	dumpreg(name, "vss", t->vss);
  1.1063+}
  1.1064+
  1.1065+static void
  1.1066+dumppipe(Igfx *igfx, int x)
  1.1067+{
  1.1068+	char name[32];
  1.1069+	Pipe *p;
  1.1070+
  1.1071+	p = &igfx->pipe[x];
  1.1072+
  1.1073+	snprint(name, sizeof(name), "%s pipe %c", igfx->ctlr->name, 'a'+x);
  1.1074+	dumpreg(name, "src", p->src);
  1.1075+	dumptrans(name, p);
  1.1076+
  1.1077+	snprint(name, sizeof(name), "%s fdi %c", igfx->ctlr->name, 'a'+x);
  1.1078+	dumptrans(name, p->fdi);
  1.1079+	dumpreg(name, "txctl", p->fdi->txctl);
  1.1080+	dumpreg(name, "rxctl", p->fdi->rxctl);
  1.1081+	dumpreg(name, "rxmisc", p->fdi->rxmisc);
  1.1082+	dumpreg(name, "rxtu1", p->fdi->rxtu[0]);
  1.1083+	dumpreg(name, "rxtu2", p->fdi->rxtu[1]);
  1.1084+	dumpreg(name, "dpctl", p->fdi->dpctl);
  1.1085+
  1.1086+	snprint(name, sizeof(name), "%s dsp %c", igfx->ctlr->name, 'a'+x);
  1.1087+	dumpreg(name, "cntr", p->dsp->cntr);
  1.1088+	dumpreg(name, "linoff", p->dsp->linoff);
  1.1089+	dumpreg(name, "stride", p->dsp->stride);
  1.1090+	dumpreg(name, "surf", p->dsp->surf);
  1.1091+	dumpreg(name, "tileoff", p->dsp->tileoff);
  1.1092+
  1.1093+	snprint(name, sizeof(name), "%s cur %c", igfx->ctlr->name, 'a'+x);
  1.1094+	dumpreg(name, "cntr", p->cur->cntr);
  1.1095+	dumpreg(name, "surf", p->cur->surf);
  1.1096+}
  1.1097+
  1.1098+static void
  1.1099+dump(Vga* vga, Ctlr* ctlr)
  1.1100+{
  1.1101+	char name[32];
  1.1102+	Igfx *igfx;
  1.1103+	int x;
  1.1104+
  1.1105+	if((igfx = vga->private) == nil)
  1.1106+		return;
  1.1107+
  1.1108+	for(x=0; x<igfx->npipe; x++)
  1.1109+		dumppipe(igfx, x);
  1.1110+
  1.1111+	for(x=0; x<nelem(igfx->dpll); x++){
  1.1112+		snprint(name, sizeof(name), "%s dpll %c", ctlr->name, 'a'+x);
  1.1113+		dumpreg(name, "ctrl", igfx->dpll[x].ctrl);
  1.1114+		dumpreg(name, "fp0", igfx->dpll[x].fp0);
  1.1115+		dumpreg(name, "fp1", igfx->dpll[x].fp1);
  1.1116+	}
  1.1117+
  1.1118+	dumpreg(ctlr->name, "dpllsel", igfx->dpllsel);
  1.1119+
  1.1120+	dumpreg(ctlr->name, "drefctl", igfx->drefctl);
  1.1121+	dumpreg(ctlr->name, "rawclkfreq", igfx->rawclkfreq);
  1.1122+	dumpreg(ctlr->name, "ssc4params", igfx->ssc4params);
  1.1123+
  1.1124+	for(x=0; x<nelem(igfx->dp); x++){
  1.1125+		snprint(name, sizeof(name), "dp %c ctl", 'a'+x);
  1.1126+		dumpreg(ctlr->name, name, igfx->dp[x].ctl);
  1.1127+	}
  1.1128+	for(x=0; x<nelem(igfx->hdmi); x++){
  1.1129+		snprint(name, sizeof(name), "hdmi %c ctl ", 'a'+x);
  1.1130+		dumpreg(ctlr->name, name, igfx->hdmi[x].ctl);
  1.1131+	}
  1.1132+
  1.1133+	for(x=0; x<nelem(igfx->pfit); x++){
  1.1134+		snprint(name, sizeof(name), "pfit %c ctrl", 'a'+x);
  1.1135+		dumpreg(ctlr->name, name, igfx->pfit[x].ctrl);
  1.1136+		snprint(name, sizeof(name), "pfit %c winpos", 'a'+x);
  1.1137+		dumpreg(ctlr->name, name, igfx->pfit[x].winpos);
  1.1138+		snprint(name, sizeof(name), "pfit %c winsize", 'a'+x);
  1.1139+		dumpreg(ctlr->name, name, igfx->pfit[x].winsize);
  1.1140+		snprint(name, sizeof(name), "pfit %c pwrgate", 'a'+x);
  1.1141+		dumpreg(ctlr->name, name, igfx->pfit[x].pwrgate);
  1.1142+	}
  1.1143+
  1.1144+	dumpreg(ctlr->name, "adpa", igfx->adpa);
  1.1145+	dumpreg(ctlr->name, "lvds", igfx->lvds);
  1.1146+	dumpreg(ctlr->name, "sdvob", igfx->sdvob);
  1.1147+	dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
  1.1148+
  1.1149+	dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
  1.1150+}
  1.1151+
  1.1152+Ctlr igfx = {
  1.1153+	"igfx",			/* name */
  1.1154+	snarf,			/* snarf */
  1.1155+	options,		/* options */
  1.1156+	init,			/* init */
  1.1157+	load,			/* load */
  1.1158+	dump,			/* dump */
  1.1159+};