xf86-video-intel: Branch 'modesetting' - 3 commits - src/i810_reg.h src/i830_display.c src/i830_display.h src/i830_driver.c src/i830.h src/i830_sdvo.c src/i830_sdvo_regs.h src/Makefile.am

Eric Anholt anholt at kemper.freedesktop.org
Thu Apr 20 01:06:29 EEST 2006


 src/Makefile.am      |    3 
 src/i810_reg.h       |   17 +
 src/i830.h           |    2 
 src/i830_display.c   |   37 +++
 src/i830_display.h   |    7 
 src/i830_driver.c    |   61 +++--
 src/i830_sdvo.c      |  578 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/i830_sdvo_regs.h |  173 +++++++++++++++
 8 files changed, 849 insertions(+), 29 deletions(-)

New commits:
diff-tree 132dc0599cf44389c4cc03919f1da8d3a0762b44 (from 88bb4b578857588f34ac84b7a20577139eccab6d)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Wed Apr 19 15:04:17 2006 -0700

    Whine if SDVO I2C device init fails, rather than be silent.

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 3b3efa1..b656bc6 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -547,13 +547,13 @@ I830SDVOInit(I2CBusPtr b)
     sdvo->d.ByteTimeout = b->ByteTimeout;
     sdvo->d.DriverPrivate.ptr = sdvo;
 
-    if (!xf86I2CDevInit(&sdvo->d))
-	goto out;
+    if (!xf86I2CDevInit(&sdvo->d)) {
+	xf86DrvMsg(b->scrnIndex, X_ERROR,
+		   "Failed to initialize SDVO I2C device\n");
+	xfree(sdvo);
+	return NULL;
+    }
     return sdvo;
-
-out:
-    xfree(sdvo);
-    return NULL;
 }
 
 Bool
diff-tree 88bb4b578857588f34ac84b7a20577139eccab6d (from d8f7dfac769d7b03f069306b1296bb2e1e08b009)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Wed Apr 19 14:23:45 2006 -0700

    Add more SDVO code.  It's taken from airlied's driver, but with magic numbers
    replaced by symbolic names in many places.  I tried to restrain myself from
    functional changes in airlied's code in this pass.

diff --git a/src/i830.h b/src/i830.h
index a631258..fa1f017 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -580,10 +580,6 @@ extern Bool I830RandRInit(ScreenPtr pScr
 extern Bool I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg,
 			char *name);
 
-/* i830_sdvo.c */
-extern I830SDVOPtr I830SDVOInit(I2CBusPtr b);
-extern Bool I830I2CDetectSDVOController(ScrnInfoPtr pScrn, int output_index);
-
 /*
  * 12288 is set as the maximum, chosen because it is enough for
  * 1920x1440 at 32bpp with a 2048 pixel line pitch with some to spare.
diff --git a/src/i830_display.c b/src/i830_display.c
index fd3c352..6fef425 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -571,6 +571,7 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayMo
 #ifdef XF86DRI
     Bool didLock = FALSE;
 #endif
+    int i;
 
     DPRINTF(PFX, "i830SetMode\n");
 
@@ -590,6 +591,11 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayMo
 	pI830->planeEnabled[1] = 0;
     }
 
+    for (i = 0; i < pI830->num_outputs; i++) {
+	if (pI830->output[i].sdvo_drv && pI830->output[i].sdvo_drv->found)
+	    I830SDVOPreSetMode(pI830->output[i].sdvo_drv, pMode);
+    }
+
     if (pI830->planeEnabled[0]) {
 	ok = i830PipeSetMode(pScrn, pMode, 0);
 	if (!ok)
@@ -600,6 +606,10 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayMo
 	if (!ok)
 	    goto done;
     }
+    for (i = 0; i < pI830->num_outputs; i++) {
+	if (pI830->output[i].sdvo_drv && pI830->output[i].sdvo_drv->found)
+	    I830SDVOPostSetMode(pI830->output[i].sdvo_drv, pMode);
+    }
 
     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Mode bandwidth is %d Mpixel/s\n",
 	       (int)(pMode->HDisplay * pMode->VDisplay *
diff --git a/src/i830_display.h b/src/i830_display.h
index d8e4e5e..9f07ba1 100644
--- a/src/i830_display.h
+++ b/src/i830_display.h
@@ -25,7 +25,14 @@
  *
  */
 
+/* i830_display.c */
 Bool i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
 Bool i830DetectCRT(ScrnInfoPtr pScrn);
 void i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on);
 void i830PipeSetBase(ScrnInfoPtr pScrn, int pipe, int x, int y);
+
+/* i830_sdvo.c */
+I830SDVOPtr I830SDVOInit(I2CBusPtr b);
+Bool I830I2CDetectSDVOController(ScrnInfoPtr pScrn, int output_index);
+Bool I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode);
+Bool I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode);
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 7f5549c..3b3efa1 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -28,6 +28,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "xf86_OSproc.h"
 #include "compiler.h"
 #include "i830.h"
+#include "i830_sdvo_regs.h"
+
+CARD16 curr_table[6];
 
 /* SDVO support for i9xx chipsets */
 static Bool sReadByte(I830SDVOPtr s, int addr, unsigned char *ch)
@@ -41,7 +44,6 @@ static Bool sReadByte(I830SDVOPtr s, int
     return TRUE;
 }
 
