diff options
author | Eric Anholt <eric@anholt.net> | 2007-03-13 16:55:38 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2007-03-13 16:59:38 -0700 |
commit | 44708bdd9ebfef0328302c9a964b80deb46e57c6 (patch) | |
tree | d0006b7e5938036e4c701ac2ac0579092f809344 | |
parent | 5135b3a79f9c30ebce78c84c49846bba83607fed (diff) |
Get SDVO DPMS working on the Mac Mini by writing SDVOB and SDVOC together.
Also, add code for setting the encoder power state like the BIOS does, but this
doesn't appear to work. We do much more than the BIOS does in powering things
down, so perhaps that's interfering somehow.
-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 |