From e29a18faaa18470f313b570fdf2d0f75c35e6cb2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 16:29:10 +0200 Subject: drm/i915: add i9xx pfit pipe asserts We can only enable the pfit if the pipe is disabled. Ensure that this is obeyed with a neat assert. Also check whether the pfit is off before enabling it - if not we've lost track of things somewhere since the pfit is only ever used by the lvds output. v2: Fix spell fail in the commit message pointed out by Ville&Jani. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f36f1baabd5..563f5052fcf 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -159,6 +159,9 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder) if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) return; + WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); + assert_pipe_disabled(dev_priv, to_intel_crtc(encoder->base.crtc)->pipe); + /* * Enable automatic panel scaling so that non-native modes * fill the screen. The panel fitter should only be -- cgit v1.2.3-70-g09d2 From d8b322474941fa565ba5c58292ccc54be92cca41 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 17:54:44 +0200 Subject: drm/i915: use pipe_config for lvds dithering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now we've relied on the bios to get this right for us. Let's try out whether our code has improved a bit, since we should dither always when the output bpp doesn't match the plane bpp. - gen5+ should be fine, since we only use the bios hint as an upgrade. - gen4 changes, since here dithering is still controlled in the lvds register. - gen2/3 has implicit dithering depeding upon whether you use 2 or 3 lvds pairs (which makes sense, since it only supports 8bpc pipe outpu configurations). - hsw doesn't support lvds. v2: Remove redudant dither setting. v3: Completly drop reliance on dev_priv->lvds_dither. v4: Enable dithering on gen2/3 only when we have a 18bpp panel, since up-dithering to a 24bpp panel is not supported by the hw. Spotted by Ville. v5: Also only enable lvds port dithering on gen4 for 18bpp modes. In practice this only excludes dithering a 10bpc plane down for a 24bpp lvds panel. Not something we truly care about. Again noticed by Ville. v6: Actually git add. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 +++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 5 +++++ drivers/gpu/drm/i915/intel_lvds.c | 15 ++++++++++----- 3 files changed, 22 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 26acc421f0c..38465f0e971 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5146,8 +5146,7 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) } static void ironlake_set_pipeconf(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode, - bool dither) + struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -5176,7 +5175,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, } val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); - if (dither) + if (intel_crtc->config.dither) val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); val &= ~PIPECONF_INTERLACE_MASK; @@ -5259,8 +5258,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc) } static void haswell_set_pipeconf(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode, - bool dither) + struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -5270,7 +5268,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc, val = I915_READ(PIPECONF(cpu_transcoder)); val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); - if (dither) + if (intel_crtc->config.dither) val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); val &= ~PIPECONF_INTERLACE_MASK_HSW; @@ -5631,7 +5629,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, bool is_lvds = false; struct intel_encoder *encoder; int ret; - bool dither, fdi_config_ok; + bool fdi_config_ok; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { @@ -5666,11 +5664,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - /* determine panel color depth */ - dither = intel_crtc->config.dither; - if (is_lvds && dev_priv->lvds_dither) - dither = true; - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); @@ -5737,7 +5730,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); - ironlake_set_pipeconf(crtc, adjusted_mode, dither); + ironlake_set_pipeconf(crtc, adjusted_mode); /* Set up the display plane register */ I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); @@ -5814,7 +5807,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, bool is_cpu_edp = false; struct intel_encoder *encoder; int ret; - bool dither; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { @@ -5850,9 +5842,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - /* determine panel color depth */ - dither = intel_crtc->config.dither; - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); @@ -5866,7 +5855,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_pch_encoder) ironlake_fdi_set_m_n(crtc); - haswell_set_pipeconf(crtc, adjusted_mode, dither); + haswell_set_pipeconf(crtc, adjusted_mode); intel_set_pipe_csc(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3595c820464..a5fe976364e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -213,6 +213,11 @@ struct intel_crtc_config { /* DP has a bunch of special case unfortunately, so mark the pipe * accordingly. */ bool has_dp_encoder; + + /* + * Enable dithering, used when the selected pipe bpp doesn't match the + * plane bpp. + */ bool dither; /* Controls for the clock computation, to override various stages. */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 563f5052fcf..84085454b10 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -136,7 +136,10 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) * special lvds dither control bit on pch-split platforms, dithering is * only controlled through the PIPECONF reg. */ if (INTEL_INFO(dev)->gen == 4) { - if (dev_priv->lvds_dither) + /* Bspec wording suggests that LVDS port dithering only exists + * for 18bpp panels. */ + if (intel_crtc->config.dither && + intel_crtc->config.pipe_bpp == 18) temp |= LVDS_ENABLE_DITHER; else temp &= ~LVDS_ENABLE_DITHER; @@ -335,7 +338,13 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", pipe_config->pipe_bpp, lvds_bpp); pipe_config->pipe_bpp = lvds_bpp; + + /* Make sure pre-965 set dither correctly for 18bpp panels. */ + if (INTEL_INFO(dev)->gen < 4 && lvds_bpp == 18) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + } + /* * We have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, @@ -470,10 +479,6 @@ out: pfit_pgm_ratios = 0; } - /* Make sure pre-965 set dither correctly */ - if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - if (pfit_control != lvds_encoder->pfit_control || pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { lvds_encoder->pfit_control = pfit_control; -- cgit v1.2.3-70-g09d2 From 2dd24552cab40ea829ba3fda890eeafd2c4816d8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 25 Apr 2013 12:55:01 -0700 Subject: drm/i915: factor out GMCH panel fitting code and use for eDP v3 This gets the panel fitter working on eDP on VLV, and should also apply to eDP panels on G4x chipsets (if we ever detect and mark an all-in-one panel as eDP anyway). A few cleanups are still possible on top of this, for example the LVDS border control could be placed in the LVDS encoder structure and updated based on the result of the panel fitter calculation. Multi-pipe fitting isn't handled correctly either if we ever get a config that wants to try the panel fitter on more than one output at a time. v2: use pipe_config for storing pfit values (Daniel) add i9xx_pfit_enable function for use by 9xx and VLV (Daniel) v3: fixup conflicts and lvds_dither check Reviewed-by: Mika Kuoppala Signed-off-by: Jesse Barnes [danvet: fix up botched conflict resolution from Jesse: - border = LVDS_BORDER_ENABLE was lost for CENTER scaling - comment about gen2/3 panel fitter scaling was lost - dev_priv->lvds_dither reintroduced.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 33 ++++++ drivers/gpu/drm/i915/intel_dp.c | 11 +- drivers/gpu/drm/i915/intel_drv.h | 6 + drivers/gpu/drm/i915/intel_lvds.c | 209 +---------------------------------- drivers/gpu/drm/i915/intel_panel.c | 191 ++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+), 209 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e83dbe5ecc..fc6f7683743 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3601,6 +3601,33 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe) } } +static void i9xx_pfit_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc_config *pipe_config = &crtc->config; + + if (!(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS))) + return; + + WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); + assert_pipe_disabled(dev_priv, crtc->pipe); + + /* + * Enable automatic panel scaling so that non-native modes + * fill the screen. The panel fitter should only be + * adjusted whilst the pipe is disabled, according to + * register description and PRM. + */ + DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", + pipe_config->pfit_control, + pipe_config->pfit_pgm_ratios); + + I915_WRITE(PFIT_PGM_RATIOS, pipe_config->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, pipe_config->pfit_control); +} + static void valleyview_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3634,6 +3661,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); + /* Enable panel fitting for eDP */ + i9xx_pfit_enable(intel_crtc); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); @@ -3670,6 +3700,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) if (encoder->pre_enable) encoder->pre_enable(encoder); + /* Enable panel fitting for LVDS */ + i9xx_pfit_enable(intel_crtc); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); if (IS_G4X(dev)) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f63973ad33c..9c834bc15ab 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -712,6 +712,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + struct intel_crtc *intel_crtc = encoder->new_crtc; struct intel_connector *intel_connector = intel_dp->attached_connector; int lane_count, clock; int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); @@ -728,9 +729,13 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { intel_fixed_panel_mode(intel_connector->panel.fixed_mode, adjusted_mode); - intel_pch_panel_fitting(dev, - intel_connector->panel.fitting_mode, - mode, adjusted_mode); + if (!HAS_PCH_SPLIT(dev)) + intel_gmch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); + else + intel_pch_panel_fitting(dev, + intel_connector->panel.fitting_mode, + mode, adjusted_mode); } /* We need to take the panel's fixed mode into account. */ target_clock = adjusted_mode->clock; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a5fe976364e..9f3f71bc2f2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -237,6 +237,9 @@ struct intel_crtc_config { int pixel_target_clock; /* Used by SDVO (and if we ever fix it, HDMI). */ unsigned pixel_multiplier; + + /* Panel fitter controls for gen2-gen4 + VLV */ + u32 pfit_control, pfit_pgm_ratios; }; struct intel_crtc { @@ -558,6 +561,9 @@ extern void intel_pch_panel_fitting(struct drm_device *dev, int fitting_mode, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); +extern void intel_gmch_panel_fitting(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode); extern void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max); extern int intel_panel_setup_backlight(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 84085454b10..7d418818c7a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -49,8 +49,6 @@ struct intel_lvds_connector { struct intel_lvds_encoder { struct intel_encoder base; - u32 pfit_control; - u32 pfit_pgm_ratios; bool is_dual_link; u32 reg; @@ -153,32 +151,6 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) I915_WRITE(lvds_encoder->reg, temp); } -static void intel_pre_enable_lvds(struct intel_encoder *encoder) -{ - struct drm_device *dev = encoder->base.dev; - struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base); - struct drm_i915_private *dev_priv = dev->dev_private; - - if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) - return; - - WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); - assert_pipe_disabled(dev_priv, to_intel_crtc(encoder->base.crtc)->pipe); - - /* - * Enable automatic panel scaling so that non-native modes - * fill the screen. The panel fitter should only be - * adjusted whilst the pipe is disabled, according to - * register description and PRM. - */ - DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - enc->pfit_control, - enc->pfit_pgm_ratios); - - I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, enc->pfit_control); -} - /** * Sets the power state for the panel. */ @@ -247,62 +219,6 @@ static int intel_lvds_mode_valid(struct drm_connector *connector, return MODE_OK; } -static void -centre_horizontally(struct drm_display_mode *mode, - int width) -{ - u32 border, sync_pos, blank_width, sync_width; - - /* keep the hsync and hblank widths constant */ - sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; - blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; - sync_pos = (blank_width - sync_width + 1) / 2; - - border = (mode->hdisplay - width + 1) / 2; - border += border & 1; /* make the border even */ - - mode->crtc_hdisplay = width; - mode->crtc_hblank_start = width + border; - mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; - - mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; - mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; -} - -static void -centre_vertically(struct drm_display_mode *mode, - int height) -{ - u32 border, sync_pos, blank_width, sync_width; - - /* keep the vsync and vblank widths constant */ - sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; - blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; - sync_pos = (blank_width - sync_width + 1) / 2; - - border = (mode->vdisplay - height + 1) / 2; - - mode->crtc_vdisplay = height; - mode->crtc_vblank_start = height + border; - mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; - - mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; - mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; -} - -static inline u32 panel_fitter_scaling(u32 source, u32 target) -{ - /* - * Floating point operation is not supported. So the FACTOR - * is defined, which can avoid the floating point computation - * when calculating the panel ratio. - */ -#define ACCURACY 12 -#define FACTOR (1 << ACCURACY) - u32 ratio = source * FACTOR / target; - return (FACTOR * ratio + FACTOR/2) / FACTOR; -} - static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct intel_crtc_config *pipe_config) { @@ -315,7 +231,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; - u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; unsigned int lvds_bpp; int pipe; @@ -338,11 +253,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", pipe_config->pipe_bpp, lvds_bpp); pipe_config->pipe_bpp = lvds_bpp; - - /* Make sure pre-965 set dither correctly for 18bpp panels. */ - if (INTEL_INFO(dev)->gen < 4 && lvds_bpp == 18) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - } /* @@ -361,18 +271,11 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, intel_connector->panel.fitting_mode, mode, adjusted_mode); return true; + } else { + intel_gmch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); } - /* Native modes don't need fitting */ - if (adjusted_mode->hdisplay == mode->hdisplay && - adjusted_mode->vdisplay == mode->vdisplay) - goto out; - - /* 965+ wants fuzzy fitting */ - if (INTEL_INFO(dev)->gen >= 4) - pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | - PFIT_FILTER_FUZZY); - /* * Enable automatic panel scaling for non-native modes so that they fill * the screen. Should be enabled before the pipe is enabled, according @@ -385,107 +288,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, drm_mode_set_crtcinfo(adjusted_mode, 0); pipe_config->timings_set = true; - switch (intel_connector->panel.fitting_mode) { - case DRM_MODE_SCALE_CENTER: - /* - * For centered modes, we have to calculate border widths & - * heights and modify the values programmed into the CRTC. - */ - centre_horizontally(adjusted_mode, mode->hdisplay); - centre_vertically(adjusted_mode, mode->vdisplay); - border = LVDS_BORDER_ENABLE; - break; - - case DRM_MODE_SCALE_ASPECT: - /* Scale but preserve the aspect ratio */ - if (INTEL_INFO(dev)->gen >= 4) { - u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; - u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; - - /* 965+ is easy, it does everything in hw */ - if (scaled_width > scaled_height) - pfit_control |= PFIT_ENABLE | PFIT_SCALING_PILLAR; - else if (scaled_width < scaled_height) - pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER; - else if (adjusted_mode->hdisplay != mode->hdisplay) - pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; - } else { - u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; - u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; - /* - * For earlier chips we have to calculate the scaling - * ratio by hand and program it into the - * PFIT_PGM_RATIO register - */ - if (scaled_width > scaled_height) { /* pillar */ - centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay); - - border = LVDS_BORDER_ENABLE; - if (mode->vdisplay != adjusted_mode->vdisplay) { - u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); - pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | - bits << PFIT_VERT_SCALE_SHIFT); - pfit_control |= (PFIT_ENABLE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - } - } else if (scaled_width < scaled_height) { /* letter */ - centre_vertically(adjusted_mode, scaled_width / mode->hdisplay); - - border = LVDS_BORDER_ENABLE; - if (mode->hdisplay != adjusted_mode->hdisplay) { - u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); - pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | - bits << PFIT_VERT_SCALE_SHIFT); - pfit_control |= (PFIT_ENABLE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - } - } else - /* Aspects match, Let hw scale both directions */ - pfit_control |= (PFIT_ENABLE | - VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - } - break; - - case DRM_MODE_SCALE_FULLSCREEN: - /* - * Full scaling, even if it changes the aspect ratio. - * Fortunately this is all done for us in hw. - */ - if (mode->vdisplay != adjusted_mode->vdisplay || - mode->hdisplay != adjusted_mode->hdisplay) { - pfit_control |= PFIT_ENABLE; - if (INTEL_INFO(dev)->gen >= 4) - pfit_control |= PFIT_SCALING_AUTO; - else - pfit_control |= (VERT_AUTO_SCALE | - VERT_INTERP_BILINEAR | - HORIZ_AUTO_SCALE | - HORIZ_INTERP_BILINEAR); - } - break; - - default: - break; - } - -out: - /* If not enabling scaling, be consistent and always use 0. */ - if ((pfit_control & PFIT_ENABLE) == 0) { - pfit_control = 0; - pfit_pgm_ratios = 0; - } - - if (pfit_control != lvds_encoder->pfit_control || - pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { - lvds_encoder->pfit_control = pfit_control; - lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; - } - dev_priv->lvds_border_bits = border; - /* * XXX: It would be nice to support lower refresh rates on the * panels to reduce power consumption, and perhaps match the @@ -1115,10 +917,6 @@ bool intel_lvds_init(struct drm_device *dev) lvds_encoder->attached_connector = lvds_connector; - if (!HAS_PCH_SPLIT(dev)) { - lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL); - } - intel_encoder = &lvds_encoder->base; encoder = &intel_encoder->base; intel_connector = &lvds_connector->base; @@ -1130,7 +928,6 @@ bool intel_lvds_init(struct drm_device *dev) DRM_MODE_ENCODER_LVDS); intel_encoder->enable = intel_enable_lvds; - intel_encoder->pre_enable = intel_pre_enable_lvds; intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; intel_encoder->compute_config = intel_lvds_compute_config; intel_encoder->disable = intel_disable_lvds; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7f6141d9a06..0f32f6498ad 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -117,6 +117,197 @@ done: dev_priv->pch_pf_size = (width << 16) | height; } +static void +centre_horizontally(struct drm_display_mode *mode, + int width) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the hsync and hblank widths constant */ + sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; + blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->hdisplay - width + 1) / 2; + border += border & 1; /* make the border even */ + + mode->crtc_hdisplay = width; + mode->crtc_hblank_start = width + border; + mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; + + mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; + mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; +} + +static void +centre_vertically(struct drm_display_mode *mode, + int height) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the vsync and vblank widths constant */ + sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; + blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->vdisplay - height + 1) / 2; + + mode->crtc_vdisplay = height; + mode->crtc_vblank_start = height + border; + mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; + + mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; + mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; +} + +static inline u32 panel_fitter_scaling(u32 source, u32 target) +{ + /* + * Floating point operation is not supported. So the FACTOR + * is defined, which can avoid the floating point computation + * when calculating the panel ratio. + */ +#define ACCURACY 12 +#define FACTOR (1 << ACCURACY) + u32 ratio = source * FACTOR / target; + return (FACTOR * ratio + FACTOR/2) / FACTOR; +} + +void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; + struct drm_display_mode *mode, *adjusted_mode; + + mode = &pipe_config->requested_mode; + adjusted_mode = &pipe_config->adjusted_mode; + + /* Native modes don't need fitting */ + if (adjusted_mode->hdisplay == mode->hdisplay && + adjusted_mode->vdisplay == mode->vdisplay) + goto out; + + switch (fitting_mode) { + case DRM_MODE_SCALE_CENTER: + /* + * For centered modes, we have to calculate border widths & + * heights and modify the values programmed into the CRTC. + */ + centre_horizontally(adjusted_mode, mode->hdisplay); + centre_vertically(adjusted_mode, mode->vdisplay); + border = LVDS_BORDER_ENABLE; + break; + case DRM_MODE_SCALE_ASPECT: + /* Scale but preserve the aspect ratio */ + if (INTEL_INFO(dev)->gen >= 4) { + u32 scaled_width = adjusted_mode->hdisplay * + mode->vdisplay; + u32 scaled_height = mode->hdisplay * + adjusted_mode->vdisplay; + + /* 965+ is easy, it does everything in hw */ + if (scaled_width > scaled_height) + pfit_control |= PFIT_ENABLE | + PFIT_SCALING_PILLAR; + else if (scaled_width < scaled_height) + pfit_control |= PFIT_ENABLE | + PFIT_SCALING_LETTER; + else if (adjusted_mode->hdisplay != mode->hdisplay) + pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; + } else { + u32 scaled_width = adjusted_mode->hdisplay * + mode->vdisplay; + u32 scaled_height = mode->hdisplay * + adjusted_mode->vdisplay; + /* + * For earlier chips we have to calculate the scaling + * ratio by hand and program it into the + * PFIT_PGM_RATIO register + */ + if (scaled_width > scaled_height) { /* pillar */ + centre_horizontally(adjusted_mode, + scaled_height / + mode->vdisplay); + + border = LVDS_BORDER_ENABLE; + if (mode->vdisplay != adjusted_mode->vdisplay) { + u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); + pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else if (scaled_width < scaled_height) { /* letter */ + centre_vertically(adjusted_mode, + scaled_width / + mode->hdisplay); + + border = LVDS_BORDER_ENABLE; + if (mode->hdisplay != adjusted_mode->hdisplay) { + u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); + pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else { + /* Aspects match, Let hw scale both directions */ + pfit_control |= (PFIT_ENABLE | + VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } + break; + default: + case DRM_MODE_SCALE_FULLSCREEN: + /* + * Full scaling, even if it changes the aspect ratio. + * Fortunately this is all done for us in hw. + */ + if (mode->vdisplay != adjusted_mode->vdisplay || + mode->hdisplay != adjusted_mode->hdisplay) { + pfit_control |= PFIT_ENABLE; + if (INTEL_INFO(dev)->gen >= 4) + pfit_control |= PFIT_SCALING_AUTO; + else + pfit_control |= (VERT_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_AUTO_SCALE | + HORIZ_INTERP_BILINEAR); + } + break; + } + + /* 965+ wants fuzzy fitting */ + /* FIXME: handle multiple panels by failing gracefully */ + if (INTEL_INFO(dev)->gen >= 4) + pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | + PFIT_FILTER_FUZZY); + +out: + if ((pfit_control & PFIT_ENABLE) == 0) { + pfit_control = 0; + pfit_pgm_ratios = 0; + } + + /* Make sure pre-965 set dither correctly for 18bpp panels. */ + if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + + if (pfit_control != pipe_config->pfit_control || + pfit_pgm_ratios != pipe_config->pfit_pgm_ratios) { + pipe_config->pfit_control = pfit_control; + pipe_config->pfit_pgm_ratios = pfit_pgm_ratios; + } + dev_priv->lvds_border_bits = border; +} + static int is_backlight_combination_mode(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- cgit v1.2.3-70-g09d2 From b074cec8c652f2d273907a4b35239b4766c894ac Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 25 Apr 2013 12:55:02 -0700 Subject: drm/i915: move PCH pfit controls into pipe_config And put the pfit stuff into substructs while we're at it. Signed-off-by: Jesse Barnes Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 65 +++++++++++++++++------------------- drivers/gpu/drm/i915/intel_dp.c | 6 ++-- drivers/gpu/drm/i915/intel_drv.h | 18 +++++++--- drivers/gpu/drm/i915/intel_lvds.c | 6 ++-- drivers/gpu/drm/i915/intel_panel.c | 25 ++++++++------ 7 files changed, 63 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8a257a9114c..14156f2b8d7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1021,8 +1021,6 @@ typedef struct drm_i915_private { struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ unsigned int lvds_border_bits; - /* Panel fitter placement and size for Ironlake+ */ - u32 pch_pf_pos, pch_pf_size; struct drm_crtc *plane_to_crtc_mapping[3]; struct drm_crtc *pipe_to_crtc_mapping[3]; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index eef450b1af4..0d7cf317b73 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -995,7 +995,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) /* Can only use the always-on power well for eDP when * not using the panel fitter, and when not using motion * blur mitigation (which we don't support). */ - if (dev_priv->pch_pf_size) + if (intel_crtc->config.pch_pfit.size) temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; else temp |= TRANS_DDI_EDP_INPUT_A_ON; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fc6f7683743..dacfc6c9055 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3225,6 +3225,28 @@ void intel_cpt_verify_modeset(struct drm_device *dev, int pipe) } } +static void ironlake_pfit_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + + if (crtc->config.pch_pfit.size && + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) { + /* Force use of hard-coded filter coefficients + * as some pre-programmed values are broken, + * e.g. x201. + */ + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | + PF_PIPE_SEL_IVB(pipe)); + else + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(PF_WIN_POS(pipe), crtc->config.pch_pfit.pos); + I915_WRITE(PF_WIN_SZ(pipe), crtc->config.pch_pfit.size); + } +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3269,21 +3291,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) encoder->pre_enable(encoder); /* Enable panel fitting for LVDS */ - if (dev_priv->pch_pf_size && - (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { - /* Force use of hard-coded filter coefficients - * as some pre-programmed values are broken, - * e.g. x201. - */ - if (IS_IVYBRIDGE(dev)) - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | - PF_PIPE_SEL_IVB(pipe)); - else - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); - I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); - I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); - } + ironlake_pfit_enable(intel_crtc); /* * On ILK+ LUT must be loaded before the pipe is running but with @@ -3353,17 +3361,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_ddi_enable_pipe_clock(intel_crtc); /* Enable panel fitting for eDP */ - if (dev_priv->pch_pf_size && - intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { - /* Force use of hard-coded filter coefficients - * as some pre-programmed values are broken, - * e.g. x201. - */ - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | - PF_PIPE_SEL_IVB(pipe)); - I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); - I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); - } + ironlake_pfit_enable(intel_crtc); /* * On ILK+ LUT must be loaded before the pipe is running but with @@ -3621,11 +3619,11 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) * register description and PRM. */ DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - pipe_config->pfit_control, - pipe_config->pfit_pgm_ratios); + pipe_config->gmch_pfit.control, + pipe_config->gmch_pfit.pgm_ratios); - I915_WRITE(PFIT_PGM_RATIOS, pipe_config->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, pipe_config->pfit_control); + I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios); + I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control); } static void valleyview_crtc_enable(struct drm_crtc *crtc) @@ -5800,6 +5798,9 @@ static void haswell_modeset_global_resources(struct drm_device *dev) /* XXX: Should check for edp transcoder here, but thanks to init * sequence that's not yet available. Just in case desktop eDP * on PORT D is possible on haswell, too. */ + /* Even the eDP panel fitter is outside the always-on well. */ + if (I915_READ(PF_WIN_SZ(crtc->pipe))) + enable = true; } list_for_each_entry(encoder, &dev->mode_config.encoder_list, @@ -5809,10 +5810,6 @@ static void haswell_modeset_global_resources(struct drm_device *dev) enable = true; } - /* Even the eDP panel fitter is outside the always-on well. */ - if (dev_priv->pch_pf_size) - enable = true; - intel_set_power_well(dev, enable); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9c834bc15ab..9ac034ee0dd 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -710,7 +710,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct intel_crtc *intel_crtc = encoder->new_crtc; struct intel_connector *intel_connector = intel_dp->attached_connector; @@ -733,9 +732,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_gmch_panel_fitting(intel_crtc, pipe_config, intel_connector->panel.fitting_mode); else - intel_pch_panel_fitting(dev, - intel_connector->panel.fitting_mode, - mode, adjusted_mode); + intel_pch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); } /* We need to take the panel's fixed mode into account. */ target_clock = adjusted_mode->clock; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9f3f71bc2f2..a8c69601496 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -239,7 +239,16 @@ struct intel_crtc_config { unsigned pixel_multiplier; /* Panel fitter controls for gen2-gen4 + VLV */ - u32 pfit_control, pfit_pgm_ratios; + struct { + u32 control; + u32 pgm_ratios; + } gmch_pfit; + + /* Panel fitter placement and size for Ironlake+ */ + struct { + u32 pos; + u32 size; + } pch_pfit; }; struct intel_crtc { @@ -557,10 +566,9 @@ extern void intel_panel_fini(struct intel_panel *panel); extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode); -extern void intel_pch_panel_fitting(struct drm_device *dev, - int fitting_mode, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); +extern void intel_pch_panel_fitting(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode); extern void intel_gmch_panel_fitting(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config, int fitting_mode); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 7d418818c7a..3e29499b2e9 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -229,7 +229,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct intel_connector *intel_connector = &lvds_encoder->attached_connector->base; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; unsigned int lvds_bpp; int pipe; @@ -267,9 +266,8 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, if (HAS_PCH_SPLIT(dev)) { pipe_config->has_pch_encoder = true; - intel_pch_panel_fitting(dev, - intel_connector->panel.fitting_mode, - mode, adjusted_mode); + intel_pch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); return true; } else { intel_gmch_panel_fitting(intel_crtc, pipe_config, diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 0f32f6498ad..00f31f7336f 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -54,14 +54,17 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, /* adjusted_mode has been preset to be the panel's fixed mode */ void -intel_pch_panel_fitting(struct drm_device *dev, - int fitting_mode, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +intel_pch_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + struct drm_display_mode *mode, *adjusted_mode; int x, y, width, height; + mode = &pipe_config->requested_mode; + adjusted_mode = &pipe_config->adjusted_mode; + x = y = width = height = 0; /* Native modes don't need fitting */ @@ -113,8 +116,8 @@ intel_pch_panel_fitting(struct drm_device *dev, } done: - dev_priv->pch_pf_pos = (x << 16) | y; - dev_priv->pch_pf_size = (width << 16) | height; + pipe_config->pch_pfit.pos = (x << 16) | y; + pipe_config->pch_pfit.size = (width << 16) | height; } static void @@ -300,10 +303,10 @@ out: if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) pfit_control |= PANEL_8TO6_DITHER_ENABLE; - if (pfit_control != pipe_config->pfit_control || - pfit_pgm_ratios != pipe_config->pfit_pgm_ratios) { - pipe_config->pfit_control = pfit_control; - pipe_config->pfit_pgm_ratios = pfit_pgm_ratios; + if (pfit_control != pipe_config->gmch_pfit.control || + pfit_pgm_ratios != pipe_config->gmch_pfit.pgm_ratios) { + pipe_config->gmch_pfit.control = pfit_control; + pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; } dev_priv->lvds_border_bits = border; } -- cgit v1.2.3-70-g09d2 From e29c22c0c4fefeb48a0157811930f7e9df0bb3f3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 21 Feb 2013 00:00:16 +0100 Subject: drm/i915: implement fdi auto-dithering So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit into this, among them the default 1080p mode. The solution is to dither down the pipe a bit so that everything fits, which this patch implements. But ports compute their state under the assumption that the bpp they pick will be the one selected, e.g. the display port bw computations won't work otherwise. Now we could adjust our code to again up-dither to the computed DP link parameters, but that's pointless. So instead when the pipe needs to adjust parameters we need to retry the pipe_config computation at the encoder stage. Furthermore we need to inform encoders that they should not increase bandwidth requirements if possible. This is required for the hdmi code, which prefers the pipe to up-dither to either of the two possible hdmi bpc values. LVDS has a similar requirement, although that's probably only theoretical in nature: It's unlikely that we'll ever see an 8bpc high-res lvds panel (which is required to hit the 2 fdi lane limit). eDP is the only thing which could increase the pipe_bpp setting again, even when in the retry-loop. This could hit the WARN. Two reasons for not bothering: - On many eDP panels we'll get a black screen if the bpp settings don't match vbt. So failing the modeset is the right thing to do. But since that also means it's the only way to light up the panel, it should work. So we shouldn't be able to hit this WARN. - There are still opens around the eDP panel handling, and maybe we need additional tricks. Before that happens it's imo no use trying to be too clever. Worst case we just need to kill that WARN or maybe fail the compute config stage if the eDP connector can't get the bpp setting it wants. And since this can only happen with an fdi link in between and so for pch eDP panels it's rather unlikely to blow up, if ever. v2: Rebased on top of a bikeshed from Paulo. v3: Improve commit message around eDP handling with the stuff things with Imre. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 56 ++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 7 +++++ drivers/gpu/drm/i915/intel_hdmi.c | 14 ++++++--- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 4 files changed, 62 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ef44b2a695..f40a28589ee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4040,13 +4040,16 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, } } -static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, - struct intel_crtc_config *pipe_config) +#define RETRY 1 +static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config) { struct drm_device *dev = intel_crtc->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; int target_clock, lane, link_bw; + bool setup_ok, needs_recompute = false; +retry: /* FDI is a binary signal running at ~2.7GHz, encoding * each output octet as 10 bits. The actual frequency * is stored as a divider into a 100MHz clock, and the @@ -4071,12 +4074,26 @@ static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, link_bw, &pipe_config->fdi_m_n); - return ironlake_check_fdi_lanes(intel_crtc->base.dev, - intel_crtc->pipe, pipe_config); + setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev, + intel_crtc->pipe, pipe_config); + if (!setup_ok && pipe_config->pipe_bpp > 6*3) { + pipe_config->pipe_bpp -= 2*3; + DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n", + pipe_config->pipe_bpp); + needs_recompute = true; + pipe_config->bw_constrained = true; + + goto retry; + } + + if (needs_recompute) + return RETRY; + + return setup_ok ? 0 : -EINVAL; } -static bool intel_crtc_compute_config(struct drm_crtc *crtc, - struct intel_crtc_config *pipe_config) +static int intel_crtc_compute_config(struct drm_crtc *crtc, + struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; @@ -4085,7 +4102,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, /* FDI link clock is fixed at 2.7G */ if (pipe_config->requested_mode.clock * 3 > IRONLAKE_FDI_FREQ * 4) - return false; + return -EINVAL; } /* All interlaced capable intel hw wants timings in frames. Note though @@ -4099,7 +4116,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, */ if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && adjusted_mode->hsync_start == adjusted_mode->hdisplay) - return false; + return -EINVAL; if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ @@ -4112,7 +4129,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, if (pipe_config->has_pch_encoder) return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); - return true; + return 0; } static int valleyview_get_display_clock_speed(struct drm_device *dev) @@ -7692,7 +7709,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, struct drm_encoder_helper_funcs *encoder_funcs; struct intel_encoder *encoder; struct intel_crtc_config *pipe_config; - int plane_bpp; + int plane_bpp, ret = -EINVAL; + bool retry = true; pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); if (!pipe_config) @@ -7705,6 +7723,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, if (plane_bpp < 0) goto fail; +encoder_retry: /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. @@ -7733,10 +7752,23 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, } } - if (!(intel_crtc_compute_config(crtc, pipe_config))) { + ret = intel_crtc_compute_config(crtc, pipe_config); + if (ret < 0) { DRM_DEBUG_KMS("CRTC fixup failed\n"); goto fail; } + + if (ret == RETRY) { + if (WARN(!retry, "loop in pipe configuration computation\n")) { + ret = -EINVAL; + goto fail; + } + + DRM_DEBUG_KMS("CRTC bw constrained, retrying\n"); + retry = false; + goto encoder_retry; + } + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; @@ -7746,7 +7778,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return pipe_config; fail: kfree(pipe_config); - return ERR_PTR(-EINVAL); + return ERR_PTR(ret); } /* Computes which crtcs are affected and sets the relevant bits in the mask. For diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 48f309eaf7a..766afcf39ee 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -223,6 +223,13 @@ struct intel_crtc_config { /* Controls for the clock computation, to override various stages. */ bool clock_set; + /* + * crtc bandwidth limit, don't increase pipe bpp or clock if not really + * required. This is set in the 2nd loop of calling encoder's + * ->compute_config if the first pick doesn't work out. + */ + bool bw_constrained; + /* Settings for the intel dpll used on pretty much everything but * haswell. */ struct dpll dpll; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 21302db7f76..93de5ff7791 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -784,6 +784,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2; + int desired_bpp; if (intel_hdmi->color_range_auto) { /* See CEA-861-E - 5.1 Default Encoding Parameters */ @@ -808,16 +809,21 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, */ if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000 && HAS_PCH_SPLIT(dev)) { - DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); - pipe_config->pipe_bpp = 12*3; + DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); + desired_bpp = 12*3; /* Need to adjust the port link by 1.5x for 12bpc. */ adjusted_mode->clock = clock_12bpc; pipe_config->pixel_target_clock = pipe_config->requested_mode.clock; } else { - DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); - pipe_config->pipe_bpp = 8*3; + DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); + desired_bpp = 8*3; + } + + if (!pipe_config->bw_constrained) { + DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); + pipe_config->pipe_bpp = desired_bpp; } if (adjusted_mode->clock > 225000) { diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3e29499b2e9..8d65baf043e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -248,7 +248,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, else lvds_bpp = 6*3; - if (lvds_bpp != pipe_config->pipe_bpp) { + if (lvds_bpp != pipe_config->pipe_bpp && !pipe_config->bw_constrained) { DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", pipe_config->pipe_bpp, lvds_bpp); pipe_config->pipe_bpp = lvds_bpp; -- cgit v1.2.3-70-g09d2 From 68fc874289e58e62bd0820db0d52150ce6d9fe03 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 22:52:16 +0200 Subject: drm/i915: move lvds_border_bits to pipe_config pipe_config is the new dev_priv! More seriously, this is actually better since a pipe_config can be thrown away if the modeset compute config stage fails. Whereas any state stored in dev_prive needs to be painstakingly restored, since otherwise a dpms off/on will wreak massive havoc. Yes, that even applies to state only used in ->mode_set callbacks, since we need to call those even for dpms on when the Haswell power well cleared everything out. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_lvds.c | 2 +- drivers/gpu/drm/i915/intel_panel.c | 3 +-- 4 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c34103d42c1..8890b0ba66c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1019,8 +1019,6 @@ typedef struct drm_i915_private { /* Kernel Modesetting */ struct sdvo_device_mapping sdvo_mappings[2]; - /* indicate whether the LVDS_BORDER should be enabled or not */ - unsigned int lvds_border_bits; struct drm_crtc *plane_to_crtc_mapping[3]; struct drm_crtc *pipe_to_crtc_mapping[3]; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 766afcf39ee..dfcf546790b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -249,6 +249,7 @@ struct intel_crtc_config { struct { u32 control; u32 pgm_ratios; + u32 lvds_border_bits; } gmch_pfit; /* Panel fitter placement and size for Ironlake+ */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8d65baf043e..47f47ea64f5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -116,7 +116,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) } /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; + temp |= intel_crtc->config.gmch_pfit.lvds_border_bits; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. */ diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 2526326efd8..4bf1e18f74c 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -183,7 +183,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, int fitting_mode) { struct drm_device *dev = intel_crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; struct drm_display_mode *mode, *adjusted_mode; @@ -312,7 +311,7 @@ out: pipe_config->gmch_pfit.control = pfit_control; pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; } - dev_priv->lvds_border_bits = border; + pipe_config->gmch_pfit.lvds_border_bits = border; } static int is_backlight_combination_mode(struct drm_device *dev) -- cgit v1.2.3-70-g09d2 From 5a80c45c5297a025c2615624042ea8b6840a5376 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 22:52:18 +0200 Subject: drm/i915: move border color writes to pfit_enable Writing hw registers from compute_config? Just say no! In this case not too horrible since we write a constant 0, and only debugging would put something else in there. But while checking that code I've noticed that this register disappeared on pch platforms, so fix that up, too. And adjust the comment a bit, it's outdated. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ drivers/gpu/drm/i915/intel_lvds.c | 10 ---------- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9b0d6b03aa1..65043379081 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3632,6 +3632,10 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios); I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control); + + /* Border color in case we don't scale up to the full screen. Black by + * default, change to something else for debugging. */ + I915_WRITE(BCLRPAT(crtc->pipe), 0); } static void valleyview_crtc_enable(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 47f47ea64f5..d256fe454a9 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -231,7 +231,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; unsigned int lvds_bpp; - int pipe; /* Should never happen!! */ if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) { @@ -274,15 +273,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, intel_connector->panel.fitting_mode); } - /* - * Enable automatic panel scaling for non-native modes so that they fill - * the screen. Should be enabled before the pipe is enabled, according - * to register description and PRM. - * Change the value here to see the borders for debugging - */ - for_each_pipe(pipe) - I915_WRITE(BCLRPAT(pipe), 0); - drm_mode_set_crtcinfo(adjusted_mode, 0); pipe_config->timings_set = true; -- cgit v1.2.3-70-g09d2 From 41aa344866e3ba1d117a798355c35d44d7cc6318 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 9 May 2013 20:03:18 -0300 Subject: drm/i915: Organize VBT stuff inside drm_i915_private drm_i915_private is getting bigger and bigger when adding new vbt stuff. So, the better way of getting drm_i915_private organized is to create a special structure for vbt stuff. v2: Basically conflicts fixes Reviewed-by: Jani Nikula Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 8 +-- drivers/gpu/drm/i915/i915_drv.h | 57 +++++++++++--------- drivers/gpu/drm/i915/intel_bios.c | 100 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_crt.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 12 ++--- drivers/gpu/drm/i915/intel_dp.c | 18 +++---- drivers/gpu/drm/i915/intel_lvds.c | 16 +++--- drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 6 +-- drivers/gpu/drm/i915/intel_tv.c | 8 +-- 10 files changed, 119 insertions(+), 112 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a1648eb3a8b..f5addac7c15 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1742,10 +1742,10 @@ int i915_driver_unload(struct drm_device *dev) * free the memory space allocated for the child device * config parsed from VBT */ - if (dev_priv->child_dev && dev_priv->child_dev_num) { - kfree(dev_priv->child_dev); - dev_priv->child_dev = NULL; - dev_priv->child_dev_num = 0; + if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) { + kfree(dev_priv->vbt.child_dev); + dev_priv->vbt.child_dev = NULL; + dev_priv->vbt.child_dev_num = 0; } vga_switcheroo_unregister_client(dev->pdev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eeec0be671b..14817de3740 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -891,6 +891,37 @@ enum modeset_restore { MODESET_SUSPENDED, }; +struct intel_vbt_data { + struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ + struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ + + /* Feature bits */ + unsigned int int_tv_support:1; + unsigned int lvds_dither:1; + unsigned int lvds_vbt:1; + unsigned int int_crt_support:1; + unsigned int lvds_use_ssc:1; + unsigned int display_clock_mode:1; + unsigned int fdi_rx_polarity_inverted:1; + int lvds_ssc_freq; + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + + /* eDP */ + int edp_rate; + int edp_lanes; + int edp_preemphasis; + int edp_vswing; + bool edp_initialized; + bool edp_support; + int edp_bpp; + struct edp_power_seq edp_pps; + + int crt_ddc_pin; + + int child_dev_num; + struct child_device_config *child_dev; +}; + typedef struct drm_i915_private { struct drm_device *dev; struct kmem_cache *slab; @@ -970,6 +1001,7 @@ typedef struct drm_i915_private { struct intel_fbc_work *fbc_work; struct intel_opregion opregion; + struct intel_vbt_data vbt; /* overlay */ struct intel_overlay *overlay; @@ -986,31 +1018,8 @@ typedef struct drm_i915_private { /* LVDS info */ struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ - - /* Feature bits from the VBIOS */ - unsigned int int_tv_support:1; - unsigned int lvds_dither:1; - unsigned int lvds_vbt:1; - unsigned int int_crt_support:1; - unsigned int lvds_use_ssc:1; - unsigned int display_clock_mode:1; - unsigned int fdi_rx_polarity_inverted:1; - int lvds_ssc_freq; - unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ - struct { - int rate; - int lanes; - int preemphasis; - int vswing; - - bool initialized; - bool support; - int bpp; - struct edp_power_seq pps; - } edp; bool no_aux_handshake; - int crt_ddc_pin; struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */ int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ @@ -1052,8 +1061,6 @@ typedef struct drm_i915_private { /* indicates the reduced downclock for LVDS*/ int lvds_downclock; u16 orig_clock; - int child_dev_num; - struct child_device_config *child_dev; bool mchbar_need_disable; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 95070b2124c..53f2bed8bc5 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -212,7 +212,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, if (!lvds_options) return; - dev_priv->lvds_dither = lvds_options->pixel_dither; + dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; if (lvds_options->panel_type == 0xff) return; @@ -226,7 +226,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, if (!lvds_lfp_data_ptrs) return; - dev_priv->lvds_vbt = 1; + dev_priv->vbt.lvds_vbt = 1; panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, lvds_lfp_data_ptrs, @@ -238,7 +238,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); - dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; + dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); drm_mode_debug_printmodeline(panel_fixed_mode); @@ -274,9 +274,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, /* check the resolution, just to be sure */ if (fp_timing->x_res == panel_fixed_mode->hdisplay && fp_timing->y_res == panel_fixed_mode->vdisplay) { - dev_priv->bios_lvds_val = fp_timing->lvds_reg_val; + dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val; DRM_DEBUG_KMS("VBT initial LVDS value %x\n", - dev_priv->bios_lvds_val); + dev_priv->vbt.bios_lvds_val); } } } @@ -316,7 +316,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); - dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; + dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); drm_mode_debug_printmodeline(panel_fixed_mode); @@ -345,20 +345,20 @@ parse_general_features(struct drm_i915_private *dev_priv, general = find_section(bdb, BDB_GENERAL_FEATURES); if (general) { - dev_priv->int_tv_support = general->int_tv_support; - dev_priv->int_crt_support = general->int_crt_support; - dev_priv->lvds_use_ssc = general->enable_ssc; - dev_priv->lvds_ssc_freq = + dev_priv->vbt.int_tv_support = general->int_tv_support; + dev_priv->vbt.int_crt_support = general->int_crt_support; + dev_priv->vbt.lvds_use_ssc = general->enable_ssc; + dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, general->ssc_freq); - dev_priv->display_clock_mode = general->display_clock_mode; - dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; + dev_priv->vbt.display_clock_mode = general->display_clock_mode; + dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", - dev_priv->int_tv_support, - dev_priv->int_crt_support, - dev_priv->lvds_use_ssc, - dev_priv->lvds_ssc_freq, - dev_priv->display_clock_mode, - dev_priv->fdi_rx_polarity_inverted); + dev_priv->vbt.int_tv_support, + dev_priv->vbt.int_crt_support, + dev_priv->vbt.lvds_use_ssc, + dev_priv->vbt.lvds_ssc_freq, + dev_priv->vbt.display_clock_mode, + dev_priv->vbt.fdi_rx_polarity_inverted); } } @@ -375,7 +375,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv, int bus_pin = general->crt_ddc_gmbus_pin; DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); if (intel_gmbus_is_port_valid(bus_pin)) - dev_priv->crt_ddc_pin = bus_pin; + dev_priv->vbt.crt_ddc_pin = bus_pin; } else { DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", block_size); @@ -486,7 +486,7 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (SUPPORTS_EDP(dev) && driver->lvds_config == BDB_DRIVER_FEATURE_EDP) - dev_priv->edp.support = 1; + dev_priv->vbt.edp_support = 1; if (driver->dual_frequency) dev_priv->render_reclock_avail = true; @@ -501,20 +501,20 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) edp = find_section(bdb, BDB_EDP); if (!edp) { - if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) + if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->vbt.edp_support) DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); return; } switch ((edp->color_depth >> (panel_type * 2)) & 3) { case EDP_18BPP: - dev_priv->edp.bpp = 18; + dev_priv->vbt.edp_bpp = 18; break; case EDP_24BPP: - dev_priv->edp.bpp = 24; + dev_priv->vbt.edp_bpp = 24; break; case EDP_30BPP: - dev_priv->edp.bpp = 30; + dev_priv->vbt.edp_bpp = 30; break; } @@ -522,48 +522,48 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) edp_pps = &edp->power_seqs[panel_type]; edp_link_params = &edp->link_params[panel_type]; - dev_priv->edp.pps = *edp_pps; + dev_priv->vbt.edp_pps = *edp_pps; - dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 : + dev_priv->vbt.edp_rate = edp_link_params->rate ? DP_LINK_BW_2_7 : DP_LINK_BW_1_62; switch (edp_link_params->lanes) { case 0: - dev_priv->edp.lanes = 1; + dev_priv->vbt.edp_lanes = 1; break; case 1: - dev_priv->edp.lanes = 2; + dev_priv->vbt.edp_lanes = 2; break; case 3: default: - dev_priv->edp.lanes = 4; + dev_priv->vbt.edp_lanes = 4; break; } switch (edp_link_params->preemphasis) { case 0: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0; break; case 1: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; break; case 2: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6; break; case 3: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; break; } switch (edp_link_params->vswing) { case 0: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400; break; case 1: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600; break; case 2: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800; break; case 3: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200; break; } } @@ -611,13 +611,13 @@ parse_device_mapping(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); return; } - dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); - if (!dev_priv->child_dev) { + dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); + if (!dev_priv->vbt.child_dev) { DRM_DEBUG_KMS("No memory space for child device\n"); return; } - dev_priv->child_dev_num = count; + dev_priv->vbt.child_dev_num = count; count = 0; for (i = 0; i < child_device_num; i++) { p_child = &(p_defs->devices[i]); @@ -625,7 +625,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, /* skip the device block if device type is invalid */ continue; } - child_dev_ptr = dev_priv->child_dev + count; + child_dev_ptr = dev_priv->vbt.child_dev + count; count++; memcpy((void *)child_dev_ptr, (void *)p_child, sizeof(*p_child)); @@ -638,23 +638,23 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; + dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; /* LFP panel data */ - dev_priv->lvds_dither = 1; - dev_priv->lvds_vbt = 0; + dev_priv->vbt.lvds_dither = 1; + dev_priv->vbt.lvds_vbt = 0; /* SDVO panel data */ - dev_priv->sdvo_lvds_vbt_mode = NULL; + dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; /* general features */ - dev_priv->int_tv_support = 1; - dev_priv->int_crt_support = 1; + dev_priv->vbt.int_tv_support = 1; + dev_priv->vbt.int_crt_support = 1; /* Default to using SSC */ - dev_priv->lvds_use_ssc = 1; - dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); - DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); + dev_priv->vbt.lvds_use_ssc = 1; + dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); + DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq); } static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 991e53047e1..cc414f1a0b9 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -442,7 +442,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG); - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); + i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); edid = intel_crt_get_edid(connector, i2c); if (edid) { @@ -648,7 +648,7 @@ static int intel_crt_get_modes(struct drm_connector *connector) int ret; struct i2c_adapter *i2c; - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); + i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); ret = intel_crt_ddc_get_modes(connector, i2c); if (ret || !IS_G4X(dev)) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e75e5468032..a14fec3a674 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4242,7 +4242,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) { if (i915_panel_use_ssc >= 0) return i915_panel_use_ssc != 0; - return dev_priv->lvds_use_ssc + return dev_priv->vbt.lvds_use_ssc && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); } @@ -4278,7 +4278,7 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) refclk = vlv_get_refclk(crtc); } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - refclk = dev_priv->lvds_ssc_freq * 1000; + refclk = dev_priv->vbt.lvds_ssc_freq * 1000; DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", refclk / 1000); } else if (!IS_GEN2(dev)) { @@ -5026,7 +5026,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) } if (HAS_PCH_IBX(dev)) { - has_ck505 = dev_priv->display_clock_mode; + has_ck505 = dev_priv->vbt.display_clock_mode; can_ssc = has_ck505; } else { has_ck505 = false; @@ -5338,8 +5338,8 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", - dev_priv->lvds_ssc_freq); - return dev_priv->lvds_ssc_freq * 1000; + dev_priv->vbt.lvds_ssc_freq); + return dev_priv->vbt.lvds_ssc_freq * 1000; } return 120000; @@ -5618,7 +5618,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, factor = 21; if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && - dev_priv->lvds_ssc_freq == 100) || + dev_priv->vbt.lvds_ssc_freq == 100) || (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; } else if (intel_crtc->config.sdvo_tv_clock) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0291b28ec87..2bb4009b7a6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -727,10 +727,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, * recomments. This means we'll up-dither 16bpp framebuffers on * high-depth panels. */ - if (is_edp(intel_dp) && dev_priv->edp.bpp) { + if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp) { DRM_DEBUG_KMS("forcing bpp for eDP panel to BIOS-provided %i\n", - dev_priv->edp.bpp); - bpp = dev_priv->edp.bpp; + dev_priv->vbt.edp_bpp); + bpp = dev_priv->vbt.edp_bpp; } for (; bpp >= 6*3; bpp -= 2*3) { @@ -2745,11 +2745,11 @@ bool intel_dpd_is_edp(struct drm_device *dev) struct child_device_config *p_child; int i; - if (!dev_priv->child_dev_num) + if (!dev_priv->vbt.child_dev_num) return false; - for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + p_child = dev_priv->vbt.child_dev + i; if (p_child->dvo_port == PORT_IDPD && p_child->device_type == DEVICE_TYPE_eDP) @@ -2827,7 +2827,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); - vbt = dev_priv->edp.pps; + vbt = dev_priv->vbt.edp_pps; /* Upper limits from eDP 1.3 spec. Note that we use the clunky units of * our hw here, which are all in 100usec. */ @@ -3097,8 +3097,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, } /* fallback to VBT if available for eDP */ - if (!fixed_mode && dev_priv->lfp_lvds_vbt_mode) { - fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) { + fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); if (fixed_mode) fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index d256fe454a9..e34e290c29e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -735,11 +735,11 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; int i; - if (!dev_priv->child_dev_num) + if (!dev_priv->vbt.child_dev_num) return true; - for (i = 0; i < dev_priv->child_dev_num; i++) { - struct child_device_config *child = dev_priv->child_dev + i; + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + struct child_device_config *child = dev_priv->vbt.child_dev + i; /* If the device type is not LFP, continue. * We have to check both the new identifiers as well as the @@ -827,7 +827,7 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) */ val = I915_READ(lvds_encoder->reg); if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) - val = dev_priv->bios_lvds_val; + val = dev_priv->vbt.bios_lvds_val; return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; } @@ -887,7 +887,7 @@ bool intel_lvds_init(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return false; - if (dev_priv->edp.support) { + if (dev_priv->vbt.edp_support) { DRM_DEBUG_KMS("disable LVDS for eDP support\n"); return false; } @@ -1005,11 +1005,11 @@ bool intel_lvds_init(struct drm_device *dev) } /* Failed to get EDID, what about VBT? */ - if (dev_priv->lfp_lvds_vbt_mode) { + if (dev_priv->vbt.lfp_lvds_vbt_mode) { DRM_DEBUG_KMS("using mode from VBT: "); - drm_mode_debug_printmodeline(dev_priv->lfp_lvds_vbt_mode); + drm_mode_debug_printmodeline(dev_priv->vbt.lfp_lvds_vbt_mode); - fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); if (fixed_mode) { fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6df886e06b6..5a22ce2b824 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3889,7 +3889,7 @@ static void cpt_init_clock_gating(struct drm_device *dev) val = I915_READ(TRANS_CHICKEN2(pipe)); val |= TRANS_CHICKEN2_TIMING_OVERRIDE; val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; - if (dev_priv->fdi_rx_polarity_inverted) + if (dev_priv->vbt.fdi_rx_polarity_inverted) val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 015f9f4263f..2f54dc3dc5d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1526,7 +1526,7 @@ intel_sdvo_get_analog_edid(struct drm_connector *connector) return drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, - dev_priv->crt_ddc_pin)); + dev_priv->vbt.crt_ddc_pin)); } static enum drm_connector_status @@ -1809,9 +1809,9 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) goto end; /* Fetch modes from VBT */ - if (dev_priv->sdvo_lvds_vbt_mode != NULL) { + if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) { newmode = drm_mode_duplicate(connector->dev, - dev_priv->sdvo_lvds_vbt_mode); + dev_priv->vbt.sdvo_lvds_vbt_mode); if (newmode != NULL) { /* Guarantee the mode is preferred */ newmode->type = (DRM_MODE_TYPE_PREFERRED | diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index b945bc54207..7d11a5adc98 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1521,12 +1521,12 @@ static int tv_is_present_in_vbt(struct drm_device *dev) struct child_device_config *p_child; int i, ret; - if (!dev_priv->child_dev_num) + if (!dev_priv->vbt.child_dev_num) return 1; ret = 0; - for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + p_child = dev_priv->vbt.child_dev + i; /* * If the device type is not TV, continue. */ @@ -1564,7 +1564,7 @@ intel_tv_init(struct drm_device *dev) return; } /* Even if we have an encoder we may not have a connector */ - if (!dev_priv->int_tv_support) + if (!dev_priv->vbt.int_tv_support) return; /* -- cgit v1.2.3-70-g09d2 From 2fa2fe9a142cf8c8a30916ccf7ca6a27019fd6d2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 May 2013 23:34:16 +0200 Subject: drm/i915: panel fitter hw state readout&check support Pfit state readout is a bit ugly on gen2/3 due to the intermingling with the lvds state, but alas. Also note that since state is always cleared to zero we can unconditonally compare all the state and completely neglect the actual platform we're running on. v2: Properly check for the pfit power domain on haswell. v3: Don't check pgm_ratios on gen4+, they're auto-computed by the hw. v4: Properly clear the lvds border bits, upset the state checker a bit. v5: Unconditionally read out panel dither settings on gen2/3. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 67 ++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_lvds.c | 1 + 2 files changed, 66 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9d01e5d6cc..12a92edbdd1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4976,6 +4976,36 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, return ret; } +static void i9xx_get_pfit_config(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; + uint32_t tmp; + + tmp = I915_READ(PFIT_CONTROL); + + if (INTEL_INFO(dev)->gen < 4) { + if (crtc->pipe != PIPE_B) + return; + + /* gen2/3 store dither state in pfit control, needs to match */ + pipe_config->gmch_pfit.control = tmp & PANEL_8TO6_DITHER_ENABLE; + } else { + if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT)) + return; + } + + if (!(tmp & PFIT_ENABLE)) + return; + + pipe_config->gmch_pfit.control = I915_READ(PFIT_CONTROL); + pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS); + if (INTEL_INFO(dev)->gen < 5) + pipe_config->gmch_pfit.lvds_border_bits = + I915_READ(LVDS) & LVDS_BORDER_ENABLE; +} + static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -4989,6 +5019,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, intel_get_pipe_timings(crtc, pipe_config); + i9xx_get_pfit_config(crtc, pipe_config); + return true; } @@ -5820,6 +5852,21 @@ static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc, & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; } +static void ironlake_get_pfit_config(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; + uint32_t tmp; + + tmp = I915_READ(PF_CTL(crtc->pipe)); + + if (tmp & PF_ENABLE) { + pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe)); + pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe)); + } +} + static bool ironlake_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -5843,6 +5890,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, intel_get_pipe_timings(crtc, pipe_config); + ironlake_get_pfit_config(crtc, pipe_config); + return true; } @@ -5962,6 +6011,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; + enum intel_display_power_domain pfit_domain; uint32_t tmp; if (!intel_display_power_enabled(dev, @@ -5991,6 +6041,10 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, intel_get_pipe_timings(crtc, pipe_config); + pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe); + if (intel_display_power_enabled(dev, pfit_domain)) + ironlake_get_pfit_config(crtc, pipe_config); + return true; } @@ -7956,7 +8010,8 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) if (mask & (1 <<(intel_crtc)->pipe)) static bool -intel_pipe_config_compare(struct intel_crtc_config *current_config, +intel_pipe_config_compare(struct drm_device *dev, + struct intel_crtc_config *current_config, struct intel_crtc_config *pipe_config) { #define PIPE_CONF_CHECK_I(name) \ @@ -8005,6 +8060,14 @@ intel_pipe_config_compare(struct intel_crtc_config *current_config, PIPE_CONF_CHECK_I(requested_mode.hdisplay); PIPE_CONF_CHECK_I(requested_mode.vdisplay); + PIPE_CONF_CHECK_I(gmch_pfit.control); + /* pfit ratios are autocomputed by the hw on gen4+ */ + if (INTEL_INFO(dev)->gen < 4) + PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); + PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); + PIPE_CONF_CHECK_I(pch_pfit.pos); + PIPE_CONF_CHECK_I(pch_pfit.size); + #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS @@ -8116,7 +8179,7 @@ intel_modeset_check_state(struct drm_device *dev) "(expected %i, found %i)\n", crtc->active, active); WARN(active && - !intel_pipe_config_compare(&crtc->config, &pipe_config), + !intel_pipe_config_compare(dev, &crtc->config, &pipe_config), "pipe state doesn't match!\n"); } } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e34e290c29e..36fe291172e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -116,6 +116,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) } /* set the corresponsding LVDS_BORDER bit */ + temp &= ~LVDS_BORDER_ENABLE; temp |= intel_crtc->config.gmch_pfit.lvds_border_bits; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. -- cgit v1.2.3-70-g09d2 From 045ac3b5629d9711531a408e92f9074db6afe7ce Mon Sep 17 00:00:00 2001 From: Jesse Barnes 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 Reviewed-by: Ville Syrjälä (v4) Tested-by: Paulo Zanoni (the new hsw ddi stuff) Signed-off-by: Daniel Vetter --- 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(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 66a0c6f0bb8..5e9f93e5325 100644 --- 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(struct intel_encoder *encoder, 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) @@ -778,6 +800,7 @@ void intel_crt_init(struct drm_device *dev) 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)) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 062de679f38..e6685218675 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1259,6 +1259,28 @@ static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) 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. */ @@ -1318,6 +1340,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) 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->port_reversal = I915_READ(DDI_BUF_CTL(port)) & diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2d90594016d..4196155cf96 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8067,6 +8067,15 @@ intel_pipe_config_compare(struct drm_device *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); @@ -8159,6 +8168,8 @@ intel_modeset_check_state(struct drm_device *dev) bool enabled = false; bool active = false; + memset(&pipe_config, 0, sizeof(pipe_config)); + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.base.id); @@ -8172,6 +8183,8 @@ intel_modeset_check_state(struct drm_device *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 " @@ -8180,7 +8193,6 @@ intel_modeset_check_state(struct drm_device *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); @@ -9589,8 +9601,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; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6ba9f09fe21..7c5eb2f6208 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1346,6 +1346,28 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, 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); @@ -3184,6 +3206,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) 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; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9b0af7e27c8..a435ce1d075 100644 --- 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; }; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 2c0be924e9a..9e80d487b5c 100644 --- 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(struct intel_encoder *encoder, 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 *dev) 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 */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 2b727f0d201..18f8ce0404c 100644 --- 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(struct intel_encoder *encoder, 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 *dev, int hdmi_reg, enum port port) 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; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 36fe291172e..655486099b7 100644 --- 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(struct intel_encoder *encoder, 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. @@ -921,6 +946,7 @@ bool intel_lvds_init(struct drm_device *dev) 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); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 78f0631b1c4..4d4a3f0cadf 100644 --- 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 *intel_sdvo, u8 cmd, 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(struct intel_sdvo *intel_sdvo, 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(struct intel_encoder *encoder, 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; @@ -2827,6 +2868,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) 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)) -- cgit v1.2.3-70-g09d2 From accfc0c50659c330cfde684017e5c1b58eee2857 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 30 May 2013 15:04:25 +0200 Subject: drm/i915: consolidate and tighten encoder cloning checks Only lvds/tv did actually check for cloning or not, but many more places should. Notices because my ivb tried to enable both cpu edp and vga on the first crtc - the resulting confusion between has_pch_encoder, has_dp_encoder but not actually being a pch dp encoder resulting in hilarity (hitting a BUG). We _really_ need an igt to random-walk our modeset space more exhaustively. The bug seems to have been exposed due to a race in the hw load detection support for VGA: Right after a hotplug VGA was still detected as connected, but obviously reading the EDID wasn't possible any more. Hence why restarting X a bit later fixed things. Due to the 1024x756 fallback resolution suddenly more outputs had the same resolution. On top of that SNA was confused with the possible_clones mask, trying to clone outputs which cannot be cloned. That bug is now fixed with commit fc1e0702b25e647cb423851fb7228989fec28bd6 Author: Daniel Vetter Date: Wed May 29 11:25:28 2013 +0100 sna: fixup up possible_clones kms->X impedance mismatch v2: Kill intel_encoder_check_is_cloned, spotted by Paulo. v3: Drop the now unused pipe param. v4: Kill the stray printk Chris spotted. v5: Elaborate on how the bug in userspace happened and why it was racy to reproduce. Cc: Chris Wilson Cc: stable@vger.kernel.org Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 64 ++++++++++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_lvds.c | 3 -- drivers/gpu/drm/i915/intel_tv.c | 3 -- 4 files changed, 24 insertions(+), 47 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a4b97caf85b..827d7ca2d9d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5868,27 +5868,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int num_connectors = 0; - bool is_cpu_edp = false; - struct intel_encoder *encoder; int ret; - for_each_encoder_on_crtc(dev, crtc, encoder) { - switch (encoder->type) { - case INTEL_OUTPUT_EDP: - if (enc_to_dig_port(&encoder->base)->port == PORT_A) - is_cpu_edp = true; - break; - } - - num_connectors++; - } - - WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", - num_connectors, pipe_name(pipe)); - if (!intel_ddi_pll_mode_set(crtc)) return -EINVAL; @@ -7564,28 +7546,6 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = { .load_lut = intel_crtc_load_lut, }; -bool intel_encoder_check_is_cloned(struct intel_encoder *encoder) -{ - struct intel_encoder *other_encoder; - struct drm_crtc *crtc = &encoder->new_crtc->base; - - if (WARN_ON(!crtc)) - return false; - - list_for_each_entry(other_encoder, - &crtc->dev->mode_config.encoder_list, - base.head) { - - if (&other_encoder->new_crtc->base != crtc || - encoder == other_encoder) - continue; - else - return true; - } - - return false; -} - static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, struct drm_crtc *crtc) { @@ -7769,6 +7729,25 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled); } +static bool check_encoder_cloning(struct drm_crtc *crtc) +{ + int num_encoders = 0; + bool uncloneable_encoders = false; + struct intel_encoder *encoder; + + list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, + base.head) { + if (&encoder->new_crtc->base != crtc) + continue; + + num_encoders++; + if (!encoder->cloneable) + uncloneable_encoders = true; + } + + return !(num_encoders > 1 && uncloneable_encoders); +} + static struct intel_crtc_config * intel_modeset_pipe_config(struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -7781,6 +7760,11 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, int plane_bpp, ret = -EINVAL; bool retry = true; + if (!check_encoder_cloning(crtc)) { + DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); + return ERR_PTR(-EINVAL); + } + pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); if (!pipe_config) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index afda71fdb4a..eae3dbc4e3e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -629,7 +629,6 @@ extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); -extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); extern void intel_modeset_check_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 655486099b7..10c3d56332f 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -264,9 +264,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, return false; } - if (intel_encoder_check_is_cloned(&lvds_encoder->base)) - return false; - if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) lvds_bpp = 8*3; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 7d11a5adc98..39debd80d19 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -914,9 +914,6 @@ intel_tv_compute_config(struct intel_encoder *encoder, if (!tv_mode) return false; - if (intel_encoder_check_is_cloned(&intel_tv->base)) - return false; - pipe_config->adjusted_mode.clock = tv_mode->clock; DRM_DEBUG_KMS("forcing bpc to 8 for TV\n"); pipe_config->pipe_bpp = 8*3; -- cgit v1.2.3-70-g09d2 From c9093354a1e839be057aee66bac37bd3b2f44d0e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Jun 2013 22:22:47 +0200 Subject: drm/i915: stop killing pfit on i9xx Nowadays (i.e. with Valleyview) we also have edp on non-PCH_SPLIT platforms, so just checking for LVDS is not good enough. Secondly we have full pfit pipe config tracking, so we'll correctly disable the pfit as part of the initial modeset. For fastboot we need a bit of work here to correctly kill unsupported configs (if e.g. the pfit is used on anything else than the built-in panel). But since that's not yet supported we don't need to worry. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +------ drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_lvds.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 06b1180c4c1..d617a72cc5c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8959,13 +8959,8 @@ static void intel_setup_outputs(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; bool dpd_is_edp = false; - bool has_lvds; - has_lvds = intel_lvds_init(dev); - if (!has_lvds && !HAS_PCH_SPLIT(dev)) { - /* disable the panel fitter on everything but LVDS */ - I915_WRITE(PFIT_CONTROL, 0); - } + intel_lvds_init(dev); if (!IS_ULT(dev)) intel_crt_init(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 02e5d655706..ffe9d35b37b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -582,7 +582,7 @@ extern void intel_mark_busy(struct drm_device *dev); extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring); extern void intel_mark_idle(struct drm_device *dev); -extern bool intel_lvds_init(struct drm_device *dev); +extern void intel_lvds_init(struct drm_device *dev); extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 10c3d56332f..eeff28ec2ff 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -877,7 +877,7 @@ static bool intel_lvds_supported(struct drm_device *dev) * Create the connector, register the LVDS DDC bus, and try to figure out what * modes we can display on the LVDS panel (if present). */ -bool intel_lvds_init(struct drm_device *dev) +void intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_lvds_encoder *lvds_encoder; @@ -895,35 +895,35 @@ bool intel_lvds_init(struct drm_device *dev) u8 pin; if (!intel_lvds_supported(dev)) - return false; + return; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) - return false; + return; pin = GMBUS_PORT_PANEL; if (!lvds_is_present_in_vbt(dev, &pin)) { DRM_DEBUG_KMS("LVDS is not present in VBT\n"); - return false; + return; } if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) - return false; + return; if (dev_priv->vbt.edp_support) { DRM_DEBUG_KMS("disable LVDS for eDP support\n"); - return false; + return; } } lvds_encoder = kzalloc(sizeof(struct intel_lvds_encoder), GFP_KERNEL); if (!lvds_encoder) - return false; + return; lvds_connector = kzalloc(sizeof(struct intel_lvds_connector), GFP_KERNEL); if (!lvds_connector) { kfree(lvds_encoder); - return false; + return; } lvds_encoder->attached_connector = lvds_connector; @@ -1094,7 +1094,7 @@ out: intel_panel_init(&intel_connector->panel, fixed_mode); intel_panel_setup_backlight(connector); - return true; + return; failed: DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); @@ -1104,5 +1104,5 @@ failed: drm_mode_destroy(dev, fixed_mode); kfree(lvds_encoder); kfree(lvds_connector); - return false; + return; } -- cgit v1.2.3-70-g09d2