-#if 0
 static Bool sWriteByte(I830SDVOPtr s, int addr, unsigned char ch)
 {
     if (!xf86I2CWriteByte(&s->d, addr, ch)) {
@@ -52,8 +54,481 @@ static Bool sWriteByte(I830SDVOPtr s, in
     }
     return TRUE;
 }
+
+/* following on from tracing the intel BIOS i2c routines */
+static void
+I830SDVOWriteOutputs(I830SDVOPtr s, int num_out)
+{
+    int i;
+
+    ErrorF("SDVO: W: ");
+    for (i = num_out; i <= SDVO_I2C_ARG_0; i++)
+	ErrorF("%02X ", s->sdvo_regs[i]);
+    ErrorF("\n");
+
+    /* blast the output regs */
+    for (i = SDVO_I2C_ARG_0; i >= num_out; i--) {
+	sWriteByte(s, i, s->sdvo_regs[i]);
+    }
+    /* blast the command reg */
+    sWriteByte(s, SDVO_I2C_OPCODE, s->sdvo_regs[SDVO_I2C_OPCODE]);
+}
+
+static void
+I830SDVOReadInputRegs(I830SDVOPtr s)
+{
+    int i;
+
+    /* follow BIOS ordering */
+    sReadByte(s, SDVO_I2C_CMD_STATUS, &s->sdvo_regs[SDVO_I2C_CMD_STATUS]);
+  
+    sReadByte(s, SDVO_I2C_RETURN_3, &s->sdvo_regs[SDVO_I2C_RETURN_3]);
+    sReadByte(s, SDVO_I2C_RETURN_2, &s->sdvo_regs[SDVO_I2C_RETURN_2]);
+    sReadByte(s, SDVO_I2C_RETURN_1, &s->sdvo_regs[SDVO_I2C_RETURN_1]);
+    sReadByte(s, SDVO_I2C_RETURN_0, &s->sdvo_regs[SDVO_I2C_RETURN_0]);
+    sReadByte(s, SDVO_I2C_RETURN_7, &s->sdvo_regs[SDVO_I2C_RETURN_7]);
+    sReadByte(s, SDVO_I2C_RETURN_6, &s->sdvo_regs[SDVO_I2C_RETURN_6]);
+    sReadByte(s, SDVO_I2C_RETURN_5, &s->sdvo_regs[SDVO_I2C_RETURN_5]);
+    sReadByte(s, SDVO_I2C_RETURN_4, &s->sdvo_regs[SDVO_I2C_RETURN_4]);
+
+    ErrorF("SDVO: R: ");
+    for (i = SDVO_I2C_CMD_STATUS; i <= SDVO_I2C_RETURN_7; i++)
+	ErrorF("%02X ", s->sdvo_regs[i]);
+    ErrorF("\n");
+}
+
+Bool
+I830SDVOSetupDDC(I830SDVOPtr s, int enable)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
+    s->sdvo_regs[SDVO_I2C_ARG_0] = SDVO_CONTROL_BUS_DDC2;
+
+    I830SDVOWriteOutputs(s, 7);
+
+    sReadByte(s, SDVO_I2C_CMD_STATUS, &s->sdvo_regs[SDVO_I2C_CMD_STATUS]);
+
+    ErrorF("SDVO: R: ");
+    ErrorF("%02X ", s->sdvo_regs[SDVO_I2C_CMD_STATUS]);
+    ErrorF("\n");
+    return TRUE;
+}
+
+static Bool
+I830SDVOSetTargetInput(I830SDVOPtr s)
+{
+    /* write out 0x10 */
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_TARGET_INPUT;
+
+    I830SDVOWriteOutputs(s, 0);
+
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+static Bool
+I830SDVOGetTrainedInputs(I830SDVOPtr s, int on)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_TRAINED_INPUTS;
+
+    /* XXX: I don't believe we need to set anything here --anholt */
+    s->sdvo_regs[0x07] = on ? 0x80 : 0x00;
+    s->sdvo_regs[0x04] = on ? 0x80 : 0x00;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+static Bool
+I830SDVOGetActiveOutputs(I830SDVOPtr s, int on)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_ACTIVE_OUTPUTS;
+
+    s->sdvo_regs[0x07] = on ? 0x01 : 0x00;
+    s->sdvo_regs[0x03] = 0x1;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+static Bool
+I830SDVOSetActiveOutputs(I830SDVOPtr s, int on)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_ACTIVE_OUTPUTS;
+
+    /* XXX: This should be touching args 0,1, I believe.  --anholt */
+    s->sdvo_regs[0x07] = on ? 0x01 : 0x00;
+    s->sdvo_regs[0x03] = on ? 0x01 : 0x00;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+static Bool
+I830SDVOGetInputPixelClockRange(I830SDVOPtr s, CARD16 clock, CARD16 height)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE;
+
+    /* XXX: SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE shouldn't be taking args. */
+
+    /* set clock regs */
+    s->sdvo_regs[0x06] = (clock >> 8) & 0xff;
+    s->sdvo_regs[0x07] = clock & 0xff;
+
+    /* set height regs */
+    s->sdvo_regs[0x02] = (height >> 8) & 0xff;
+    s->sdvo_regs[0x03] = height & 0xff;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+static Bool
+I830SDVOSetTargetOutput(I830SDVOPtr s)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_TARGET_OUTPUT;
+
+    s->sdvo_regs[SDVO_I2C_ARG_0] = 0x1;	/* Enable */
+    s->sdvo_regs[SDVO_I2C_ARG_1] = 0x0; /* Disable */
+
+    I830SDVOWriteOutputs(s, 0);		/* XXX: Only write these two */
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+#if 0
+static Bool
+I830SDVOGetOutputTimingsPart1(I830SDVOPtr s)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_OUTPUT_TIMINGS_PART1;
+
+    /* XXX: No args */
+    s->sdvo_regs[0x07] = 0x0;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+  
+    return TRUE;
+}
+
+static Bool
+I830SDVOGetOutputTimingsPart2(I830SDVOPtr s)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_OUTPUT_TIMINGS_PART2;
+
+    /* XXX: No args */
+    s->sdvo_regs[0x07] = 0x0;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
 #endif
 
