diff options
-rw-r--r-- | src/i830_sdvo.c | 93 | ||||
-rw-r--r-- | src/i830_sdvo_regs.h | 2 |
2 files changed, 83 insertions, 12 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index acfe5999..8f3193b1 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -95,6 +95,11 @@ struct i830_sdvo_priv { * This is set if we detect output of sdvo device as LVDS. */ Bool is_lvds; + DisplayModePtr sdvo_lvds_fixed_mode; + /** + *This is set if output is LVDS or TV. + */ + uint8_t sdvo_flags; /** * Returned SDTV resolutions allowed for the current format, if the @@ -614,6 +619,8 @@ static Bool i830_sdvo_create_preferred_input_timing(xf86OutputPtr output, uint16_t clock, uint16_t width, uint16_t height) { + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; struct i830_sdvo_preferred_input_timing_args args; uint8_t status; @@ -622,7 +629,11 @@ i830_sdvo_create_preferred_input_timing(xf86OutputPtr output, uint16_t clock, args.width = width; args.height = height; args.interlace = 0; - args.scaled = 0; + if (dev_priv->is_lvds && + (dev_priv->sdvo_lvds_fixed_mode->HDisplay != width || + (dev_priv->sdvo_lvds_fixed_mode->VDisplay != height))) + args.scaled = 1; + i830_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, &args, sizeof(args)); status = i830_sdvo_read_response(output, NULL, 0); @@ -1012,12 +1023,7 @@ i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, I830OutputPrivatePtr intel_output = output->driver_private; struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; - if (!dev_priv->is_tv) { - /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO - * device will be told of the multiplier during mode_set. - */ - adjusted_mode->Clock *= i830_sdvo_get_pixel_multiplier(mode); - } else { + if (dev_priv->is_tv) { struct i830_sdvo_dtd output_dtd; Bool success; @@ -1048,6 +1054,7 @@ i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, i830_sdvo_get_preferred_input_timing(output, &input_dtd); i830_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; xf86SetModeCrtc(adjusted_mode, 0); @@ -1063,7 +1070,47 @@ i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, } else { return FALSE; } - } + } else if (dev_priv->is_lvds) { + struct i830_sdvo_dtd output_dtd; + Bool success; + + /* Set output timings */ + i830_sdvo_get_dtd_from_mode(&output_dtd, + dev_priv->sdvo_lvds_fixed_mode); + i830_sdvo_set_target_output(output, dev_priv->controlled_output); + i830_sdvo_set_output_timing(output, &output_dtd); + + /* Set the input timing to the screen. Assume always input 0. */ + i830_sdvo_set_target_input(output, TRUE, FALSE); + + + success = i830_sdvo_create_preferred_input_timing(output, + mode->Clock / 10, + mode->HDisplay, + mode->VDisplay); + if (success) { + struct i830_sdvo_dtd input_dtd; + + i830_sdvo_get_preferred_input_timing(output, &input_dtd); + + i830_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + + xf86SetModeCrtc(adjusted_mode, 0); + + /* adjust origin mode's clock for current input, + for correct pixel mulitiplier setting. */ + mode->Clock = adjusted_mode->Clock; + + /* Clock range is required to be in 100-200Mhz */ + adjusted_mode->Clock *= i830_sdvo_get_pixel_multiplier(mode); + } else + return FALSE; + } else + /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO + * device will be told of the multiplier during mode_set. + */ + adjusted_mode->Clock *= i830_sdvo_get_pixel_multiplier(mode); return TRUE; } @@ -1107,9 +1154,10 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode, /* We have tried to get input timing in mode_fixup, and filled into adjusted_mode */ - if (dev_priv->is_tv) + if (dev_priv->is_tv || dev_priv->is_lvds) { i830_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); - else + input_dtd.part2.sdvo_flags = dev_priv->sdvo_flags; + } else i830_sdvo_get_dtd_from_mode(&input_dtd, mode); /* If it's a TV, we already set the output timing in mode_fixup. @@ -1122,7 +1170,7 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode, if (dev_priv->is_tv) i830_sdvo_set_tv_format(output); - if (!dev_priv->is_tv) { + if (!dev_priv->is_tv && !dev_priv->is_lvds) { /* Set the output timing to the screen */ i830_sdvo_set_output_timing(output, &input_dtd); } @@ -1185,6 +1233,8 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode, } else { sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } + if (dev_priv->sdvo_flags & SDVO_STALL_FLAG) + sdvox |= SDVO_STALL_SELECT; i830_sdvo_write_sdvox(output, sdvox); @@ -1343,6 +1393,16 @@ i830_sdvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) if (dev_priv->pixel_clock_max < pMode->Clock) return MODE_CLOCK_HIGH; + if (dev_priv->is_lvds) { + if (dev_priv->sdvo_lvds_fixed_mode == NULL) + return MODE_PANEL; + + if (pMode->HDisplay > dev_priv->sdvo_lvds_fixed_mode->HDisplay) + return MODE_PANEL; + + if (pMode->VDisplay > dev_priv->sdvo_lvds_fixed_mode->VDisplay) + return MODE_PANEL; + } return MODE_OK; } @@ -1556,6 +1616,8 @@ i830_sdvo_check_hdmi_encode (xf86OutputPtr output) /* This function will try to fetch native modes for sdvo lvds output*/ static DisplayModePtr i830_sdvo_lvds_fetch_modes(xf86OutputPtr output) { + I830OutputPrivatePtr intel_output =output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; I830Ptr pI830 = I830PTR(output->scrn); DisplayModePtr modes; @@ -1573,8 +1635,11 @@ static DisplayModePtr i830_sdvo_lvds_fetch_modes(xf86OutputPtr output) end: /* Guarantee the the first preferred mode is chosen by xserver */ - if (modes != NULL) + if (modes != NULL) { + dev_priv->sdvo_lvds_fixed_mode = xf86DuplicateMode(modes); modes->type |= (M_T_DRIVER | M_T_PREFERRED); + xf86SetModeCrtc(dev_priv->sdvo_lvds_fixed_mode, 0); + } return modes; } @@ -1958,6 +2023,10 @@ i830_sdvo_destroy (xf86OutputPtr output) xfree(randr_output->name); } + if (dev_priv->sdvo_lvds_fixed_mode) + xf86DeleteMode(&dev_priv->sdvo_lvds_fixed_mode, + dev_priv->sdvo_lvds_fixed_mode); + xfree (intel_output); } } diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h index ab383550..9fb99b61 100644 --- a/src/i830_sdvo_regs.h +++ b/src/i830_sdvo_regs.h @@ -722,3 +722,5 @@ struct i830_sdvo_encode{ uint8_t dvi_rev; uint8_t hdmi_rev; } __attribute__ ((packed)); + +#define SDVO_STALL_FLAG (1 << 7) |