summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/g80_display.c93
-rw-r--r--src/g80_output.c23
-rw-r--r--src/g80_type.h2
-rw-r--r--src/nv_driver.c2
4 files changed, 105 insertions, 15 deletions
diff --git a/src/g80_display.c b/src/g80_display.c
index cf4631d..1b1efe9 100644
--- a/src/g80_display.c
+++ b/src/g80_display.c
@@ -146,26 +146,95 @@ G80CalcPLL(float pclk, int *pNA, int *pMA, int *pNB, int *pMB, int *pP)
}
static void
+G80CalcPLL2(float pclk, int *pN, int *pM, int *pPL)
+{
+ const float refclk = 27000.0f;
+ const int minN = 8, maxN = 255;
+ const int minM = 1, maxM = 255;
+ const int minPL = 1, maxPL = 63;
+ const int minU = 25000, maxU = 50000;
+ const int minVco = 500000;
+ int maxVco = 1000000;
+ int lowPL, highPL, pl;
+ float vco, bestError = FLT_MAX;
+
+ vco = pclk + pclk / 50;
+
+ if(maxVco < vco) maxVco = vco;
+
+ highPL = (maxVco + vco - 1) / pclk;
+ if(highPL > maxPL) highPL = maxPL;
+ if(highPL < minPL) highPL = minPL;
+
+ lowPL = minVco / vco;
+ if(lowPL > maxPL) lowPL = maxPL;
+ if(lowPL < minPL) lowPL = minPL;
+
+ for(pl = highPL; pl >= lowPL; pl--) {
+ int m;
+
+ for(m = minM; m <= maxM; m++) {
+ int n;
+ float freq, error;
+
+ if(refclk / m < minU) break;
+ if(refclk / m > maxU) continue;
+
+ n = rint(pclk * pl * m / refclk);
+ if(n > maxN) break;
+ if(n < minN) continue;
+
+ freq = refclk * (n / (float)m) / pl;
+ error = fabsf(pclk - freq);
+ if(error < bestError) {
+ *pN = n;
+ *pM = m;
+ *pPL = pl;
+ bestError = error;
+ }
+ }
+ }
+}
+
+static void
G80CrtcSetPClk(xf86CrtcPtr crtc)
{
G80Ptr pNv = G80PTR(crtc->scrn);
G80CrtcPrivPtr pPriv = crtc->driver_private;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
const int headOff = 0x800 * pPriv->head;
- int lo_n, lo_m, hi_n, hi_m, p, i;
- CARD32 lo = pNv->reg[(0x00614104+headOff)/4];
- CARD32 hi = pNv->reg[(0x00614108+headOff)/4];
+ int i;
+
+ if(pPriv->pclk == 0)
+ return;
+
+ if(pNv->architecture < 0xa0) {
+ int lo_n, lo_m, hi_n, hi_m, p, i;
+ CARD32 lo = pNv->reg[(0x00614104+headOff)/4];
+ CARD32 hi = pNv->reg[(0x00614108+headOff)/4];
+
+ pNv->reg[(0x00614100+headOff)/4] = 0x10000610;
+ lo &= 0xff00ff00;
+ hi &= 0x8000ff00;
- pNv->reg[(0x00614100+headOff)/4] = 0x10000610;
- lo &= 0xff00ff00;
- hi &= 0x8000ff00;
+ G80CalcPLL(pPriv->pclk, &lo_n, &lo_m, &hi_n, &hi_m, &p);
- G80CalcPLL(pPriv->pclk, &lo_n, &lo_m, &hi_n, &hi_m, &p);
+ lo |= (lo_m << 16) | lo_n;
+ hi |= (p << 28) | (hi_m << 16) | hi_n;
+ pNv->reg[(0x00614104+headOff)/4] = lo;
+ pNv->reg[(0x00614108+headOff)/4] = hi;
+ } else {
+ int n, m, pl;
+ CARD32 r = pNv->reg[(0x00614104+headOff)/4];
+
+ pNv->reg[(0x00614100+headOff)/4] = 0x50000610;
+ r &= 0xffc00000;
- lo |= (lo_m << 16) | lo_n;
- hi |= (p << 28) | (hi_m << 16) | hi_n;
- pNv->reg[(0x00614104+headOff)/4] = lo;
- pNv->reg[(0x00614108+headOff)/4] = hi;
+ G80CalcPLL2(pPriv->pclk, &n, &m, &pl);
+ r |= pl << 16 | m << 8 | n;
+
+ pNv->reg[(0x00614104+headOff)/4] = r;
+ }
pNv->reg[(0x00614200+headOff)/4] = 0;
for(i = 0; i < xf86_config->num_output; i++) {
@@ -235,6 +304,8 @@ G80DispPreInit(ScrnInfoPtr pScrn)
pNv->reg[0x006101D8/4] = pNv->reg[0x0061B000/4];
pNv->reg[0x006101E0/4] = pNv->reg[0x0061C000/4];
pNv->reg[0x006101E4/4] = pNv->reg[0x0061C800/4];
+ pNv->reg[0x006101E8/4] = pNv->reg[0x0061D000/4];
+ pNv->reg[0x006101EC/4] = pNv->reg[0x0061D800/4];
pNv->reg[0x0061A004/4] = 0x80550000;
pNv->reg[0x0061A010/4] = 0x00000001;
pNv->reg[0x0061A804/4] = 0x80550000;
diff --git a/src/g80_output.c b/src/g80_output.c
index 75bf7ba..b2d8b07 100644
--- a/src/g80_output.c
+++ b/src/g80_output.c
@@ -127,6 +127,11 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
"VGA%d: invalid port type %d\n", or, portType);
break;
}
+ if(port >= G80_NUM_I2C_PORTS) {
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "VGA%d: unrecognized port %d\n", or, port);
+ break;
+ }
if(pNv->i2cMap[port].dac != -1) {
xf86DrvMsg(scrnIndex, X_WARNING,
"DDC routing table corrupt! DAC %i -> %i for "
@@ -152,6 +157,11 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
"DVI%d: invalid port type %d\n", or, portType);
break;
}
+ if(port >= G80_NUM_I2C_PORTS) {
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "DVI%d: unrecognized port %d\n", or, port);
+ break;
+ }
if(pNv->i2cMap[port].sor != -1)
xf86DrvMsg(scrnIndex, X_WARNING,
"DDC routing table corrupt! SOR %i -> %i for "
@@ -181,6 +191,11 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
"LVDS: invalid port type %d\n", portType);
break;
}
+ if(port >= G80_NUM_I2C_PORTS) {
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "LVDS: unrecognized port %d\n", port);
+ break;
+ }
pNv->lvds.i2cPort = port;
break;
@@ -217,9 +232,11 @@ fail:
static CARD32 i2cAddr(const int port)
{
- const CARD32 base = (port > 3) ? 0x0000E1D4 : 0x0000E138;
- const CARD32 offset = (port > 3) ? 0x20 : 0x18;
- return base + port * offset;
+ const CARD32 addrs[G80_NUM_I2C_PORTS] = {
+ 0xE138, 0xE150, 0xE168, 0xE180, 0xE254, 0xE274, 0xE764, 0xE780, 0xE79C,
+ 0xE7B8
+ };
+ return addrs[port];
}
static void G80_I2CPutBits(I2CBusPtr b, int clock, int data)
diff --git a/src/g80_type.h b/src/g80_type.h
index 0cebae7..9bb07a4 100644
--- a/src/g80_type.h
+++ b/src/g80_type.h
@@ -7,7 +7,7 @@
#include <xf86Crtc.h>
#include <xf86int10.h>
-#define G80_NUM_I2C_PORTS 6
+#define G80_NUM_I2C_PORTS 10
typedef enum Head {
HEAD0 = 0,
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 41840dd..d1f4c24 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -727,6 +727,8 @@ NVIsG80(int chipType)
case 0x0650:
case 0x06e0:
case 0x06f0:
+ case 0x0a60:
+ case 0x0a70:
return TRUE;
}