+static Bool
+I830SDVOSetTimingsPart1(I830SDVOPtr s, char cmd, CARD16 clock, CARD16 magic1,
+			CARD16 magic2, CARD16 magic3)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = cmd;
+
+    /* set clock regs */
+    s->sdvo_regs[SDVO_I2C_ARG_0] = clock & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_1] = (clock >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_2] = magic3 & 0xff;  
+    s->sdvo_regs[SDVO_I2C_ARG_3] = (magic3 >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_4] = magic2 & 0xff;  
+    s->sdvo_regs[SDVO_I2C_ARG_5] = (magic2 >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_6] = magic1 & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_7] = (magic1 >> 8) & 0xff;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+  
+    return TRUE;
+}
+
+static Bool
+I830SDVOSetInputTimingsPart1(I830SDVOPtr s, CARD16 clock,
+			     CARD16 magic1, CARD16 magic2, CARD16 magic3)
+{
+    return I830SDVOSetTimingsPart1(s, SDVO_CMD_SET_INPUT_TIMINGS_PART1,
+				   clock, magic1, magic2, magic3);
+}
+
+static Bool
+I830SDVOSetOutputTimingsPart1(I830SDVOPtr s, CARD16 clock, CARD16 magic1,
+			      CARD16 magic2, CARD16 magic3)
+{
+    return I830SDVOSetTimingsPart1(s, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1,
+				   clock, magic1, magic2, magic3);
+}
+
+static Bool
+I830SDVOGetPreferredInputTimingPart2(I830SDVOPtr s, CARD16 clock,
+				     CARD16 magic1, CARD16 magic2,
+				     CARD16 magic3)
+{
+    Bool ok;
+
+    /* XXX: This is a rather different command */
+    ok = I830SDVOSetTimingsPart1(s, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
+				 clock, magic1, magic2, magic3);
+
+    curr_table[3] = s->sdvo_regs[SDVO_I2C_RETURN_0] |
+		    (s->sdvo_regs[SDVO_I2C_RETURN_1] << 8);
+    curr_table[4] = s->sdvo_regs[SDVO_I2C_RETURN_2] |
+		    (s->sdvo_regs[SDVO_I2C_RETURN_3] << 8);
+    curr_table[5] = 0x1e;
+
+    return ok;
+}
+
+static Bool
+I830SDVOSetTimingsPart2(I830SDVOPtr s, CARD8 cmd, CARD16 magic4, CARD16 magic5,
+			CARD16 magic6)
+{
+    memset(s->sdvo_regs, 0, 9);
+  
+    s->sdvo_regs[SDVO_I2C_OPCODE] = cmd;
+ 
+    /* set clock regs */
+    s->sdvo_regs[SDVO_I2C_ARG_0] = magic4 & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_1] = (magic4 >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_2] = magic5 & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_3] = (magic5 >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_4] = magic6 & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_5] = (magic6 >> 8) & 0xff;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+  
+    return TRUE;
+}
+
+static Bool
+I830SDVOSetInputTimingsPart2(I830SDVOPtr s, CARD16 magic4, CARD16 magic5,
+			     CARD16 magic6)
+{
+    return I830SDVOSetTimingsPart2(s, SDVO_CMD_SET_INPUT_TIMINGS_PART2, magic4,
+				   magic5, magic6);
+}
+
+static Bool
+I830SDVOSetOutputTimingsPart2(I830SDVOPtr s, CARD16 magic4, CARD16 magic5,
+			      CARD16 magic6)
+{
+    return I830SDVOSetTimingsPart2(s, SDVO_CMD_SET_OUTPUT_TIMINGS_PART2, magic4,
+				   magic5, magic6);
+}
+
+static Bool
+I830SDVOCreatePreferredInputTiming(I830SDVOPtr s, CARD16 clock, CARD16 width,
+				   CARD16 height)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING;
+
+    s->sdvo_regs[SDVO_I2C_ARG_0] = clock & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_1] = (clock >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_2] = width & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_3] = (width >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_4] = (height >> 8) & 0xff;
+    s->sdvo_regs[SDVO_I2C_ARG_5] = height & 0xff;  
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+static Bool
+I830SDVOGetPreferredInputTimingPart1(I830SDVOPtr s)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1;
+
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    curr_table[0] = s->sdvo_regs[SDVO_I2C_RETURN_6] |
+		    (s->sdvo_regs[SDVO_I2C_RETURN_7] << 8);
+    curr_table[1] = s->sdvo_regs[SDVO_I2C_RETURN_4] |
+		    (s->sdvo_regs[SDVO_I2C_RETURN_5] << 8);
+    curr_table[2] = s->sdvo_regs[SDVO_I2C_RETURN_2] |
+		    (s->sdvo_regs[SDVO_I2C_RETURN_3] << 8);
+
+    return TRUE;
+}
+
+static Bool
+I830SDVOSetClockRateMult(I830SDVOPtr s, CARD8 val)
+{
+    memset(s->sdvo_regs, 0, 9);
+
+    s->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_CLOCK_RATE_MULT;
+
+    s->sdvo_regs[SDVO_I2C_ARG_0] = val;
+    I830SDVOWriteOutputs(s, 0);
+    I830SDVOReadInputRegs(s);
+
+    return TRUE;
+}
+
+Bool
+I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode)
+{
+    CARD16 clock = mode->Clock/10, width = mode->CrtcHDisplay;
+    CARD16 height = mode->CrtcVDisplay;
+    CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
+    CARD16 h_sync_offset, v_sync_offset;
+    CARD16 sync_flags;
+    CARD8 c16a[8];
+    CARD8 c17a[8];
+    CARD16 out_timings[6];
+
+    /* do some mode translations */
+    h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart;
+    h_sync_len = mode->CrtcHSyncEnd - mode->CrtcHSyncStart;
+
+    v_blank_len = mode->CrtcVBlankEnd - mode->CrtcVBlankStart;
+    v_sync_len = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
+
+    h_sync_offset = mode->CrtcHSyncStart - mode->CrtcHBlankStart;
+    v_sync_offset = mode->CrtcVSyncStart - mode->CrtcVBlankStart;
+
+    sync_flags = 0x18;
+    if (mode->Flags & V_PHSYNC)
+	sync_flags |= 0x2;
+    if (mode->Flags & V_PVSYNC)
+	sync_flags |= 0x4;
+    /* high bits of 0 */
+    c16a[7] = clock & 0xff;
+    c16a[6] = (clock >> 8) & 0xff;
+    c16a[5] = (width & 0xff);
+    c16a[4] = (h_blank_len & 0xff);
+    c16a[3] = (((width >> 8) & 0xf) << 4) | ((h_blank_len >> 8) & 0xf);
+    c16a[2] = (height & 0xff);
+    c16a[1] = (v_blank_len & 0xff);
+    c16a[0] = (((height >> 8) & 0xf) << 4) | ((v_blank_len >> 8) & 0xf);
+
+    c17a[7] = h_sync_offset;
+    c17a[6] = h_sync_len & 0xff;
+    c17a[5] = (v_sync_offset & 0xf) << 4 | (v_sync_len & 0xf);
+    c17a[4] = 0;
+    c17a[3] = sync_flags;
+    c17a[2] = 0;
+    out_timings[0] = c16a[1] | ((short)c16a[0] << 8);
+    out_timings[1] = c16a[3] | ((short)c16a[2] << 8);
+    out_timings[2] = c16a[5] | ((short)c16a[4] << 8);
+    out_timings[3] = c17a[7] | ((short)c17a[6] << 8);
+    out_timings[4] = c17a[5] | ((short)c17a[4] << 8);
+    out_timings[5] = c17a[3] | ((short)c17a[2] << 8);
+
+    I830SDVOSetTargetInput(s);
+    I830SDVOGetInputPixelClockRange(s, clock, height);
+
+    I830SDVOGetActiveOutputs(s, 0);
+    I830SDVOSetActiveOutputs(s, 0);
+
+    I830SDVOSetTargetOutput(s);
+    I830SDVOSetOutputTimingsPart1(s, clock, out_timings[0], out_timings[1],
+				  out_timings[2]);
+
+    I830SDVOSetTargetOutput(s);
+    I830SDVOSetOutputTimingsPart2(s, out_timings[3], out_timings[4],
+				  out_timings[5]);
+
+    I830SDVOSetTargetInput(s);
+
+    I830SDVOCreatePreferredInputTiming(s, clock, width, height);
+    I830SDVOSetTargetInput(s);
+
+    I830SDVOGetPreferredInputTimingPart1(s);
+    I830SDVOSetTargetInput(s);
+
+    I830SDVOGetPreferredInputTimingPart2(s, clock, out_timings[0], out_timings[1],
+					 out_timings[2]);
+    I830SDVOSetTargetInput(s);
+
+    I830SDVOSetInputTimingsPart1(s, clock, curr_table[0], curr_table[1],
+				 curr_table[2]);
+
+    I830SDVOSetTargetInput(s);
+    I830SDVOSetInputTimingsPart2(s, curr_table[3], curr_table[4],
+				 out_timings[5]);
+
+    I830SDVOSetTargetInput(s);
+    /*if (mode->PrivFlags & I830_MFLAG_DOUBLE)
+	I830SDVOSetClockRateMult(s, 0x02);
+    else */
+	I830SDVOSetClockRateMult(s, 0x01);
+
+    return TRUE;
+}
+
+Bool
+I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode)
+{
+    int clock = mode->Clock/10, height=mode->CrtcVDisplay;
+    Bool ret = TRUE;
+
+    /* the BIOS writes out 6 commands post mode set */
+    /* two 03s, 04 05, 10, 1d */
+    /* these contain the height and mode clock / 10 by the looks of it */
+
+    I830SDVOGetTrainedInputs(s, 1);
+    I830SDVOGetTrainedInputs(s, 0);
+
+    /* THIS IS A DIRTY HACK - sometimes for some reason on startup
+     * the BIOS doesn't find my DVI monitor -
+     * without this hack the driver doesn't work.. this causes the modesetting
+     * to be re-run
+     */
+    if (s->sdvo_regs[SDVO_I2C_RETURN_0] != 0x1) {
+	ret = FALSE;
+    }
+
+    I830SDVOGetActiveOutputs(s, 1);
+    I830SDVOSetActiveOutputs(s, 1);
+
+    I830SDVOSetTargetInput(s);
+    I830SDVOGetInputPixelClockRange(s, clock, height);
+
+    return ret;
+}
+
 I830SDVOPtr
 I830SDVOInit(I2CBusPtr b)
 {
@@ -92,7 +567,7 @@ I830I2CDetectSDVOController(ScrnInfoPtr 
     if (sdvo == NULL)
 	return FALSE;
 
-    for (i=0; i<0x40; i++) {
+    for (i = 0; i < 0x40; i++) {
 	if (!sReadByte(sdvo, i, &ch[i]))
 	    return FALSE;
     }
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
new file mode 100644
index 0000000..5ad4ac9
--- /dev/null
+++ b/src/i830_sdvo_regs.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric at anholt.net>
+ *
+ */
+
+/* I2C registers for SDVO */
+#define SDVO_I2C_ARG_0				0x07
+#define SDVO_I2C_ARG_1				0x06
+#define SDVO_I2C_ARG_2				0x05
+#define SDVO_I2C_ARG_3				0x04
+#define SDVO_I2C_ARG_4				0x03
+#define SDVO_I2C_ARG_5				0x02
+#define SDVO_I2C_ARG_6				0x01
+#define SDVO_I2C_ARG_7				0x00
+#define SDVO_I2C_OPCODE				0x08
+#define SDVO_I2C_CMD_STATUS			0x09
+#define SDVO_I2C_RETURN_0			0x0a
+#define SDVO_I2C_RETURN_1			0x0b
+#define SDVO_I2C_RETURN_2			0x0c
+#define SDVO_I2C_RETURN_3			0x0d
+#define SDVO_I2C_RETURN_4			0x0e
+#define SDVO_I2C_RETURN_5			0x0f
+#define SDVO_I2C_RETURN_6			0x10
+#define SDVO_I2C_RETURN_7			0x11
+#define SDVO_I2C_VENDOR_BEGIN			0x20
+
+/* Status results */
+#define SDVO_CMD_STATUS_POWER_ON		0x0
+#define SDVO_CMD_STATUS_SUCCESS			0x1
+#define SDVO_CMD_STATUS_NOTSUPP			0x2
+#define SDVO_CMD_STATUS_INVALID_ARG		0x3
+#define SDVO_CMD_STATUS_PENDING			0x4
+#define SDVO_CMD_STATUS_TARGET_NOT_SUPP		0x5
+#define SDVO_CMD_STATUS_SCALING_NOT_SUPP	0x6
+
+/* SDVO commands, argument/result registers */
+#define SDVO_CMD_RESET					0x01
+#define SDVO_CMD_GET_DEVICE_CAPS			0x02
+# define SDVO_DEVICE_CAPS_VENDOR_ID			SDVO_I2C_RETURN_0
+# define SDVO_DEVICE_CAPS_DEVICE_ID			SDVO_I2C_RETURN_1
+# define SDVO_DEVICE_CAPS_DEVICE_REV_ID			SDVO_I2C_RETURN_2
+# define SDVO_DEVICE_CAPS_SDVOVERSION_MINOR		SDVO_I2C_RETURN_3
+# define SDVO_DEVICE_CAPS_SDVOVERSION_MAJOR		SDVO_I2C_RETURN_4
+# define SDVO_DEVICE_CAPS_CAPS				SDVO_I2C_RETURN_5
+# define SDVO_DEVICE_CAPS_INPUTS_MASK				(3 << 0)
+# define SDVO_DEVICE_CAPS_SMOOTH_SCALING			(1 << 2)
+# define SDVO_DEVICE_CAPS_SHARP_SCALING				(1 << 3)
+# define SDVO_DEVICE_CAPS_UP_SCALING				(1 << 4)
+# define SDVO_DEVICE_CAPS_DOWN_SCALING				(1 << 5)
+# define SDVO_DEVICE_CAPS_STALL_SUPPORT				(1 << 6)
+# define SDVO_DEVICE_CAPS_OUTPUT_0_SUPPORTED		SDVO_I2C_RETURN_6
+# define SDVO_DEVICE_CAPS_OUTPUT_1_SUPPORTED		SDVO_I2C_RETURN_7
+
+#define SDVO_CMD_GET_FIRMWARE_REV			0x86
+# define SDVO_DEVICE_FIRMWARE_MINOR			SDVO_I2C_RETURN_0
+# define SDVO_DEVICE_FIRMWARE_MAJOR			SDVO_I2C_RETURN_1
+
+#define SDVO_CMD_GET_TRAINED_INPUTS			0x03
+
+#define SDVO_CMD_GET_ACTIVE_OUTPUTS			0x04
+
+#define SDVO_CMD_SET_ACTIVE_OUTPUTS			0x05
+
+#define SDVO_CMD_GET_IN_OUT_MAP				0x06
+
+#define SDVO_CMD_SET_IN_OUT_MAP				0x07
+
+#define SDVO_CMD_GET_ATTACHED_DISPLAYS			0x0b
+
+#define SDVO_CMD_GET_HOT_PLUG_SUPPORT			0x0c
+
+#define SDVO_CMD_SET_ACTIVE_HOT_PLUG			0x0d
+
+#define SDVO_CMD_GET_ACTIVE_HOT_PLUG			0x0e
+
+#define SDVO_CMD_GET_INTR_EVENT_SOURCE			0x0f
+
+#define SDVO_CMD_SET_TARGET_INPUT			0x10
+
+#define SDVO_CMD_SET_TARGET_OUTPUT			0x11
+
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART1		0x12
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART2		0x13
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART1		0x14
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART2		0x15
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1		0x16
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2		0x17
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1		0x18
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2		0x19
+/* Part 1 */
+# define SDVO_DTD_CLOCK_LOW				SDVO_I2C_ARG_0
+# define SDVO_DTD_CLOCK_HIGH				SDVO_I2C_ARG_1
+# define SDVO_DTD_H_ACTIVE				SDVO_I2C_ARG_2
+# define SDVO_DTD_H_BLANK				SDVO_I2C_ARG_3
+# define SDVO_DTD_H_HIGH				SDVO_I2C_ARG_4
+# define SDVO_DTD_V_ACTIVE				SDVO_I2C_ARG_5
+# define SDVO_DTD_V_BLANK				SDVO_I2C_ARG_6
+# define SDVO_DTD_V_HIGH				SDVO_I2C_ARG_7
+/* Part 2 */
+# define SDVO_DTD_HSYNC_OFF				SDVO_I2C_ARG_0
+# define SDVO_DTD_HSYNC_WIDTH				SDVO_I2C_ARG_1
+# define SDVO_DTD_VSYNC_OFF_WIDTH			SDVO_I2C_ARG_2
+# define SDVO_DTD_SYSNC_OFF_WIDTH_HIGH			SDVO_I2C_ARG_3
+# define SDVO_DTD_DTD_FLAGS				SDVO_I2C_ARG_4
+# define SDVO_DTD_DTD_FLAG_INTERLACED				(1 << 7)
+# define SDVO_DTD_DTD_FLAG_STEREO_MASK				(3 << 5)
+# define SDVO_DTD_DTD_FLAG_INPUT_MASK				(3 << 3)
+# define SDVO_DTD_DTD_FLAG_SYNC_MASK				(3 << 1)
+# define SDVO_DTD_SDVO_FLAS				SDVO_I2C_ARG_5
+# define SDVO_DTD_SDVO_FLAG_STALL				(1 << 7)
+# define SDVO_DTD_SDVO_FLAG_NOT_CENTERED			(1 << 6)
+# define SDVO_DTD_SDVO_FLAG_SCALING_MASK			(3 << 4)
+# define SDVO_DTD_VSYNC_OFF_HIGH			SDVO_I2C_ARG_6
+
+#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING		0x1a
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW		SDVO_I2C_ARG_0
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH		SDVO_I2C_ARG_1
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW		SDVO_I2C_ARG_2
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH		SDVO_I2C_ARG_3
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW		SDVO_I2C_ARG_4
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH	SDVO_I2C_ARG_5
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS		SDVO_I2C_ARG_6
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED		(1 << 0)
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED		(1 << 1)
+
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1	0x1b
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2	0x1c
+
+#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE		0x1d
+#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE		0x1e
+
+#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS		0x1f
+
+#define SDVO_CMD_GET_CLOCK_RATE_MULT			0x20
+
+#define SDVO_CMD_SET_CLOCK_RATE_MULT			0x21
+
+#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS		0x27
+
+#define SDVO_CMD_GET_TV_FORMAT				0x28
+
+#define SDVO_CMD_SET_TV_FORMAT				0x29
+
+#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT		0x93
+
+#define SDVO_CMD_SET_CONTROL_BUS_SWITCH			0x7a
+# define SDVO_CONTROL_BUS_PROM				0x0
+# define SDVO_CONTROL_BUS_DDC1				0x1
+# define SDVO_CONTROL_BUS_DDC2				0x2
+# define SDVO_CONTROL_BUS_DDC3				0x3
+
diff-tree d8f7dfac769d7b03f069306b1296bb2e1e08b009 (from a371a04a57620b7128e3c4395bc7c2ac55effe19)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Wed Apr 19 10:45:13 2006 -0700

    Start bringing in some SDVO code, mostly from airlied.

diff --git a/src/Makefile.am b/src/Makefile.am
index 1789af2..da48149 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -61,7 +61,8 @@ i810_drv_la_SOURCES = \
          i830_modes.c \
          i830_video.c \
          i830_rotate.c \
-	 i830_randr.c
+	 i830_randr.c \
+	 i830_sdvo.c
 
 if DRI
 i810_drv_la_SOURCES += \
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 92d9cf9..82571e0 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -745,6 +745,23 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # define SDVOC_HOTPLUG_INT_STATUS		(1 << 7)
 # define SDVOB_HOTPLUG_INT_STATUS		(1 << 6)
 
+#define SDVOB			0x61140
+#define SDVOC			0x61160
+#define SDVO_ENABLE				(1 << 31)
+#define SDVO_PIPE_B_SELECT			(1 << 30)
+#define SDVO_STALL_SELECT			(1 << 29)
+#define SDVO_INTERRUPT_ENABLE			(1 << 26)
+/* Programmed value is multiplier - 1, up to 5x.  alv, gdg only */
+#define SDVO_PORT_MULTIPLY_MASK			(7 << 23)
+#define SDVO_PHASE_SELECT_MASK			(15 << 23)
+#define SDVO_PHASE_SELECT_DEFAULT		(6 << 23)
+#define SDVO_CLOCK_OUTPUT_INVERT		(1 << 18)
+#define SDVOC_GANG_MODE				(1 << 16)
+#define SDVO_BORDER_ENABLE			(1 << 7)
+#define SDVO_DETECTED				(1 << 2)
+/* Bits to be preserved when writing */
+#define SDVO_PRESERVE_MASK			(1 << 17)
+
 #define I830_HTOTAL_MASK 	0xfff0000
 #define I830_HACTIVE_MASK	0x7ff
 
diff --git a/src/i830.h b/src/i830.h
index babbe08..a631258 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -202,7 +202,7 @@ struct _I830OutputRec {
    I2CBusPtr pI2CBus;
    I2CBusPtr pDDCBus;
    struct _I830DVODriver *i2c_drv;
-   struct _I830SDVODriver *sdvo_drv;
+   I830SDVOPtr sdvo_drv;
 };
 
 typedef struct _I830Rec {
@@ -580,6 +580,10 @@ extern Bool I830RandRInit(ScreenPtr pScr
 extern Bool I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg,
 			char *name);
 
+/* i830_sdvo.c */
+extern I830SDVOPtr I830SDVOInit(I2CBusPtr b);
+extern Bool I830I2CDetectSDVOController(ScrnInfoPtr pScrn, int output_index);
+
 /*
  * 12288 is set as the maximum, chosen because it is enough for
  * 1920x1440 at 32bpp with a 2048 pixel line pitch with some to spare.
diff --git a/src/i830_display.c b/src/i830_display.c
index 8eebfca..fd3c352 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -255,8 +255,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
     int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
     CARD32 dpll = 0, fp = 0, temp;
     CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr;
-    CARD32 pipesrc, dspsize, adpa;
-    Bool ok;
+    CARD32 pipesrc, dspsize, adpa, sdvoc = 0;
+    Bool ok, is_sdvo;
     int refclk, pixel_clock;
     int outputs;
 
@@ -283,6 +283,14 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 		   "Can't support LVDS on pipe A\n");
 	return FALSE;
     }
+    if ((outputs & PIPE_DFP_ACTIVE) || (outputs & PIPE_DFP2_ACTIVE)) {
+	/* We'll change how we control outputs soon, but to get the SDVO code up
+	 * and running, just check for these two possibilities.
+	 */
+	is_sdvo = TRUE;
+    } else {
+	is_sdvo = FALSE;
+    }
 
     htot = (pMode->CrtcHDisplay - 1) | ((pMode->CrtcHTotal - 1) << 16);
     hblank = (pMode->CrtcHBlankStart - 1) | ((pMode->CrtcHBlankEnd - 1) << 16);
@@ -378,6 +386,19 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 	dpll |= PLL_REF_INPUT_DREFCLK;
     dpll |= SDV0_DEFAULT_MULTIPLIER;
 
+    if (is_sdvo) {
+	dpll |= DPLL_DVO_HIGH_SPEED;
+
+	ErrorF("DVOB: %08x\nDVOC: %08x\n", (int)INREG(SDVOB), (int)INREG(SDVOC));
+
+	sdvoc = INREG(SDVOC) & SDVO_PRESERVE_MASK;
+	sdvoc |= SDVO_ENABLE;
+	if (pipe == 1)
+	    sdvoc |= SDVO_PIPE_B_SELECT;
+	sdvoc |= SDVO_PHASE_SELECT_DEFAULT;
+	sdvoc |= SDVO_BORDER_ENABLE;
+    }
+
     fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
 
 #if 1
@@ -532,6 +553,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 
     if (outputs & PIPE_CRT_ACTIVE)
 	OUTREG(ADPA, adpa);
+    if (is_sdvo)
+	OUTREG(SDVOC, sdvoc);
 
     return TRUE;
 }
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 8930db0..591605a 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -1338,13 +1338,15 @@ static void
 I830SetupOutputBusses(ScrnInfoPtr pScrn)
 {
    I830Ptr pI830 = I830PTR(pScrn);
+   int i = 0;
+   Bool ret;
 
    /* everyone has at least a single analog output */
-   pI830->num_outputs = 1;
-   pI830->output[0].type = I830_OUTPUT_ANALOG;
+   pI830->output[i].type = I830_OUTPUT_ANALOG;
 
    /* setup the DDC bus for the analog output */
-   I830I2CInit(pScrn, &pI830->output[0].pDDCBus, GPIOA, "CRTDDC_A");
+   I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOA, "CRTDDC_A");
+   i++;
 
    /* need to add the output busses for each device 
     * - this function is very incomplete
@@ -1355,35 +1357,44 @@ I830SetupOutputBusses(ScrnInfoPtr pScrn)
    case PCI_CHIP_845_G:
    case PCI_CHIP_I855_GM:
    case PCI_CHIP_I865_G:
-      pI830->num_outputs = 2;
-      pI830->output[1].type = I830_OUTPUT_DVO;
-      I830I2CInit(pScrn, &pI830->output[1].pDDCBus, GPIOD, "DVODDC_D");
-      I830I2CInit(pScrn, &pI830->output[1].pI2CBus, GPIOE, "DVOI2C_E");
+      pI830->output[i].type = I830_OUTPUT_DVO;
+      I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOD, "DVODDC_D");
+      I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "DVOI2C_E");
+      i++;
       break;
    case PCI_CHIP_E7221_G:
       /* ??? */
       break;
-   case PCI_CHIP_I915_G:
    case PCI_CHIP_I915_GM:
-      pI830->num_outputs = 2;
-      pI830->output[1].type = I830_OUTPUT_LVDS;
-      I830I2CInit(pScrn, &pI830->output[1].pDDCBus, GPIOC, "LVDSDDC_C");
+   case PCI_CHIP_I945_GM:
+      pI830->output[i].type = I830_OUTPUT_LVDS;
+      I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOC, "LVDSDDC_C");
+      i++;
       break;
-#if 0
+   case PCI_CHIP_I915_G:
    case PCI_CHIP_I945_G:
-   case PCI_CHIP_I945_GM:
-      /* SDVO ports have a single control bus */
-      pI830->num_outputs = 2;
-      pI830->output[1].type = I830_OUTPUT_SDVO;
-      I830I2CInit(pScrn, &pI830->output[1].pI2CBus, GPIOE, "SDVOCTRL_E");
+      /* Set up SDVOB */
+      pI830->output[i].type = I830_OUTPUT_SDVO;
+      I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "SDVOCTRL_E");
+
+      pI830->output[i].sdvo_drv = I830SDVOInit(pI830->output[i].pI2CBus);
+      ret = I830I2CDetectSDVOController(pScrn, i);
+      if (ret == TRUE)
+	 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found sDVOB\n");
+      i++;
+
+      /* Set up SDVOC */
+      pI830->output[i].type = I830_OUTPUT_SDVO;
+      I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "SDVOCTRL_E");
 
