| From 1292d9d152fd59e386e9c87110e0dc1c5a4f0e91 Mon Sep 17 00:00:00 2001 |
| From: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Date: Mon, 29 Apr 2013 21:56:12 +0200 |
| Subject: drm/i915: hw state readout support for pipe timings |
| |
| This does duplicate the logic in intel_crtc_mode_get a bit, but the |
| issue is that we also should handle interlace modes and other insanity |
| correctly. |
| |
| Hence I've opted for a sligthly more elaborate route where we first |
| read out the crtc timings for the adjusted mode, and then optionally |
| (not sure if we really need it) compute the modeline from that. |
| |
| v2: Also read out the pipe source dimensions into the requested mode. |
| |
| v3: Rebase on top of the moved cpu_transcoder. |
| |
| v4: Simplify CHECK_FLAGS logic as suggested by Chris Wilson. Also |
| properly #undef that macro again. |
| |
| Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> (v3) |
| [danvet: Use the existing mask for interlaced bits, spotted by Mika.] |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| |
| (cherry picked from commit 1bd1bd806037af04dd1d7bdd39b2b04090c10d2c) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/i915_reg.h | 1 |
| drivers/gpu/drm/i915/intel_display.c | 75 +++++++++++++++++++++++++++++++++++ |
| 2 files changed, 76 insertions(+) |
| |
| --- a/drivers/gpu/drm/i915/i915_reg.h |
| +++ b/drivers/gpu/drm/i915/i915_reg.h |
| @@ -2850,6 +2850,7 @@ |
| #define PIPECONF_INTERLACED_ILK (3 << 21) |
| #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ |
| #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ |
| +#define PIPECONF_INTERLACE_MODE_MASK (7 << 21) |
| #define PIPECONF_CXSR_DOWNCLOCK (1<<16) |
| #define PIPECONF_COLOR_RANGE_SELECT (1 << 13) |
| #define PIPECONF_BPC_MASK (0x7 << 5) |
| --- a/drivers/gpu/drm/i915/intel_display.c |
| +++ b/drivers/gpu/drm/i915/intel_display.c |
| @@ -4728,6 +4728,45 @@ static void intel_set_pipe_timings(struc |
| ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); |
| } |
| |
| +static void intel_get_pipe_timings(struct intel_crtc *crtc, |
| + struct intel_crtc_config *pipe_config) |
| +{ |
| + struct drm_device *dev = crtc->base.dev; |
| + struct drm_i915_private *dev_priv = dev->dev_private; |
| + enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; |
| + uint32_t tmp; |
| + |
| + tmp = I915_READ(HTOTAL(cpu_transcoder)); |
| + pipe_config->adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1; |
| + pipe_config->adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1; |
| + tmp = I915_READ(HBLANK(cpu_transcoder)); |
| + pipe_config->adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1; |
| + pipe_config->adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1; |
| + tmp = I915_READ(HSYNC(cpu_transcoder)); |
| + pipe_config->adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1; |
| + pipe_config->adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1; |
| + |
| + tmp = I915_READ(VTOTAL(cpu_transcoder)); |
| + pipe_config->adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1; |
| + pipe_config->adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1; |
| + tmp = I915_READ(VBLANK(cpu_transcoder)); |
| + pipe_config->adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1; |
| + pipe_config->adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1; |
| + tmp = I915_READ(VSYNC(cpu_transcoder)); |
| + pipe_config->adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1; |
| + pipe_config->adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1; |
| + |
| + if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) { |
| + pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE; |
| + pipe_config->adjusted_mode.crtc_vtotal += 1; |
| + pipe_config->adjusted_mode.crtc_vblank_end += 1; |
| + } |
| + |
| + tmp = I915_READ(PIPESRC(crtc->pipe)); |
| + pipe_config->requested_mode.vdisplay = (tmp & 0xffff) + 1; |
| + pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1; |
| +} |
| + |
| static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) |
| { |
| struct drm_device *dev = intel_crtc->base.dev; |
| @@ -4949,6 +4988,8 @@ static bool i9xx_get_pipe_config(struct |
| if (!(tmp & PIPECONF_ENABLE)) |
| return false; |
| |
| + intel_get_pipe_timings(crtc, pipe_config); |
| + |
| return true; |
| } |
| |
| @@ -5866,6 +5907,8 @@ static bool ironlake_get_pipe_config(str |
| ironlake_get_fdi_m_n_config(crtc, pipe_config); |
| } |
| |
| + intel_get_pipe_timings(crtc, pipe_config); |
| + |
| return true; |
| } |
| |
| @@ -6013,6 +6056,8 @@ static bool haswell_get_pipe_config(stru |
| ironlake_get_fdi_m_n_config(crtc, pipe_config); |
| } |
| |
| + intel_get_pipe_timings(crtc, pipe_config); |
| + |
| return true; |
| } |
| |
| @@ -7994,6 +8039,15 @@ intel_pipe_config_compare(struct intel_c |
| return false; \ |
| } |
| |
| +#define PIPE_CONF_CHECK_FLAGS(name, mask) \ |
| + if ((current_config->name ^ pipe_config->name) & (mask)) { \ |
| + DRM_ERROR("mismatch in " #name " " \ |
| + "(expected %i, found %i)\n", \ |
| + current_config->name & (mask), \ |
| + pipe_config->name & (mask)); \ |
| + return false; \ |
| + } |
| + |
| PIPE_CONF_CHECK_I(has_pch_encoder); |
| PIPE_CONF_CHECK_I(fdi_lanes); |
| PIPE_CONF_CHECK_I(fdi_m_n.gmch_m); |
| @@ -8002,7 +8056,28 @@ intel_pipe_config_compare(struct intel_c |
| PIPE_CONF_CHECK_I(fdi_m_n.link_n); |
| PIPE_CONF_CHECK_I(fdi_m_n.tu); |
| |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_end); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_start); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_end); |
| + |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vdisplay); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vtotal); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_start); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_end); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start); |
| + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end); |
| + |
| + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, |
| + DRM_MODE_FLAG_INTERLACE); |
| + |
| + PIPE_CONF_CHECK_I(requested_mode.hdisplay); |
| + PIPE_CONF_CHECK_I(requested_mode.vdisplay); |
| + |
| #undef PIPE_CONF_CHECK_I |
| +#undef PIPE_CONF_CHECK_FLAGS |
| |
| return true; |
| } |