mirror of
https://github.com/X11Libre/xf86-video-nv.git
synced 2026-03-24 01:24:21 +00:00
G80: Handle extended I2C ports and LVDS panels with DDC-based EDIDs.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 NVIDIA, Corporation
|
||||
* Copyright (c) 2007-2008 NVIDIA, Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
@@ -76,7 +76,7 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
|
||||
CARD32 b;
|
||||
|
||||
/* Clear the i2c map to invalid */
|
||||
for(i = 0; i < 4; i++)
|
||||
for(i = 0; i < G80_NUM_I2C_PORTS; i++)
|
||||
pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
|
||||
|
||||
if(*(CARD16*)pNv->table1 != 0xaa55) goto fail;
|
||||
@@ -162,6 +162,27 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
|
||||
case 3: /* LVDS */
|
||||
pNv->lvds.present = TRUE;
|
||||
pNv->lvds.or = or;
|
||||
pNv->lvds.i2cPort = -1;
|
||||
|
||||
if(port == 15) {
|
||||
xf86DrvMsg(scrnIndex, X_INFO, "LVDS has no I2C port\n");
|
||||
break;
|
||||
}
|
||||
if(port >= table3Entries) {
|
||||
xf86DrvMsg(scrnIndex, X_WARNING,
|
||||
"LVDS: invalid port %d\n", port);
|
||||
break;
|
||||
}
|
||||
b = *(CARD32*)&table3[table3EntSize * port];
|
||||
port = b & 0xff;
|
||||
portType = b >> 24;
|
||||
if(portType != 5) {
|
||||
xf86DrvMsg(scrnIndex, X_WARNING,
|
||||
"LVDS: invalid port type %d\n", portType);
|
||||
break;
|
||||
}
|
||||
pNv->lvds.i2cPort = port;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -172,7 +193,7 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
|
||||
xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n");
|
||||
if(pNv->lvds.present)
|
||||
xf86DrvMsg(scrnIndex, X_PROBED, " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or);
|
||||
for(i = 0; i < 4; i++) {
|
||||
for(i = 0; i < G80_NUM_I2C_PORTS; i++) {
|
||||
if(pNv->i2cMap[i].dac != -1)
|
||||
xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
|
||||
if(pNv->i2cMap[i].sor != -1)
|
||||
@@ -190,21 +211,24 @@ fail:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static uint32_t i2cAddr(const int port)
|
||||
{
|
||||
const uint32_t base = (port > 3) ? 0x0000E1E0 : 0x0000E138;
|
||||
return base + port * 0x18;
|
||||
}
|
||||
|
||||
static void G80_I2CPutBits(I2CBusPtr b, int clock, int data)
|
||||
{
|
||||
G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
|
||||
const int off = b->DriverPrivate.val * 0x18;
|
||||
|
||||
pNv->reg[(0x0000E138+off)/4] = 4 | clock | data << 1;
|
||||
pNv->reg[i2cAddr(b->DriverPrivate.val)/4] = 4 | clock | data << 1;
|
||||
}
|
||||
|
||||
static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data)
|
||||
{
|
||||
G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
|
||||
const int off = b->DriverPrivate.val * 0x18;
|
||||
unsigned char val;
|
||||
|
||||
val = pNv->reg[(0x0000E138+off)/4];
|
||||
val = pNv->reg[i2cAddr(b->DriverPrivate.val)/4];
|
||||
*clock = !!(val & 1);
|
||||
*data = !!(val & 2);
|
||||
}
|
||||
@@ -272,14 +296,15 @@ ProbeDDC(I2CBusPtr i2c)
|
||||
ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex];
|
||||
G80Ptr pNv = G80PTR(pScrn);
|
||||
xf86MonPtr monInfo = NULL;
|
||||
const int bus = i2c->DriverPrivate.val, off = bus * 0x18;
|
||||
const int bus = i2c->DriverPrivate.val;
|
||||
const uint32_t addr = i2cAddr(bus);
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"Probing for EDID on I2C bus %i...\n", bus);
|
||||
pNv->reg[(0x0000E138+off)/4] = 7;
|
||||
pNv->reg[addr/4] = 7;
|
||||
/* Should probably use xf86OutputGetEDID here */
|
||||
monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c);
|
||||
pNv->reg[(0x0000E138+off)/4] = 3;
|
||||
pNv->reg[addr/4] = 3;
|
||||
|
||||
if(monInfo) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
|
||||
@@ -376,7 +401,7 @@ G80CreateOutputs(ScrnInfoPtr pScrn)
|
||||
return FALSE;
|
||||
|
||||
/* For each DDC port, create an output for the attached ORs */
|
||||
for(i = 0; i < 4; i++) {
|
||||
for(i = 0; i < G80_NUM_I2C_PORTS; i++) {
|
||||
xf86OutputPtr dac = NULL, sor = NULL;
|
||||
I2CBusPtr i2c;
|
||||
char i2cName[16];
|
||||
@@ -420,6 +445,19 @@ G80CreateOutputs(ScrnInfoPtr pScrn)
|
||||
G80OutputPrivPtr pPriv = lvds->driver_private;
|
||||
|
||||
pPriv->scale = G80_SCALE_ASPECT;
|
||||
|
||||
if(pNv->lvds.i2cPort != -1) {
|
||||
I2CBusPtr i2c;
|
||||
char i2cName[16];
|
||||
|
||||
snprintf(i2cName, sizeof(i2cName), "I2C%i (LVDS)", pNv->lvds.i2cPort);
|
||||
pPriv->i2c = G80I2CInit(pScrn, i2cName, pNv->lvds.i2cPort);
|
||||
if(!pPriv->i2c) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
"Failed to initialize I2C for port %i (LVDS)!\n",
|
||||
pNv->lvds.i2cPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For each output, set the crtc and clone masks */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 NVIDIA, Corporation
|
||||
* Copyright (c) 2007-2008 NVIDIA, Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
@@ -143,7 +143,15 @@ G80SorDetect(xf86OutputPtr output)
|
||||
static xf86OutputStatus
|
||||
G80SorLVDSDetect(xf86OutputPtr output)
|
||||
{
|
||||
/* Assume LVDS is always connected */
|
||||
G80OutputPrivPtr pPriv = output->driver_private;
|
||||
|
||||
if(pPriv->i2c) {
|
||||
/* If LVDS has an I2C port, use the normal probe routine to get the
|
||||
* EDID, if possible. */
|
||||
G80SorDetect(output);
|
||||
}
|
||||
|
||||
/* Ignore G80SorDetect and assume LVDS is always connected */
|
||||
return XF86OutputStatusConnected;
|
||||
}
|
||||
|
||||
@@ -242,6 +250,13 @@ static DisplayModePtr
|
||||
G80SorGetLVDSModes(xf86OutputPtr output)
|
||||
{
|
||||
G80OutputPrivPtr pPriv = output->driver_private;
|
||||
|
||||
/* If an EDID was read during detection, use the modes from that. */
|
||||
DisplayModePtr modes = G80OutputGetDDCModes(output);
|
||||
if(modes)
|
||||
return modes;
|
||||
|
||||
/* Otherwise, feed in the mode we read during initialization. */
|
||||
return xf86DuplicateMode(pPriv->nativeMode);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <xf86Crtc.h>
|
||||
#include <xf86int10.h>
|
||||
|
||||
#define G80_NUM_I2C_PORTS 6
|
||||
|
||||
typedef enum Head {
|
||||
HEAD0 = 0,
|
||||
HEAD1
|
||||
@@ -51,10 +53,11 @@ typedef struct G80Rec {
|
||||
struct {
|
||||
ORNum dac;
|
||||
ORNum sor;
|
||||
} i2cMap[4];
|
||||
} i2cMap[G80_NUM_I2C_PORTS];
|
||||
struct {
|
||||
Bool present;
|
||||
ORNum or;
|
||||
int i2cPort;
|
||||
} lvds;
|
||||
unsigned loadVal;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user