summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@linux.ie>2007-03-25 12:12:55 +1000
committerDave Airlie <airlied@linux.ie>2007-03-25 12:12:55 +1000
commit4c2d386aef46a10541ab3d43165226dda8060b0d (patch)
tree73640c92d1b92703f7de9777b473b54f2d56a338
parent5f23553ab361e586a366e9e3cc9a483f8c5621de (diff)
downloadxorg-driver-xf86-video-nouveau-4c2d386aef46a10541ab3d43165226dda8060b0d.tar.gz
randr12: attempt to parse DCB table from nv40 bios
-rw-r--r--src/nv_bios.c57
-rw-r--r--src/nv_output.c137
-rw-r--r--src/nv_type.h6
3 files changed, 155 insertions, 45 deletions
diff --git a/src/nv_bios.c b/src/nv_bios.c
index 286e85f..a43a4fb 100644
--- a/src/nv_bios.c
+++ b/src/nv_bios.c
@@ -1498,6 +1498,52 @@ static unsigned int findstr(bios_t* bios, unsigned char *str, int len)
return 0;
}
+#define G5_FIXED_LOC 0xe2f8
+
+
+static unsigned int nv_find_dcb_table(ScrnInfoPtr pScrn, bios_t *bios)
+{
+ NVPtr pNv = NVPTR(pScrn);
+ CARD16 bufloc;
+ int is_g5;
+ CARD32 sig;
+ char *table2;
+ unsigned char headerSize, entries;
+ CARD32 header_word;
+ int i;
+
+ /* get the offset from 0x36 */
+
+ bufloc = *(CARD16 *)&bios->data[0x36];
+ if (bufloc == 0x0) {
+ if ((pNv->Chipset & 0x0ff0) == CHIPSET_NV43) {
+ is_g5 = 1;
+ bufloc = G5_FIXED_LOC;
+ } else {
+ return 0;
+ }
+ }
+
+ table2 = &bios->data[bufloc];
+ sig = *(uint32_t*)(table2 + 6);
+ if ((sig != 0x4edcbdcb) && (sig!=0xcbbddc4e))
+ return 0;
+
+ header_word = *(uint32_t *)table2;
+ headerSize = (header_word >> 8) & 0xff;
+ entries = (header_word >> 16) & 0xff;
+
+ if (entries >= NV40_NUM_DCB_ENTRIES)
+ entries = NV40_NUM_DCB_ENTRIES;
+
+ for (i = 0; i < entries; i++) {
+ pNv->dcb_table[i] = *(uint32_t *)&table2[headerSize + 8 * i];
+ }
+
+ return entries;
+}
+
+
unsigned int NVParseBios(ScrnInfoPtr pScrn)
{
unsigned int bit_offset;
@@ -1507,7 +1553,7 @@ unsigned int NVParseBios(ScrnInfoPtr pScrn)
unsigned char nv_signature[]={0xff,0x7f,'N','V',0x0};
unsigned char bit_signature[]={'B','I','T'};
NVPtr pNv;
- int i;
+ int i, ret;
pNv = NVPTR(pScrn);
bios.data=xalloc(NV_PROM_SIZE);
@@ -1546,6 +1592,15 @@ unsigned int NVParseBios(ScrnInfoPtr pScrn)
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No known script signature found.\n");
}
+ /* look for NV40+ DCB table - and make a copy somewhere for output setup code */
+ ret = nv_find_dcb_table(pScrn, &bios);
+ if (ret)
+ {
+ pNv->dcb_entries = ret;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DCB found %d entries.\n", ret);
+ }
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No DCB table found\n");
xfree(bios.data);
return 1;
}
diff --git a/src/nv_output.c b/src/nv_output.c
index eeebab0..1faf3b5 100644
--- a/src/nv_output.c
+++ b/src/nv_output.c
@@ -682,6 +682,71 @@ static const xf86OutputFuncsRec nv_lvds_output_funcs = {
.commit = nv_output_commit,
};
+
+static void nv_add_analog_output(ScrnInfoPtr pScrn, int i2c_index)
+{
+ NVPtr pNv = NVPTR(pScrn);
+ xf86OutputPtr output;
+ NVOutputPrivatePtr nv_output;
+ char outputname[20];
+ int crtc_mask = (1<<0) | (1<<1);
+
+ sprintf(outputname, "Analog-%d", pNv->analog_count);
+ output = xf86OutputCreate (pScrn, &nv_analog_output_funcs, outputname);
+ if (!output)
+ return;
+ nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
+ if (!nv_output)
+ {
+ xf86OutputDestroy (output);
+ return;
+ }
+
+ output->driver_private = nv_output;
+ nv_output->type = OUTPUT_ANALOG;
+
+ nv_output->ramdac = pNv->analog_count;
+
+ nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
+
+ output->possible_crtcs = crtc_mask;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
+
+ pNv->analog_count++;
+}
+
+
+static void nv_add_digital_output(ScrnInfoPtr pScrn, int i2c_index)
+{
+ NVPtr pNv = NVPTR(pScrn);
+ xf86OutputPtr output;
+ NVOutputPrivatePtr nv_output;
+ char outputname[20];
+ int crtc_mask = (1<<0) | (1<<1);
+
+ sprintf(outputname, "Digital-%d", pNv->digital_count);
+ output = xf86OutputCreate (pScrn, &nv_digital_output_funcs, outputname);
+ if (!output)
+ return;
+ nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
+ if (!nv_output)
+ {
+ xf86OutputDestroy (output);
+ return;
+ }
+
+ output->driver_private = nv_output;
+ nv_output->type = OUTPUT_DIGITAL;
+
+ nv_output->ramdac = pNv->digital_count;
+
+ nv_output->pDDCBus = pNv->pI2CBus[i2c_index];
+
+ output->possible_crtcs = crtc_mask;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
+
+ pNv->digital_count++;
+}
/**
* Set up the outputs according to what type of chip we are.
*
@@ -697,61 +762,45 @@ void Nv20SetupOutputs(ScrnInfoPtr pScrn)
int i;
int num_analog_outputs = pNv->twoHeads ? 2 : 1;
int num_digital_outputs = 1;
- char outputname[20];
- int crtc_mask = (1<<0) | (1<<1);
for (i = 0 ; i < num_analog_outputs; i++) {
- sprintf(outputname, "Analog-%d", i);
- output = xf86OutputCreate (pScrn, &nv_analog_output_funcs, outputname);
- if (!output)
- return;
- nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
- if (!nv_output)
- {
- xf86OutputDestroy (output);
- return;
- }
-
- output->driver_private = nv_output;
- nv_output->type = OUTPUT_ANALOG;
-
- nv_output->ramdac = i;
-
- nv_output->pDDCBus = pNv->pI2CBus[i];
-
- output->possible_crtcs = crtc_mask;
- xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
-
+ nv_add_analog_output(pScrn, i);
}
for (i = 0 ; i < num_digital_outputs; i++) {
- sprintf(outputname, "Digital-%d", i);
- output = xf86OutputCreate (pScrn, &nv_digital_output_funcs, outputname);
- if (!output)
- return;
- nv_output = xnfcalloc (sizeof (NVOutputPrivateRec), 1);
- if (!nv_output)
- {
- xf86OutputDestroy (output);
- return;
- }
-
- output->driver_private = nv_output;
- nv_output->type = OUTPUT_DIGITAL;
-
- nv_output->ramdac = i;
-
- nv_output->pDDCBus = pNv->pI2CBus[i];
-
- output->possible_crtcs = crtc_mask;
- xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Adding output %s\n", outputname);
+ nv_add_digital_output(pScrn, i);
}
-
}
void Nv40SetupOutputs(ScrnInfoPtr pScrn)
{
+ unsigned char type, port, or;
+ NVPtr pNv = NVPTR(pScrn);
+ int i;
+
/* we setup the outputs up from the BIOS table */
+ if (pNv->dcb_entries) {
+ for (i = 0 ; i < pNv->dcb_entries; i++) {
+ type = pNv->dcb_table[i] & 0xf;
+ port = (pNv->dcb_table[i] >> 4) & 0xf;
+ or = ffs((pNv->dcb_table[i] >> 24) & 0xf) - 1;
+
+ if (type < 4)
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DCB entry: %d: %08X type: %d, port %d:, or %d\n", i, pNv->dcb_table[i], type, port, or);
+ if (type < 4 && port != 0xf) {
+ switch(type) {
+ case 0: /* analog */
+ nv_add_analog_output(pScrn, port);
+ break;
+ case 2:
+ nv_add_digital_output(pScrn, port);
+ default:
+ break;
+ }
+ }
+ }
+ } else
+ Nv20SetupOutputs(pScrn);
}
diff --git a/src/nv_type.h b/src/nv_type.h
index 70d3798..36ec7b5 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -71,6 +71,7 @@
#define Set8Bits(value) ((value)&0xff)
#define NV_I2C_BUSES 3
+#define NV40_NUM_DCB_ENTRIES 10
typedef enum
{
@@ -303,6 +304,11 @@ typedef struct _NVRec {
/* we know about 3 i2c buses */
I2CBusPtr pI2CBus[3];
+ int dcb_entries;
+
+ int analog_count;
+ int digital_count;
+ CARD32 dcb_table[NV40_NUM_DCB_ENTRIES]; /* 10 is a good limit */
} NVRec;
#define NVPTR(p) ((NVPtr)((p)->driverPrivate))