diff options
-rw-r--r-- | src/i830_sdvo.c | 81 | ||||
-rw-r--r-- | src/i830_sdvo_regs.h | 8 |
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 |