| From e94917dfbe1dab1819af4b23f0c7450bafb803a0 Mon Sep 17 00:00:00 2001 |
| From: Jesse Barnes <jbarnes@virtuousgeek.org> |
| Date: Tue, 14 May 2013 17:08:26 -0700 |
| Subject: drm/i915: add encoder get_config function v5 |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| We can use this for fetching encoder specific pipe_config state, like |
| mode flags, adjusted clock, etc. |
| |
| Just used for mode flags atm, so we can check the pipe config state at |
| mode set time. |
| |
| v2: get_config when checking hw state too |
| v3: fix DVO and LVDS mode flags (Ville) |
| get SDVO DTD for flag fetch (Ville) |
| v4: use input timings (Ville) |
| correct command used (Ville) |
| remove gen4 check (Ville) |
| v5: get DDI flag config too |
| |
| Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> |
| Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> (v4) |
| Tested-by: Paulo Zanoni <przanoni@gmail.com> (the new hsw ddi stuff) |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit 045ac3b5629d9711531a408e92f9074db6afe7ce) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/intel_crt.c | 23 +++++++++++++++++++ |
| drivers/gpu/drm/i915/intel_ddi.c | 23 +++++++++++++++++++ |
| drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++++-- |
| drivers/gpu/drm/i915/intel_dp.c | 23 +++++++++++++++++++ |
| drivers/gpu/drm/i915/intel_drv.h | 4 +++ |
| drivers/gpu/drm/i915/intel_dvo.c | 21 +++++++++++++++++ |
| drivers/gpu/drm/i915/intel_hdmi.c | 23 +++++++++++++++++++ |
| drivers/gpu/drm/i915/intel_lvds.c | 26 +++++++++++++++++++++ |
| drivers/gpu/drm/i915/intel_sdvo.c | 42 +++++++++++++++++++++++++++++++++++ |
| 9 files changed, 202 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/gpu/drm/i915/intel_crt.c |
| +++ b/drivers/gpu/drm/i915/intel_crt.c |
| @@ -84,6 +84,28 @@ static bool intel_crt_get_hw_state(struc |
| return true; |
| } |
| |
| +static void intel_crt_get_config(struct intel_encoder *encoder, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
| + struct intel_crt *crt = intel_encoder_to_crt(encoder); |
| + u32 tmp, flags = 0; |
| + |
| + tmp = I915_READ(crt->adpa_reg); |
| + |
| + if (tmp & ADPA_HSYNC_ACTIVE_HIGH) |
| + flags |= DRM_MODE_FLAG_PHSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NHSYNC; |
| + |
| + if (tmp & ADPA_VSYNC_ACTIVE_HIGH) |
| + flags |= DRM_MODE_FLAG_PVSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NVSYNC; |
| + |
| + pipe_config->adjusted_mode.flags |= flags; |
| +} |
| + |
| /* Note: The caller is required to filter out dpms modes not supported by the |
| * platform. */ |
| static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) |
| @@ -787,6 +809,7 @@ void intel_crt_init(struct drm_device *d |
| crt->base.compute_config = intel_crt_compute_config; |
| crt->base.disable = intel_disable_crt; |
| crt->base.enable = intel_enable_crt; |
| + crt->base.get_config = intel_crt_get_config; |
| if (I915_HAS_HOTPLUG(dev)) |
| crt->base.hpd_pin = HPD_CRT; |
| if (HAS_DDI(dev)) |
| --- a/drivers/gpu/drm/i915/intel_ddi.c |
| +++ b/drivers/gpu/drm/i915/intel_ddi.c |
| @@ -1266,6 +1266,28 @@ static void intel_ddi_hot_plug(struct in |
| intel_dp_check_link_status(intel_dp); |
| } |
| |
| +static void intel_ddi_get_config(struct intel_encoder *encoder, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
| + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
| + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; |
| + u32 temp, flags = 0; |
| + |
| + temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); |
| + if (temp & TRANS_DDI_PHSYNC) |
| + flags |= DRM_MODE_FLAG_PHSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NHSYNC; |
| + if (temp & TRANS_DDI_PVSYNC) |
| + flags |= DRM_MODE_FLAG_PVSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NVSYNC; |
| + |
| + pipe_config->adjusted_mode.flags |= flags; |
| + pipe_config->pixel_multiplier = 1; |
| +} |
| + |
| static void intel_ddi_destroy(struct drm_encoder *encoder) |
| { |
| /* HDMI has nothing special to destroy, so we can go with this. */ |
| @@ -1325,6 +1347,7 @@ void intel_ddi_init(struct drm_device *d |
| intel_encoder->disable = intel_disable_ddi; |
| intel_encoder->post_disable = intel_ddi_post_disable; |
| intel_encoder->get_hw_state = intel_ddi_get_hw_state; |
| + intel_encoder->get_config = intel_ddi_get_config; |
| |
| intel_dig_port->port = port; |
| intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & |
| --- a/drivers/gpu/drm/i915/intel_display.c |
| +++ b/drivers/gpu/drm/i915/intel_display.c |
| @@ -8071,6 +8071,15 @@ intel_pipe_config_compare(struct drm_dev |
| PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, |
| DRM_MODE_FLAG_INTERLACE); |
| |
| + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, |
| + DRM_MODE_FLAG_PHSYNC); |
| + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, |
| + DRM_MODE_FLAG_NHSYNC); |
| + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, |
| + DRM_MODE_FLAG_PVSYNC); |
| + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, |
| + DRM_MODE_FLAG_NVSYNC); |
| + |
| PIPE_CONF_CHECK_I(requested_mode.hdisplay); |
| PIPE_CONF_CHECK_I(requested_mode.vdisplay); |
| |
| @@ -8163,6 +8172,8 @@ intel_modeset_check_state(struct drm_dev |
| bool enabled = false; |
| bool active = false; |
| |
| + memset(&pipe_config, 0, sizeof(pipe_config)); |
| + |
| DRM_DEBUG_KMS("[CRTC:%d]\n", |
| crtc->base.base.id); |
| |
| @@ -8176,6 +8187,8 @@ intel_modeset_check_state(struct drm_dev |
| enabled = true; |
| if (encoder->connectors_active) |
| active = true; |
| + if (encoder->get_config) |
| + encoder->get_config(encoder, &pipe_config); |
| } |
| WARN(active != crtc->active, |
| "crtc's computed active state doesn't match tracked active state " |
| @@ -8184,7 +8197,6 @@ intel_modeset_check_state(struct drm_dev |
| "crtc's computed enabled state doesn't match tracked enabled state " |
| "(expected %i, found %i)\n", enabled, crtc->base.enabled); |
| |
| - memset(&pipe_config, 0, sizeof(pipe_config)); |
| pipe_config.cpu_transcoder = crtc->config.cpu_transcoder; |
| active = dev_priv->display.get_pipe_config(crtc, |
| &pipe_config); |
| @@ -9638,8 +9650,10 @@ setup_pipes: |
| pipe = 0; |
| |
| if (encoder->get_hw_state(encoder, &pipe)) { |
| - encoder->base.crtc = |
| - dev_priv->pipe_to_crtc_mapping[pipe]; |
| + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
| + encoder->base.crtc = &crtc->base; |
| + if (encoder->get_config) |
| + encoder->get_config(encoder, &crtc->config); |
| } else { |
| encoder->base.crtc = NULL; |
| } |
| --- a/drivers/gpu/drm/i915/intel_dp.c |
| +++ b/drivers/gpu/drm/i915/intel_dp.c |
| @@ -1366,6 +1366,28 @@ static bool intel_dp_get_hw_state(struct |
| return true; |
| } |
| |
| +static void intel_dp_get_config(struct intel_encoder *encoder, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
| + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
| + u32 tmp, flags = 0; |
| + |
| + tmp = I915_READ(intel_dp->output_reg); |
| + |
| + if (tmp & DP_SYNC_HS_HIGH) |
| + flags |= DRM_MODE_FLAG_PHSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NHSYNC; |
| + |
| + if (tmp & DP_SYNC_VS_HIGH) |
| + flags |= DRM_MODE_FLAG_PVSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NVSYNC; |
| + |
| + pipe_config->adjusted_mode.flags |= flags; |
| +} |
| + |
| static void intel_disable_dp(struct intel_encoder *encoder) |
| { |
| struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); |
| @@ -3220,6 +3242,7 @@ intel_dp_init(struct drm_device *dev, in |
| intel_encoder->disable = intel_disable_dp; |
| intel_encoder->post_disable = intel_post_disable_dp; |
| intel_encoder->get_hw_state = intel_dp_get_hw_state; |
| + intel_encoder->get_config = intel_dp_get_config; |
| if (IS_VALLEYVIEW(dev)) |
| intel_encoder->pre_pll_enable = intel_dp_pre_pll_enable; |
| |
| --- a/drivers/gpu/drm/i915/intel_drv.h |
| +++ b/drivers/gpu/drm/i915/intel_drv.h |
| @@ -139,6 +139,10 @@ struct intel_encoder { |
| * the encoder is active. If the encoder is enabled it also set the pipe |
| * it is connected to in the pipe parameter. */ |
| bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); |
| + /* Reconstructs the equivalent mode flags for the current hardware |
| + * state. */ |
| + void (*get_config)(struct intel_encoder *, |
| + struct intel_crtc_config *pipe_config); |
| int crtc_mask; |
| enum hpd_pin hpd_pin; |
| }; |
| --- a/drivers/gpu/drm/i915/intel_dvo.c |
| +++ b/drivers/gpu/drm/i915/intel_dvo.c |
| @@ -136,6 +136,26 @@ static bool intel_dvo_get_hw_state(struc |
| return true; |
| } |
| |
| +static void intel_dvo_get_config(struct intel_encoder *encoder, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
| + struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base); |
| + u32 tmp, flags = 0; |
| + |
| + tmp = I915_READ(intel_dvo->dev.dvo_reg); |
| + if (tmp & DVO_HSYNC_ACTIVE_HIGH) |
| + flags |= DRM_MODE_FLAG_PHSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NHSYNC; |
| + if (tmp & DVO_VSYNC_ACTIVE_HIGH) |
| + flags |= DRM_MODE_FLAG_PVSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NVSYNC; |
| + |
| + pipe_config->adjusted_mode.flags |= flags; |
| +} |
| + |
| static void intel_disable_dvo(struct intel_encoder *encoder) |
| { |
| struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
| @@ -447,6 +467,7 @@ void intel_dvo_init(struct drm_device *d |
| intel_encoder->disable = intel_disable_dvo; |
| intel_encoder->enable = intel_enable_dvo; |
| intel_encoder->get_hw_state = intel_dvo_get_hw_state; |
| + intel_encoder->get_config = intel_dvo_get_config; |
| intel_connector->get_hw_state = intel_dvo_connector_get_hw_state; |
| |
| /* Now, try to find a controller */ |
| --- a/drivers/gpu/drm/i915/intel_hdmi.c |
| +++ b/drivers/gpu/drm/i915/intel_hdmi.c |
| @@ -658,6 +658,28 @@ static bool intel_hdmi_get_hw_state(stru |
| return true; |
| } |
| |
| +static void intel_hdmi_get_config(struct intel_encoder *encoder, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
| + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
| + u32 tmp, flags = 0; |
| + |
| + tmp = I915_READ(intel_hdmi->hdmi_reg); |
| + |
| + if (tmp & SDVO_HSYNC_ACTIVE_HIGH) |
| + flags |= DRM_MODE_FLAG_PHSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NHSYNC; |
| + |
| + if (tmp & SDVO_VSYNC_ACTIVE_HIGH) |
| + flags |= DRM_MODE_FLAG_PVSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NVSYNC; |
| + |
| + pipe_config->adjusted_mode.flags |= flags; |
| +} |
| + |
| static void intel_enable_hdmi(struct intel_encoder *encoder) |
| { |
| struct drm_device *dev = encoder->base.dev; |
| @@ -1216,6 +1238,7 @@ void intel_hdmi_init(struct drm_device * |
| intel_encoder->enable = intel_enable_hdmi; |
| intel_encoder->disable = intel_disable_hdmi; |
| intel_encoder->get_hw_state = intel_hdmi_get_hw_state; |
| + intel_encoder->get_config = intel_hdmi_get_config; |
| if (IS_VALLEYVIEW(dev)) { |
| intel_encoder->pre_enable = intel_hdmi_pre_enable; |
| intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable; |
| --- a/drivers/gpu/drm/i915/intel_lvds.c |
| +++ b/drivers/gpu/drm/i915/intel_lvds.c |
| @@ -86,6 +86,31 @@ static bool intel_lvds_get_hw_state(stru |
| return true; |
| } |
| |
| +static void intel_lvds_get_config(struct intel_encoder *encoder, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct drm_device *dev = encoder->base.dev; |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + u32 lvds_reg, tmp, flags = 0; |
| + |
| + if (HAS_PCH_SPLIT(dev)) |
| + lvds_reg = PCH_LVDS; |
| + else |
| + lvds_reg = LVDS; |
| + |
| + tmp = I915_READ(lvds_reg); |
| + if (tmp & LVDS_HSYNC_POLARITY) |
| + flags |= DRM_MODE_FLAG_NHSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_PHSYNC; |
| + if (tmp & LVDS_VSYNC_POLARITY) |
| + flags |= DRM_MODE_FLAG_NVSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_PVSYNC; |
| + |
| + pipe_config->adjusted_mode.flags |= flags; |
| +} |
| + |
| /* The LVDS pin pair needs to be on before the DPLLs are enabled. |
| * This is an exception to the general rule that mode_set doesn't turn |
| * things on. |
| @@ -980,6 +1005,7 @@ bool intel_lvds_init(struct drm_device * |
| intel_encoder->compute_config = intel_lvds_compute_config; |
| intel_encoder->disable = intel_disable_lvds; |
| intel_encoder->get_hw_state = intel_lvds_get_hw_state; |
| + intel_encoder->get_config = intel_lvds_get_config; |
| intel_connector->get_hw_state = intel_connector_get_hw_state; |
| |
| intel_connector_attach_encoder(intel_connector, intel_encoder); |
| --- a/drivers/gpu/drm/i915/intel_sdvo.c |
| +++ b/drivers/gpu/drm/i915/intel_sdvo.c |
| @@ -712,6 +712,13 @@ static bool intel_sdvo_set_timing(struct |
| intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); |
| } |
| |
| +static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd, |
| + struct intel_sdvo_dtd *dtd) |
| +{ |
| + return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) && |
| + intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); |
| +} |
| + |
| static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo, |
| struct intel_sdvo_dtd *dtd) |
| { |
| @@ -726,6 +733,13 @@ static bool intel_sdvo_set_output_timing |
| SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); |
| } |
| |
| +static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo, |
| + struct intel_sdvo_dtd *dtd) |
| +{ |
| + return intel_sdvo_get_timing(intel_sdvo, |
| + SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); |
| +} |
| + |
| static bool |
| intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, |
| uint16_t clock, |
| @@ -1295,6 +1309,33 @@ static bool intel_sdvo_get_hw_state(stru |
| return true; |
| } |
| |
| +static void intel_sdvo_get_config(struct intel_encoder *encoder, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); |
| + struct intel_sdvo_dtd dtd; |
| + u32 flags = 0; |
| + bool ret; |
| + |
| + ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd); |
| + if (!ret) { |
| + DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n"); |
| + return; |
| + } |
| + |
| + if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) |
| + flags |= DRM_MODE_FLAG_PHSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NHSYNC; |
| + |
| + if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) |
| + flags |= DRM_MODE_FLAG_PVSYNC; |
| + else |
| + flags |= DRM_MODE_FLAG_NVSYNC; |
| + |
| + pipe_config->adjusted_mode.flags |= flags; |
| +} |
| + |
| static void intel_disable_sdvo(struct intel_encoder *encoder) |
| { |
| struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
| @@ -2821,6 +2862,7 @@ bool intel_sdvo_init(struct drm_device * |
| intel_encoder->mode_set = intel_sdvo_mode_set; |
| intel_encoder->enable = intel_enable_sdvo; |
| intel_encoder->get_hw_state = intel_sdvo_get_hw_state; |
| + intel_encoder->get_config = intel_sdvo_get_config; |
| |
| /* In default case sdvo lvds is false */ |
| if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) |