-      pI830->output[1].sdvo_drv = I830SDVOInit(pI830->output[1].pI2CBus);
-      ret = I830I2CDetectSDVOController(pScrn, 1);
+      pI830->output[i].sdvo_drv = I830SDVOInit(pI830->output[i].pI2CBus);
+      ret = I830I2CDetectSDVOController(pScrn, i);
       if (ret == TRUE)
-	 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found sDVO\n");
+	 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found sDVOC\n");
+      i++;
       break;
-#endif
    }
+   pI830->num_outputs = i;
 }
 
 void 
@@ -1442,8 +1453,8 @@ void I830DetectMonitors(ScrnInfoPtr pScr
 	 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC DVO %d, %08lX\n", i,
 		    pI830->output[i].pDDCBus->DriverPrivate.uval);
 	 xf86PrintEDID(pI830->output[i].MonInfo);
-      
-#if 0
+
+#if 0      
 	 /* if we are on an i2C bus > 0 and we see a monitor - try to
 	  * find a controller chip
 	  */
@@ -1459,9 +1470,9 @@ void I830DetectMonitors(ScrnInfoPtr pScr
 	 }
 #endif
       break;
-#if 0
       case I830_OUTPUT_SDVO:
 	 if (pI830->output[i].sdvo_drv->found) {
+#if 0
 	    I830SDVOSetupDDC(pI830->output[i].sdvo_drv);
 
 	    pI830->output[i].MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,
@@ -1470,9 +1481,9 @@ void I830DetectMonitors(ScrnInfoPtr pScr
 	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC SDVO %d, %08X\n", i,
 		       pI830->output[i].pI2CBus->DriverPrivate.uval);
 	    xf86PrintEDID(pI830->output[i].MonInfo);
+#endif
 	 }
 	 break;
