summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/i830_sdvo.c81
-rw-r--r--src/i830_sdvo_regs.h8
2 files changed, 78 insertions, 11 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index cd0b115a..fb6a7c88 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -79,6 +79,25 @@ struct i830_sdvo_priv {
/** @} */
};
+/**
+ * Writes the SDVOB or SDVOC with the given value, but always writes both
+ * SDVOB and SDVOC to work around apparent hardware issues (according to
+ * comments in the BIOS).
+ */
+static void i830_sdvo_write_sdvox(xf86OutputPtr output, CARD32 val)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830OutputPrivatePtr intel_output = output->driver_private;
+ struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ if (dev_priv->output_device == SDVOC)
+ OUTREG(SDVOB, INREG(SDVOB));
+ OUTREG(dev_priv->output_device, val);
+ if (dev_priv->output_device == SDVOB)
+ OUTREG(SDVOC, INREG(SDVOC));
+}
+
/** Read a single byte from the given address on the SDVO device. */
static Bool i830_sdvo_read_byte(xf86OutputPtr output, int addr,
unsigned char *ch)
@@ -163,6 +182,9 @@ const static struct _sdvo_cmd_name {
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODER_POWER_STATE),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
};
@@ -346,6 +368,34 @@ i830_sdvo_set_active_outputs(xf86OutputPtr output,
return (status == SDVO_CMD_STATUS_SUCCESS);
}
+static Bool
+i830_sdvo_set_encoder_power_state(xf86OutputPtr output, int mode)
+{
+ CARD8 status;
+ CARD8 state;
+
+ switch (mode) {
+ case DPMSModeOn:
+ state = SDVO_ENCODER_STATE_ON;
+ break;
+ case DPMSModeStandby:
+ state = SDVO_ENCODER_STATE_STANDBY;
+ break;
+ case DPMSModeSuspend:
+ state = SDVO_ENCODER_STATE_SUSPEND;
+ break;
+ case DPMSModeOff:
+ state = SDVO_ENCODER_STATE_OFF;
+ break;
+ }
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state,
+ sizeof(state));
+ status = i830_sdvo_read_response(output, NULL, 0);
+
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
/**
* Returns the pixel clock range limits of the current target input in kHz.
*/
@@ -669,7 +719,7 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
}
- OUTREG(dev_priv->output_device, sdvox);
+ i830_sdvo_write_sdvox(output, sdvox);
}
static void
@@ -683,9 +733,16 @@ i830_sdvo_dpms(xf86OutputPtr output, int mode)
if (mode != DPMSModeOn) {
i830_sdvo_set_active_outputs(output, 0);
- temp = INREG(dev_priv->output_device);
- if ((temp & SDVO_ENABLE) != 0)
- OUTREG(dev_priv->output_device, temp & ~SDVO_ENABLE);
+ if (0)
+ i830_sdvo_set_encoder_power_state(output, mode);
+
+ if (mode == DPMSModeOff) {
+ temp = INREG(dev_priv->output_device);
+ if ((temp & SDVO_ENABLE) != 0) {
+ i830_sdvo_write_sdvox(output, temp & ~SDVO_ENABLE);
+ POSTING_READ(dev_priv->output_device);
+ }
+ }
} else {
Bool input1, input2;
int i;
@@ -694,14 +751,15 @@ i830_sdvo_dpms(xf86OutputPtr output, int mode)
temp = INREG(dev_priv->output_device);
if ((temp & SDVO_ENABLE) == 0)
{
- OUTREG(dev_priv->output_device, temp | SDVO_ENABLE);
+ i830_sdvo_write_sdvox(output, temp | SDVO_ENABLE);
POSTING_READ(dev_priv->output_device);
#if 0
- /* Do it again! If we remove this below register write, or the exact
- * same one 2 lines up, the mac mini SDVO output doesn't turn on.
+ /* Do it again! If we remove this below register write, or the
+ * exact same one 2 lines up, the mac mini SDVO output doesn't
+ * turn on.
*/
- OUTREG(dev_priv->output_device,
- INREG(dev_priv->output_device) | SDVO_ENABLE);
+ i830_sdvo_write_sdvox(output, INREG(dev_priv->output_device) |
+ SDVO_ENABLE);
POSTING_READ(dev_priv->output_device);
#endif
}
@@ -717,6 +775,8 @@ i830_sdvo_dpms(xf86OutputPtr output, int mode)
SDVO_NAME(dev_priv));
}
+ if (0)
+ i830_sdvo_set_encoder_power_state(output, mode);
i830_sdvo_set_active_outputs(output, dev_priv->active_outputs);
}
}
@@ -764,7 +824,6 @@ i830_sdvo_restore(xf86OutputPtr output)
ScrnInfoPtr pScrn = output->scrn;
I830OutputPrivatePtr intel_output = output->driver_private;
struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
- I830Ptr pI830 = I830PTR(pScrn);
int o;
int i;
Bool input1, input2;
@@ -794,7 +853,7 @@ i830_sdvo_restore(xf86OutputPtr output)
i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult);
- OUTREG(dev_priv->output_device, dev_priv->save_SDVOX);
+ i830_sdvo_write_sdvox(output, dev_priv->save_SDVOX);
if (dev_priv->save_SDVOX & SDVO_ENABLE)
{
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index 59b2aa89..437ff503 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -307,6 +307,14 @@ struct i830_sdvo_set_target_input_args {
#define SDVO_CMD_SET_TV_FORMAT 0x29
+#define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a
+#define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b
+#define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c
+# define SDVO_ENCODER_STATE_ON (1 << 0)
+# define SDVO_ENCODER_STATE_STANDBY (1 << 1)
+# define SDVO_ENCODER_STATE_SUSPEND (1 << 2)
+# define SDVO_ENCODER_STATE_OFF (1 << 3)
+
#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93
#define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a