ref: 9b28b2d97b2a064cecdcd44a4a627db0c28e633d
parent: 773f1c5f6ab2d3f5c5a815e83049ab1dab8de690
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jan 11 20:51:51 EST 2015
igfx: vga support on x230, fix fdi link setup, LG Flatron L1730P vgadb entry
--- a/lib/vgadb
+++ b/lib/vgadb
@@ -1707,3 +1707,12 @@
vrs=802 vre=804 vt=830
hsync=- vsync=-
lcd=1
+
+#
+# LG Flatron L1730P
+#
+l1730p=1280x1024 # 60Hz
+ clock=108
+ shb=1320 ehb=1440 ht=1688
+ vrs=1025 vre=1028 vt=1066
+ hsync=+ vsync=+
--- a/sys/src/cmd/aux/vga/igfx.c
+++ b/sys/src/cmd/aux/vga/igfx.c
@@ -16,6 +16,7 @@
typedef struct Plane Plane;
typedef struct Trans Trans;
typedef struct Pipe Pipe;
+typedef struct Igfx Igfx;
enum {
MHz = 1000000,
@@ -114,7 +115,6 @@
Pfit *pfit; /* selected panel fitter */
};
-typedef struct Igfx Igfx;
struct Igfx {
Ctlr *ctlr;
Pcidev *pci;
@@ -151,9 +151,11 @@
/* common */
Reg adpa;
Reg lvds;
- Edid *lvdsedid;
Reg vgacntrl;
+
+ Edid *adpaedid;
+ Edid *lvdsedid;
};
static u32int
@@ -309,7 +311,7 @@
return -1;
}
-static void snarfedid(Igfx*);
+static Edid* snarfedid(Igfx*, int port, int addr);
static void
snarf(Vga* vga, Ctlr* ctlr)
@@ -370,6 +372,9 @@
if(igfx->pipe[y].pfit == nil)
igfx->pipe[y].pfit = &igfx->pfit[0];
+ igfx->ppstatus = snarfreg(igfx, 0x61200);
+ igfx->ppcontrol = snarfreg(igfx, 0x61204);
+
igfx->vgacntrl = snarfreg(igfx, 0x071400);
break;
@@ -389,7 +394,7 @@
igfx->rawclkfreq = snarfreg(igfx, 0xC6204);
igfx->ssc4params = snarfreg(igfx, 0xC6210);
- /* cpu displayport A*/
+ /* cpu displayport A */
igfx->dp[0].ctl = snarfreg(igfx, 0x64000);
igfx->dp[0].auxctl = snarfreg(igfx, 0x64010);
igfx->dp[0].auxdat[0] = snarfreg(igfx, 0x64014);
@@ -454,7 +459,8 @@
for(x=0; x<igfx->npipe; x++)
snarfpipe(igfx, x);
- snarfedid(igfx);
+ igfx->adpaedid = snarfedid(igfx, 2, 0x50);
+ igfx->lvdsedid = snarfedid(igfx, 3, 0x50);
ctlr->flag |= Fsnarf;
}
@@ -476,13 +482,16 @@
best = -1;
for(N=3; N<=8; N++)
for(M2=5; M2<=9; M2++)
- for(M1=10; M1<=20; M1++){
+// for(M1=10; M1<=20; M1++){
+ for(M1=12; M1<=22; M1++){
M = 5*(M1+2) + (M2+2);
- if(M < 70 || M > 120)
+ if(M < 79 || M > 127)
+// if(M < 70 || M > 120)
continue;
for(P1=1; P1<=8; P1++){
P = P1 * P2;
- if(P < 4 || P > 98)
+ if(P < 5 || P > 98)
+// if(P < 4 || P > 98)
continue;
a = cref;
a *= M;
@@ -507,6 +516,20 @@
}
static int
+getcref(Igfx *igfx, int x)
+{
+ Dpll *dpll;
+
+ dpll = &igfx->dpll[x];
+ if(igfx->type == TypeG45){
+ if(((dpll->ctrl.v >> 13) & 3) == 3)
+ return 100*MHz;
+ return 96*MHz;
+ }
+ return 120*MHz;
+}
+
+static int
initdpll(Igfx *igfx, int x, int freq, int islvds, int ishdmi)
{
int cref, m1, m2, n, p1, p2;
@@ -517,8 +540,7 @@
/* PLL Reference Input Select */
dpll = igfx->pipe[x].dpll;
dpll->ctrl.v &= ~(3<<13);
- dpll->ctrl.v |= (islvds ? 2 : 0) << 13;
- cref = islvds ? 100*MHz : 96*MHz;
+ dpll->ctrl.v |= (islvds ? 3 : 0) << 13;
break;
case TypeIVB:
/* transcoder dpll enable */
@@ -525,14 +547,20 @@
igfx->dpllsel.v |= 8<<(x*4);
/* program rawclock to 125MHz */
igfx->rawclkfreq.v = 125;
+
+ igfx->drefctl.v &= ~(3<<13);
+ igfx->drefctl.v &= ~(3<<11);
+ igfx->drefctl.v &= ~(3<<9);
+ igfx->drefctl.v &= ~(3<<7);
+ igfx->drefctl.v &= ~3;
+
if(islvds){
- /* 120MHz SSC integrated source enable */
- igfx->drefctl.v &= ~(3<<11);
igfx->drefctl.v |= 2<<11;
-
- /* 120MHz SSC4 modulation en */
- igfx->drefctl.v |= 2;
+ igfx->drefctl.v |= 1;
+ } else {
+ igfx->drefctl.v |= 2<<9;
}
+
/*
* PLL Reference Input Select:
* 000 DREFCLK (default is 120 MHz) for DAC/HDMI/DVI/DP
@@ -542,11 +570,11 @@
dpll = igfx->pipe[x].fdi->dpll;
dpll->ctrl.v &= ~(7<<13);
dpll->ctrl.v |= (islvds ? 3 : 0) << 13;
- cref = 120*MHz;
break;
default:
return -1;
}
+ cref = getcref(igfx, x);
/* Dpll Mode select */
dpll->ctrl.v &= ~(3<<26);
@@ -603,11 +631,13 @@
n = 0x800000;
m = (n * ((freq * bpp)/8)) / (lsclk * lanes);
+
t->dm[0].v = (tu-1)<<25 | m;
t->dn[0].v = n;
n = 0x80000;
m = (n * freq) / lsclk;
+
t->lm[0].v = m;
t->ln[0].v = n;
@@ -628,11 +658,13 @@
/* trans/pipe timing */
t->ht.v = (m->ht - 1)<<16 | (m->x - 1);
- t->hb.v = t->ht.v;
t->hs.v = (m->ehb - 1)<<16 | (m->shb - 1);
t->vt.v = (m->vt - 1)<<16 | (m->y - 1);
- t->vb.v = t->vt.v;
t->vs.v = (m->vre - 1)<<16 | (m->vrs - 1);
+
+ t->hb.v = t->ht.v;
+ t->vb.v = t->vt.v;
+
t->vss.v = 0;
}
@@ -647,7 +679,7 @@
p->src.v = (m->x - 1)<<16 | (m->y - 1);
if(p->pfit != nil){
- /* panel fitter enable, hardcoded coefficients */
+ /* panel fitter on, hardcoded coefficients */
p->pfit->ctrl.v = 1<<31 | 1<<23;
p->pfit->winpos.v = 0;
p->pfit->winsize.v = (m->x << 16) | m->y;
@@ -658,7 +690,7 @@
/* default for displayport */
tu = 64;
- bpc = 8;
+ bpc = 6; /* why */
lanes = 1;
fdi = p->fdi;
@@ -666,29 +698,10 @@
/* enable and set monitor timings for transcoder */
inittrans(fdi, m);
- /*
- * hack:
- * we do not program fdi in load(), so use
- * snarfed bios initialized values for now.
- */
- if(fdi->rxctl.v & (1<<31)){
- tu = 1+(fdi->rxtu[0].v >> 25);
- bpc = bpctab[(fdi->rxctl.v >> 16) & 3];
- lanes = 1+((fdi->rxctl.v >> 19) & 7);
- }
-
- /* fdi tx enable */
- fdi->txctl.v |= (1<<31);
/* tx port width selection */
fdi->txctl.v &= ~(7<<19);
fdi->txctl.v |= (lanes-1)<<19;
- /* tx fdi pll enable */
- fdi->txctl.v |= (1<<14);
- /* clear auto training bits */
- fdi->txctl.v &= ~(7<<8 | 1);
- /* fdi rx enable */
- fdi->rxctl.v |= (1<<31);
/* rx port width selection */
fdi->rxctl.v &= ~(7<<19);
fdi->rxctl.v |= (lanes-1)<<19;
@@ -702,11 +715,11 @@
break;
}
}
- /* rx fdi pll enable */
- fdi->rxctl.v |= (1<<13);
- /* rx fdi rawclk to pcdclk selection */
- fdi->rxctl.v |= (1<<4);
+ /* enhanced framing on */
+ fdi->rxctl.v |= (1<<6);
+ fdi->txctl.v |= (1<<18);
+
/* tusize 1 and 2 */
fdi->rxtu[0].v = (tu-1)<<25;
fdi->rxtu[1].v = (tu-1)<<25;
@@ -742,7 +755,14 @@
/* disable vga */
igfx->vgacntrl.v |= (1<<31);
- x = 0;
+ /* disable all pipes adpa and lvds */
+ igfx->ppcontrol.v &= 0xFFFF;
+ igfx->ppcontrol.v &= ~5;
+ igfx->lvds.v &= ~(1<<31);
+ igfx->adpa.v &= ~(1<<31);
+ for(x=0; x<igfx->npipe; x++)
+ igfx->pipe[x].conf.v &= ~(1<<31);
+
islvds = 0;
if((val = dbattr(m->attr, "lcd")) != nil && atoi(val) != 0){
islvds = 1;
@@ -752,14 +772,18 @@
else
x = (igfx->lvds.v >> 30) & 1;
igfx->lvds.v |= (1<<31);
-
- igfx->ppcontrol.v &= ~0xFFFF0000;
igfx->ppcontrol.v |= 5;
+ } else {
+ if(igfx->npipe > 2)
+ x = (igfx->adpa.v >> 29) & 3;
+ else
+ x = (igfx->adpa.v >> 30) & 1;
+ igfx->adpa.v |= (1<<31);
}
p = &igfx->pipe[x];
- /* plane enable, 32bpp and assign pipe */
- p->dsp->cntr.v = (1<<31) | (6<<26) | (x<<24);
+ /* plane enable, 32bpp */
+ p->dsp->cntr.v = (1<<31) | (6<<26);
/* stride must be 64 byte aligned */
p->dsp->stride.v = m->x * (m->z / 8);
@@ -839,6 +863,7 @@
static void
enablepipe(Igfx *igfx, int x)
{
+ int i;
Pipe *p;
p = &igfx->pipe[x];
@@ -845,11 +870,18 @@
if((p->conf.v & (1<<31)) == 0)
return; /* pipe is disabled, done */
- if(0){
+ if(p->fdi->rxctl.a != 0){
p->fdi->rxctl.v &= ~(1<<31);
+ p->fdi->rxctl.v &= ~(1<<4); /* rawclk */
+ p->fdi->rxctl.v |= (1<<13); /* enable pll */
loadreg(igfx, p->fdi->rxctl);
sleep(5);
+ p->fdi->rxctl.v |= (1<<4); /* pcdclk */
+ loadreg(igfx, p->fdi->rxctl);
+ sleep(5);
+ p->fdi->txctl.v &= ~(7<<8 | 1); /* clear auto training bits */
p->fdi->txctl.v &= ~(1<<31);
+ p->fdi->rxctl.v |= (1<<14); /* enable pll */
loadreg(igfx, p->fdi->txctl);
sleep(5);
}
@@ -879,18 +911,28 @@
loadreg(igfx, p->cur->pos);
loadreg(igfx, p->cur->base); /* arm */
- if(0){
+ if(p->fdi->rxctl.a != 0){
/* enable fdi */
loadreg(igfx, p->fdi->rxtu[1]);
loadreg(igfx, p->fdi->rxtu[0]);
loadreg(igfx, p->fdi->rxmisc);
- p->fdi->rxctl.v &= ~(3<<8 | 1<<10 | 3);
- p->fdi->rxctl.v |= (1<<31);
+
+ p->fdi->rxctl.v &= ~(3<<8); /* link train pattern 00 */
+ p->fdi->rxctl.v |= 1<<10; /* auto train enable */
+ p->fdi->rxctl.v |= 1<<31; /* enable */
loadreg(igfx, p->fdi->rxctl);
- p->fdi->txctl.v &= ~(3<<8 | 1<<10 | 2);
- p->fdi->txctl.v |= (1<<31);
+ p->fdi->txctl.v &= ~(3<<8); /* link train pattern 00 */
+ p->fdi->txctl.v |= 1<<10; /* auto train enable */
+ p->fdi->txctl.v |= 1<<31; /* enable */
loadreg(igfx, p->fdi->txctl);
+
+ /* wait for link training done */
+ for(i=0; i<200; i++){
+ sleep(5);
+ if(rr(igfx, p->fdi->txctl.a) & 2)
+ break;
+ }
}
/* enable the transcoder */
@@ -902,10 +944,6 @@
{
int i;
- /* the front fell off on x230 */
- if(igfx->type == TypeIVB && t == &igfx->pipe[0])
- goto skippipe;
-
/* disable transcoder / pipe */
csr(igfx, t->conf.a, 1<<31, 0);
for(i=0; i<100; i++){
@@ -916,7 +954,6 @@
/* workarround: clear timing override bit */
csr(igfx, t->chicken.a, 1<<31, 0);
-skippipe:
/* disable dpll */
if(t->dpll != nil)
csr(igfx, t->dpll->ctrl.a, 1<<31, 0);
@@ -943,11 +980,9 @@
if(p->pfit != nil)
csr(igfx, p->pfit->ctrl.a, 1<<31, 0);
- if(0){
- /* disable fdi transmitter and receiver */
- csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
- csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
- }
+ /* disable fdi transmitter and receiver */
+ csr(igfx, p->fdi->txctl.a, 1<<31 | 1<<10, 0);
+ csr(igfx, p->fdi->rxctl.a, 1<<31 | 1<<10, 0);
/* disable displayport transcoder */
csr(igfx, p->fdi->dpctl.a, 1<<31, 3<<29);
@@ -1048,7 +1083,7 @@
int tu, m, n;
if(t->dm[0].a != 0 && t->dm[0].v != 0){
- tu = (t->dm[0].v >> 25)+1;
+ tu = 1+((t->dm[0].v >> 25) & 0x3f);
printitem(name, "dm1 tu");
Bprint(&stdout, " %d\n", tu);
@@ -1129,6 +1164,54 @@
}
static void
+dumpdpll(Igfx *igfx, int x)
+{
+ int cref, m1, m2, n, p1, p2;
+ uvlong freq;
+ char name[32];
+ Dpll *dpll;
+ u32int m;
+
+ dpll = &igfx->dpll[x];
+ snprint(name, sizeof(name), "%s dpll %c", igfx->ctlr->name, 'a'+x);
+
+ dumpreg(name, "ctrl", dpll->ctrl);
+ dumpreg(name, "fp0", dpll->fp0);
+ dumpreg(name, "fp1", dpll->fp1);
+
+ p2 = ((dpll->ctrl.v >> 13) & 3) == 3 ? 14 : 10;
+ if(((dpll->ctrl.v >> 24) & 3) == 1)
+ p2 >>= 1;
+ m = (dpll->ctrl.v >> 16) & 0xFF;
+ for(p1 = 1; p1 <= 8; p1++)
+ if(m & (1<<(p1-1)))
+ break;
+ printitem(name, "ctrl p1");
+ Bprint(&stdout, " %d\n", p1);
+ printitem(name, "ctrl p2");
+ Bprint(&stdout, " %d\n", p2);
+
+ n = (dpll->fp0.v >> 16) & 0x3f;
+ m1 = (dpll->fp0.v >> 8) & 0x3f;
+ m2 = (dpll->fp0.v >> 0) & 0x3f;
+
+ cref = getcref(igfx, x);
+ freq = ((uvlong)cref * (5*(m1+2) + (m2+2)) / (n+2)) / (p1 * p2);
+
+ printitem(name, "fp0 m1");
+ Bprint(&stdout, " %d\n", m1);
+ printitem(name, "fp0 m2");
+ Bprint(&stdout, " %d\n", m2);
+ printitem(name, "fp0 n");
+ Bprint(&stdout, " %d\n", n);
+
+ printitem(name, "cref");
+ Bprint(&stdout, " %d\n", cref);
+ printitem(name, "fp0 freq");
+ Bprint(&stdout, " %lld\n", freq);
+}
+
+static void
dump(Vga* vga, Ctlr* ctlr)
{
char name[32];
@@ -1141,12 +1224,8 @@
for(x=0; x<igfx->npipe; x++)
dumppipe(igfx, x);
- for(x=0; x<nelem(igfx->dpll); x++){
- snprint(name, sizeof(name), "%s dpll %c", ctlr->name, 'a'+x);
- dumpreg(name, "ctrl", igfx->dpll[x].ctrl);
- dumpreg(name, "fp0", igfx->dpll[x].fp0);
- dumpreg(name, "fp1", igfx->dpll[x].fp1);
- }
+ for(x=0; x<nelem(igfx->dpll); x++)
+ dumpdpll(igfx, x);
dumpreg(ctlr->name, "dpllsel", igfx->dpllsel);
@@ -1181,8 +1260,14 @@
dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
- if(igfx->lvdsedid != nil)
+ if(igfx->adpaedid != nil){
+ Bprint(&stdout, "edid adpa\n");
+ printedid(igfx->adpaedid);
+ }
+ if(igfx->lvdsedid != nil){
+ Bprint(&stdout, "edid lvds\n");
printedid(igfx->lvdsedid);
+ }
}
enum {
@@ -1195,7 +1280,7 @@
};
static int
-gmbusread(Igfx *igfx, int portsel, int addr, uchar *data, int len)
+gmbusread(Igfx *igfx, int port, int addr, uchar *data, int len)
{
u32int x, y;
int n, t;
@@ -1203,7 +1288,7 @@
if(igfx->gmbus[GMBUSCP].a == 0)
return -1;
- wr(igfx, igfx->gmbus[GMBUSCP].a, portsel);
+ wr(igfx, igfx->gmbus[GMBUSCP].a, port);
wr(igfx, igfx->gmbus[GMBUSIX].a, 0);
/* bus cycle without index and stop, byte count, slave address, read */
@@ -1238,21 +1323,41 @@
data[n++] = y & 0xff;
}
}
+
return n;
}
-static void
-snarfedid(Igfx *igfx)
+static Edid*
+snarfedid(Igfx *igfx, int port, int addr)
{
- uchar buf[128];
+ uchar buf[256], tmp[256];
+ Edid *e;
+ int i;
- if(gmbusread(igfx, 3, 0x50, buf, sizeof(buf)) != sizeof(buf))
- return;
- igfx->lvdsedid = malloc(sizeof(Edid));
- if(parseedid128(igfx->lvdsedid, buf) != 0){
- free(igfx->lvdsedid);
- igfx->lvdsedid = nil;
+ /* read twice */
+ if(gmbusread(igfx, port, addr, buf, 128) != 128)
+ return nil;
+ if(gmbusread(igfx, port, addr, buf + 128, 128) != 128)
+ return nil;
+
+ /* shift if neccesary so edid block is at the start */
+ for(i=0; i<256-8; i++){
+ if(buf[i+0] == 0x00 && buf[i+1] == 0xFF && buf[i+2] == 0xFF && buf[i+3] == 0xFF
+ && buf[i+4] == 0xFF && buf[i+5] == 0xFF && buf[i+6] == 0xFF && buf[i+7] == 0x00){
+ memmove(tmp, buf, i);
+ memmove(buf, buf + i, 256 - i);
+ memmove(buf + (256 - i), tmp, i);
+ break;
+ }
}
+
+ e = malloc(sizeof(Edid));
+ if(parseedid128(e, buf) != 0){
+ free(e);
+ return nil;
+ }
+
+ return e;
}
Ctlr igfx = {