From d65406327345e5a5e0f697a3ffe3e53bc9b5d7c6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Apr 2013 15:18:36 +0300 Subject: drm/i915: keep max backlight internal to intel_panel.c In preparation of adding locking to backlight, make max backlight value (the modulation frequency the PWM duty cycle value must not exceed) internal to intel_panel.c. Have intel_panel_set_backlight() accept a caller defined range for level, and scale input to max backlight value internally. Clean up intel_panel_get_max_backlight() and usage internally. Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 51 ++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index eb5e6e95f3c7..63a7c36a7603 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -130,6 +130,9 @@ static int is_backlight_combination_mode(struct drm_device *dev) return 0; } +/* XXX: query mode clock or hardware clock and program max PWM appropriately + * when it's 0. + */ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -164,7 +167,7 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) return val; } -static u32 _intel_panel_get_max_backlight(struct drm_device *dev) +static u32 intel_panel_get_max_backlight(struct drm_device *dev) { u32 max; @@ -182,23 +185,8 @@ static u32 _intel_panel_get_max_backlight(struct drm_device *dev) max *= 0xff; } - return max; -} - -u32 intel_panel_get_max_backlight(struct drm_device *dev) -{ - u32 max; - - max = _intel_panel_get_max_backlight(dev); - if (max == 0) { - /* XXX add code here to query mode clock or hardware clock - * and program max PWM appropriately. - */ - pr_warn_once("fixme: max PWM is zero\n"); - return 1; - } - DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); + return max; } @@ -217,8 +205,11 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) return val; if (i915_panel_invert_brightness > 0 || - dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) - return intel_panel_get_max_backlight(dev) - val; + dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { + u32 max = intel_panel_get_max_backlight(dev); + if (max) + return max - val; + } return val; } @@ -270,6 +261,10 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level u32 max = intel_panel_get_max_backlight(dev); u8 lbpc; + /* we're screwed, but keep behaviour backwards compatible */ + if (!max) + max = 1; + lbpc = level * 0xfe / max + 1; level /= lbpc; pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); @@ -282,9 +277,20 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level I915_WRITE(BLC_PWM_CTL, tmp | level); } -void intel_panel_set_backlight(struct drm_device *dev, u32 level) +/* set backlight brightness to level in range [0..max] */ +void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 freq; + + freq = intel_panel_get_max_backlight(dev); + if (!freq) { + /* we are screwed, bail out */ + return; + } + + /* scale to hardware */ + level = level * freq / max; dev_priv->backlight.level = level; if (dev_priv->backlight.device) @@ -405,7 +411,8 @@ intel_panel_detect(struct drm_device *dev) static int intel_panel_update_status(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); - intel_panel_set_backlight(dev, bd->props.brightness); + intel_panel_set_backlight(dev, bd->props.brightness, + bd->props.max_brightness); return 0; } @@ -434,7 +441,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.brightness = dev_priv->backlight.level; - props.max_brightness = _intel_panel_get_max_backlight(dev); + props.max_brightness = intel_panel_get_max_backlight(dev); if (props.max_brightness == 0) { DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); return -ENODEV; -- cgit v1.2.3 From 8ba2d18520ce380cf572e9902d9b3b91ece6c2c0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Apr 2013 15:18:37 +0300 Subject: drm/i915: protect backlight registers and data with a spinlock Backlight data and registers are fiddled through LVDS/eDP modeset enable/disable hooks, backlight sysfs files, asle interrupts, and register save/restore. Protect the backlight related registers and driver private fields using a spinlock. The locking in register save/restore covers a little more than is strictly necessary, including non-modeset case, for simplicity. v2: Cover register access, save/restore, i915_read_blc_pwm_ctl() and code paths leading there. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 63a7c36a7603..5d3e9d7d51a7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -138,6 +138,8 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 val; + WARN_ON(!spin_is_locked(&dev_priv->backlight.lock)); + /* Restore the CTL value if it lost, e.g. GPU reset */ if (HAS_PCH_SPLIT(dev_priv->dev)) { @@ -218,6 +220,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 val; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); if (HAS_PCH_SPLIT(dev)) { val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; @@ -235,6 +240,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) } val = intel_panel_compute_brightness(dev, val); + + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); return val; } @@ -282,11 +290,14 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) { struct drm_i915_private *dev_priv = dev->dev_private; u32 freq; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); freq = intel_panel_get_max_backlight(dev); if (!freq) { /* we are screwed, bail out */ - return; + goto out; } /* scale to hardware */ @@ -298,11 +309,16 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) if (dev_priv->backlight.enabled) intel_panel_actually_set_backlight(dev, level); +out: + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); } void intel_panel_disable_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); dev_priv->backlight.enabled = false; intel_panel_actually_set_backlight(dev, 0); @@ -320,12 +336,17 @@ void intel_panel_disable_backlight(struct drm_device *dev) I915_WRITE(BLC_PWM_PCH_CTL1, tmp); } } + + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); } void intel_panel_enable_backlight(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); if (dev_priv->backlight.level == 0) { dev_priv->backlight.level = intel_panel_get_max_backlight(dev); @@ -375,6 +396,8 @@ set_level: */ dev_priv->backlight.enabled = true; intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); + + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); } static void intel_panel_init_backlight(struct drm_device *dev) @@ -432,6 +455,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct backlight_properties props; + unsigned long flags; intel_panel_init_backlight(dev); @@ -441,7 +465,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.brightness = dev_priv->backlight.level; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); props.max_brightness = intel_panel_get_max_backlight(dev); + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + if (props.max_brightness == 0) { DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); return -ENODEV; -- cgit v1.2.3 From 35ffda4883a8d3f75632d7389dc96a25640033f0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 25 Apr 2013 16:49:25 +0300 Subject: drm/i915: hsw backlight registers need transcoder instead of pipe v2: Make TRANSCODER_EDP handling more explicit. (Imre) Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 5d3e9d7d51a7..7f6141d9a06d 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -344,6 +344,8 @@ void intel_panel_enable_backlight(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = + intel_pipe_to_cpu_transcoder(dev_priv, pipe); unsigned long flags; spin_lock_irqsave(&dev_priv->backlight.lock, flags); @@ -374,7 +376,10 @@ void intel_panel_enable_backlight(struct drm_device *dev, else tmp &= ~BLM_PIPE_SELECT; - tmp |= BLM_PIPE(pipe); + if (cpu_transcoder == TRANSCODER_EDP) + tmp |= BLM_TRANSCODER_EDP; + else + tmp |= BLM_PIPE(cpu_transcoder); tmp &= ~BLM_PWM_ENABLE; I915_WRITE(reg, tmp); -- cgit v1.2.3 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_panel.c | 191 +++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7f6141d9a06d..0f32f6498ad3 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 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/intel_panel.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 0f32f6498ad3..00f31f7336f2 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 From ab3e67f43a299b064ccd8cd230d4a006a05c8a4c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 25 Apr 2013 12:55:03 -0700 Subject: drm/i915: warn about invalid pfit modes We prevent invalid ones from getting here in the first place, but it doesn't hurt to have an extra sanity check. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 00f31f7336f2..2526326efd81 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -58,7 +58,6 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, struct intel_crtc_config *pipe_config, int fitting_mode) { - struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; struct drm_display_mode *mode, *adjusted_mode; int x, y, width, height; @@ -107,12 +106,15 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, } break; - default: case DRM_MODE_SCALE_FULLSCREEN: x = y = 0; width = adjusted_mode->hdisplay; height = adjusted_mode->vdisplay; break; + + default: + WARN(1, "bad panel fit mode: %d\n", fitting_mode); + return; } done: @@ -267,7 +269,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, } } break; - default: case DRM_MODE_SCALE_FULLSCREEN: /* * Full scaling, even if it changes the aspect ratio. @@ -285,6 +286,9 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, HORIZ_INTERP_BILINEAR); } break; + default: + WARN(1, "bad panel fit mode: %d\n", fitting_mode); + return; } /* 965+ wants fuzzy fitting */ -- cgit v1.2.3 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/intel_panel.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 2526326efd81..4bf1e18f74cc 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 From 2deefda541edb0c73e57e988ccaac4cd014da0d3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 22:52:17 +0200 Subject: drm/i915: rip out indirection for pfit pipe_config assignment This was still required a bit (on the cargo-cult side though) when the state was stored in dev_priv, and when the enable/disable sequence was botched a bit (to avoid too many updates). But with pipeconfig we always get a clean slate, so this is pointless. Rip it out. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 4bf1e18f74cc..56f17b2382fc 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -306,11 +306,8 @@ out: if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) pfit_control |= PANEL_8TO6_DITHER_ENABLE; - 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; - } + pipe_config->gmch_pfit.control = pfit_control; + pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; pipe_config->gmch_pfit.lvds_border_bits = border; } -- cgit v1.2.3 From df0a67979543e716d411eb11406848dcb50abd0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 22 May 2013 11:36:40 +0300 Subject: drm/i915: Fix WARN_ON() on UP machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WARN_ON(!spin_is_locked()) is not a good idea on a UP system w/o spinlock debugging. Use WARN_ON_SMP() instead. This check has been added in commit 8ba2d18520ce380cf572e9902d9b3b91ece6c2c0 Author: Jani Nikula Date: Fri Apr 12 15:18:37 2013 +0300 drm/i915: protect backlight registers and data with a spinlock Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 56f17b2382fc..80bea1d3209f 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -332,7 +332,7 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 val; - WARN_ON(!spin_is_locked(&dev_priv->backlight.lock)); + WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock)); /* Restore the CTL value if it lost, e.g. GPU reset */ -- cgit v1.2.3 From 21d8a4756af5fdf4a42e79a77cf3b6f52678d443 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Jul 2013 08:07:30 +0200 Subject: drm/i915: fix pfit regression for non-autoscaled resolutions I.e. for letter/pillarboxing. For those cases we need to adjust the mode a bit, but Jesse gmch pfit refactoring in commit 2dd24552cab40ea829ba3fda890eeafd2c4816d8 Author: Jesse Barnes Date: Thu Apr 25 12:55:01 2013 -0700 drm/i915: factor out GMCH panel fitting code and use for eDP v3 broke that by reordering the computation of the gmch pfit state with the block of code that prepared the adjusted mode for it and told the modeset core not to overwrite the adjusted mode with default settings. We might want to switch around the core code to just fill in defaults, but this code predates the pipe_config modeset rework. And in the old crtc helpers we did not have a suitable spot to do this. Cc: Mika Kuoppala Cc: Jesse Barnes Cc: Hans de Bruin Reported-and-tested-by: Hans de Bruin Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 80bea1d3209f..45010bb5d132 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -194,6 +194,9 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, adjusted_mode->vdisplay == mode->vdisplay) goto out; + drm_mode_set_crtcinfo(adjusted_mode, 0); + pipe_config->timings_set = true; + switch (fitting_mode) { case DRM_MODE_SCALE_CENTER: /* -- cgit v1.2.3 From e85843bec6c2ea7c10ec61238396891cc2b753a9 Mon Sep 17 00:00:00 2001 From: Kamal Mostafa Date: Fri, 19 Jul 2013 15:02:01 -0700 Subject: drm/i915: quirk no PCH_PWM_ENABLE for Dell XPS13 backlight BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=47941 BugLink: https://bugs.launchpad.net/bugs/1163720 BugLink: https://bugs.launchpad.net/bugs/1162026 Some machines suffer from non-functional backlight controls if BLM_PCH_PWM_ENABLE is set, so provide a quirk to avoid doing so. Apply this quirk to Dell XPS 13 models. Tested-by: Eric Griffith Tested-by: Kent Baxley Cc: # v3.8+ Signed-off-by: Kamal Mostafa Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 45010bb5d132..67e2c1f1c9a8 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -583,7 +583,8 @@ void intel_panel_enable_backlight(struct drm_device *dev, POSTING_READ(reg); I915_WRITE(reg, tmp | BLM_PWM_ENABLE); - if (HAS_PCH_SPLIT(dev)) { + if (HAS_PCH_SPLIT(dev) && + !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { tmp = I915_READ(BLC_PWM_PCH_CTL1); tmp |= BLM_PCH_PWM_ENABLE; tmp &= ~BLM_PCH_OVERRIDE_ENABLE; -- cgit v1.2.3 From 22505b82a2800bddb67908522833bef96dd15845 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Fri, 2 Aug 2013 09:16:03 +0800 Subject: drm/i915: avoid brightness overflow when doing scale Some card's max brightness level is pretty large, e.g. on Acer Aspire 4732Z, the max level is 989910. If user space set a large enough level then the current scale done in intel_panel_set_backlight will cause an integer overflow and the scaled level will be mistakenly small, leaving user with an almost black screen. This patch fixes this problem. Signed-off-by: Aaron Lu [danvet: Add a comment to explain what's going on.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 67e2c1f1c9a8..5063eadac3ef 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -497,8 +497,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) goto out; } - /* scale to hardware */ - level = level * freq / max; + /* scale to hardware, but be careful to not overflow */ + if (freq < max) + level = level * freq / max; + else + level = freq / max * level; dev_priv->backlight.level = level; if (dev_priv->backlight.device) -- cgit v1.2.3 From 3f577573cd5482a32f85bd131e52f7cb4b9ac518 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 25 Jul 2013 14:31:30 +0300 Subject: drm/i915: do not disable backlight on vgaswitcheroo switch off On muxed systems, the other vgaswitcheroo client may depend on i915 to handle the backlight. We began switching off the backlight since commit a261b246ebd552fd5d5a8ed84cc931bb821c427f Author: Daniel Vetter Date: Thu Jul 26 19:21:47 2012 +0200 drm/i915: disable all crtcs at suspend time breaking backlight on discreet graphics in (some) muxed systems. Keep the backlight on when the state is changed through vgaswitcheroo. Note: The alternative would be to add a quirk table to achieve the same based on system identifiers, but AFAICS it would asymptotically approach effectively the same as this patch as more IDs are added, but with the maintenance burden of the quirk table. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=55311 Tested-by: Fede Tested-by: Aximab Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=59785 Tested-by: sfievet Signed-off-by: Jani Nikula Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_panel.c') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 5063eadac3ef..5950888ae1d0 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -518,6 +518,17 @@ void intel_panel_disable_backlight(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; unsigned long flags; + /* + * Do not disable backlight on the vgaswitcheroo path. When switching + * away from i915, the other client may depend on i915 to handle the + * backlight. This will leave the backlight on unnecessarily when + * another client is not activated. + */ + if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { + DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); + return; + } + spin_lock_irqsave(&dev_priv->backlight.lock, flags); dev_priv->backlight.enabled = false; -- cgit v1.2.3