[Intel-gfx] [Resend][PATCH 2/3] drm/i915: enable sdvo lvds scaling function.
Ian Romanick
idr at freedesktop.org
Tue Jun 30 20:05:02 CEST 2009
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
ling.ma at intel.com wrote:
> Currently we implemented basic sdvo lvds function,
> But except for sdvo lvds fixed mode, we can not switch
> to other modes, otherwise display get black. The patch
> handle three operations to enable sdvo lvds. At first
> duplicate sdvo fixed mode for adjustment, then according
> to fixed mode line valid all modes, at last adjust input
> mode to fit our requirement.
>
> Acked by Li Peng <peng.li at linux.intel.com>
>
> Signed-off-by: Ma Ling <ling.ma at intel.com>
Looks good.
Reviewed-by: Ian Romanick <idr at freedesktop.org>
> ---
> drivers/gpu/drm/i915/intel_sdvo.c | 114 ++++++++++++++++++++++++++++----
> drivers/gpu/drm/i915/intel_sdvo_regs.h | 1 +
> 2 files changed, 103 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> index f034737..4f0c309 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -68,12 +68,23 @@ struct intel_sdvo_priv {
> * This is set if we treat the device as HDMI, instead of DVI.
> */
> bool is_hdmi;
> +
> /**
> * This is set if we detect output of sdvo device as LVDS.
> */
> bool is_lvds;
>
> /**
> + * This is sdvo flags for input timing.
> + */
> + uint8_t sdvo_flags;
> +
> + /**
> + * This is sdvo fixed pannel mode pointer
> + */
> + struct drm_display_mode *sdvo_lvds_fixed_mode;
> +
> + /**
> * Returned SDTV resolutions allowed for the current format, if the
> * device reported it.
> */
> @@ -592,6 +603,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
> uint16_t height)
> {
> struct intel_sdvo_preferred_input_timing_args args;
> + struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
> uint8_t status;
>
> memset(&args, 0, sizeof(args));
> @@ -599,7 +611,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
> args.width = width;
> args.height = height;
> args.interlace = 0;
> - args.scaled = 0;
> +
> + if (sdvo_priv->is_lvds &&
> + (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width ||
> + sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height))
> + args.scaled = 1;
> +
> intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
> &args, sizeof(args));
> status = intel_sdvo_read_response(output, NULL, 0);
> @@ -944,12 +961,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
> struct intel_output *output = enc_to_intel_output(encoder);
> struct intel_sdvo_priv *dev_priv = 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 *= intel_sdvo_get_pixel_multiplier(mode);
> - } else {
> + if (dev_priv->is_tv) {
> struct intel_sdvo_dtd output_dtd;
> bool success;
>
> @@ -980,6 +992,47 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
> intel_sdvo_get_preferred_input_timing(output,
> &input_dtd);
> intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
> + dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
> +
> + drm_mode_set_crtcinfo(adjusted_mode, 0);
> +
> + mode->clock = adjusted_mode->clock;
> +
> + adjusted_mode->clock *=
> + intel_sdvo_get_pixel_multiplier(mode);
> + } else {
> + return false;
> + }
> + } else if (dev_priv->is_lvds) {
> + struct intel_sdvo_dtd output_dtd;
> + bool success;
> +
> + drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0);
> + /* Set output timings */
> + intel_sdvo_get_dtd_from_mode(&output_dtd,
> + dev_priv->sdvo_lvds_fixed_mode);
> +
> + intel_sdvo_set_target_output(output,
> + dev_priv->controlled_output);
> + intel_sdvo_set_output_timing(output, &output_dtd);
> +
> + /* Set the input timing to the screen. Assume always input 0. */
> + intel_sdvo_set_target_input(output, true, false);
> +
> +
> + success = intel_sdvo_create_preferred_input_timing(
> + output,
> + mode->clock / 10,
> + mode->hdisplay,
> + mode->vdisplay);
> +
> + if (success) {
> + struct intel_sdvo_dtd input_dtd;
> +
> + intel_sdvo_get_preferred_input_timing(output,
> + &input_dtd);
> + intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
> + dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
>
> drm_mode_set_crtcinfo(adjusted_mode, 0);
>
> @@ -990,6 +1043,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
> } 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 *= intel_sdvo_get_pixel_multiplier(mode);
> }
> return true;
> }
> @@ -1033,15 +1092,16 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
>
> /* We have tried to get input timing in mode_fixup, and filled into
> adjusted_mode */
> - if (sdvo_priv->is_tv)
> + if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
> intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
> - else
> + input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags;
> + } else
> intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
>
> /* If it's a TV, we already set the output timing in mode_fixup.
> * Otherwise, the output timing is equal to the input timing.
> */
> - if (!sdvo_priv->is_tv) {
> + if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) {
> /* Set the output timing to the screen */
> intel_sdvo_set_target_output(output,
> sdvo_priv->controlled_output);
> @@ -1116,6 +1176,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
> sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
> }
>
> + if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL)
> + sdvox |= SDVO_STALL_SELECT;
> intel_sdvo_write_sdvox(output, sdvox);
> }
>
> @@ -1276,6 +1338,17 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector,
> if (sdvo_priv->pixel_clock_max < mode->clock)
> return MODE_CLOCK_HIGH;
>
> + if (sdvo_priv->is_lvds == true) {
> + if (sdvo_priv->sdvo_lvds_fixed_mode == NULL)
> + return MODE_PANEL;
> +
> + if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay)
> + return MODE_PANEL;
> +
> + if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay)
> + return MODE_PANEL;
> + }
> +
> return MODE_OK;
> }
>
> @@ -1549,6 +1622,8 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
> {
> struct intel_output *intel_output = to_intel_output(connector);
> struct drm_i915_private *dev_priv = connector->dev->dev_private;
> + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
> + struct drm_display_mode *newmode;
>
> /*
> * Attempt to get the mode list from DDC.
> @@ -1557,11 +1632,10 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
> */
> intel_ddc_get_modes(intel_output);
> if (list_empty(&connector->probed_modes) == false)
> - return;
> + goto end;
>
> /* Fetch modes from VBT */
> if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
> - struct drm_display_mode *newmode;
> newmode = drm_mode_duplicate(connector->dev,
> dev_priv->sdvo_lvds_vbt_mode);
> if (newmode != NULL) {
> @@ -1571,6 +1645,16 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
> drm_mode_probed_add(connector, newmode);
> }
> }
> +
> +end:
> + list_for_each_entry(newmode, &connector->probed_modes, head) {
> + if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
> + sdvo_priv->sdvo_lvds_fixed_mode =
> + drm_mode_duplicate(connector->dev, newmode);
> + break;
> + }
> + }
> +
> }
>
> static int intel_sdvo_get_modes(struct drm_connector *connector)
> @@ -1593,14 +1677,20 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
> static void intel_sdvo_destroy(struct drm_connector *connector)
> {
> struct intel_output *intel_output = to_intel_output(connector);
> + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
>
> if (intel_output->i2c_bus)
> intel_i2c_destroy(intel_output->i2c_bus);
> if (intel_output->ddc_bus)
> intel_i2c_destroy(intel_output->ddc_bus);
>
> + if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
> + drm_mode_destroy(connector->dev,
> + sdvo_priv->sdvo_lvds_fixed_mode);
> +
> drm_sysfs_connector_remove(connector);
> drm_connector_cleanup(connector);
> +
> kfree(intel_output);
> }
>
> diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h
> index 193938b..ba5cdf8 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h
> +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h
> @@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg {
> #define SDVO_HBUF_TX_ONCE (2 << 6)
> #define SDVO_HBUF_TX_VSYNC (3 << 6)
> #define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c
> +#define SDVO_NEED_TO_STALL (1 << 7)
>
> struct intel_sdvo_encode{
> u8 dvi_rev;
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkpKU8sACgkQX1gOwKyEAw+vNwCfcEpqm18Az3kdiSaunB3DXK+M
l98AnRFSXLwCIxE74NZXWlhNPs2M4pUA
=2bKp
-----END PGP SIGNATURE-----
More information about the Intel-gfx
mailing list