-#endif
       case I830_OUTPUT_UNUSED:
 	 break;
       default:
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
new file mode 100644
index 0000000..7f5549c
--- /dev/null
+++ b/src/i830_sdvo.c
@@ -0,0 +1,103 @@
+/**************************************************************************
+
+ Copyright 2006 Dave Airlie <airlied at linux.ie>
+ 
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#include "xf86.h"
+#include "xf86_ansic.h"
+#include "xf86_OSproc.h"
+#include "compiler.h"
+#include "i830.h"
+
+/* SDVO support for i9xx chipsets */
+static Bool sReadByte(I830SDVOPtr s, int addr, unsigned char *ch)
+{
+    if (!xf86I2CReadByte(&s->d, addr, ch)) {
+	xf86DrvMsg(s->d.pI2CBus->scrnIndex, X_ERROR,
+		   "Unable to read from %s Slave %d.\n", s->d.pI2CBus->BusName,
+		   s->d.SlaveAddr);
+	return FALSE;
+    }
+    return TRUE;
+}
+
+#if 0
+static Bool sWriteByte(I830SDVOPtr s, int addr, unsigned char ch)
+{
+    if (!xf86I2CWriteByte(&s->d, addr, ch)) {
+	xf86DrvMsg(s->d.pI2CBus->scrnIndex, X_ERROR,
+		   "Unable to write to %s Slave %d.\n", s->d.pI2CBus->BusName,
+		   s->d.SlaveAddr);
+	return FALSE;
+    }
+    return TRUE;
+}
+#endif
+
+I830SDVOPtr
+I830SDVOInit(I2CBusPtr b)
+{
+    I830SDVOPtr sdvo;
+
+    sdvo = xcalloc(1, sizeof(I830SDVORec));
+    if (sdvo == NULL)
+	return NULL;
+
+    sdvo->d.DevName = "SDVO Controller";
+    sdvo->d.SlaveAddr = 0x39 << 1;
+    sdvo->d.pI2CBus = b;
+    sdvo->d.StartTimeout = b->StartTimeout;
+    sdvo->d.BitTimeout = b->BitTimeout;
+    sdvo->d.AcknTimeout = b->AcknTimeout;
+    sdvo->d.ByteTimeout = b->ByteTimeout;
+    sdvo->d.DriverPrivate.ptr = sdvo;
+
+    if (!xf86I2CDevInit(&sdvo->d))
+	goto out;
+    return sdvo;
+
+out:
+    xfree(sdvo);
+    return NULL;
+}
+
+Bool
+I830I2CDetectSDVOController(ScrnInfoPtr pScrn, int output_index)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    unsigned char ch[64];
+    int i;
+    I830SDVOPtr sdvo = pI830->output[output_index].sdvo_drv;
+
+    if (sdvo == NULL)
+	return FALSE;
+
+    for (i=0; i<0x40; i++) {
+	if (!sReadByte(sdvo, i, &ch[i]))
+	    return FALSE;
+    }
+
+    pI830->output[output_index].sdvo_drv->found = 1;
+
+    return TRUE;
+}



More information about the xorg-commit mailing list