Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_panel.c | 197 +++++++++++++++++++++++++++++++----- 2 files changed, 170 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a699efd..344f717 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4531,6 +4531,7 @@ #define SOUTH_CHICKEN2 0xc2004 #define FDI_MPHY_IOSFSB_RESET_STATUS (1<<13) #define FDI_MPHY_IOSFSB_RESET_CTL (1<<12) +#define PWM_GRANULARITY (1<<5) /* LPT */ #define DPLS_EDP_PPS_FIX_DIS (1<<0) #define _FDI_RXA_CHICKEN 0xc200c diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 1cf8085f..c020ab0 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -916,10 +916,93 @@ static void intel_backlight_device_unregister(struct intel_connector *connector) #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ /* - * Note: The setup hooks can't assume pipe is set! + * HSW/BDW: This value represents the period of the PWM stream in clock periods + * multiplied by 128 (default increment) or 16 (alternate increment, selected in + * LPT SOUTH_CHICKEN2 register bit 5). * - * XXX: Query mode clock or hardware clock and program PWM modulation frequency - * appropriately when it's 0. Use VBT and/or sane defaults. + * XXX: This only works when driving the PCH PWM. When driving the CPU PWM on + * the utility pin, the granularity needs to be determined by BLC_PWM_CTL bit + * 27. + */ +static int hsw_hz_to_pwm(struct drm_device *dev, u16 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 mul, clock; + + if (I915_READ(SOUTH_CHICKEN2) & PWM_GRANULARITY) + mul = 16; + else + mul = 128; + + if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) + clock = MHz(135); /* LPT:H */ + else + clock = MHz(24); /* LPT:LP */ + + return clock / (pwm_freq_hz * mul); +} + +/* + * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH + * display raw clocks multiplied by 128. + */ +static int pch_hz_to_pwm(struct drm_device *dev, u16 pwm_freq_hz) +{ + int clock = MHz(intel_pch_rawclk(dev)); + + return clock / (pwm_freq_hz * 128); +} + +/* + * Gen2: This field determines the number of time base events (display core + * clock frequency/32) in total for a complete cycle of modulated backlight + * control. + * + * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock) + * divided by 32. + */ +static int i9xx_hz_to_pwm(struct drm_device *dev, u16 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int clock; + + if (IS_PINEVIEW(dev)) + clock = intel_hrawclk(dev); + else + clock = 1000 * dev_priv->display.get_display_clock_speed(dev); + + return clock / (pwm_freq_hz * 32); +} + +/* + * Gen4: This value represents the period of the PWM stream in display core + * clocks multiplied by 128. + */ +static int i965_hz_to_pwm(struct drm_device *dev, u16 pwm_freq_hz) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int clock = 1000 * dev_priv->display.get_display_clock_speed(dev); + + return clock / (pwm_freq_hz * 128); +} + +/* + * VLV: This value represents the period of the PWM stream in display core + * clocks ([DevCTG] 100MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks + * multiplied by 16. + * + * XXX: Where is this selected??? + */ +static int vlv_hz_to_pwm(struct drm_device *dev, u16 pwm_freq_hz) +{ + if (1) + return MHz(25) / (pwm_freq_hz * 16); + else + return MHz(100) / (pwm_freq_hz * 128); +} + +/* + * Note: The setup hooks can't assume pipe is set! */ static int bdw_setup_backlight(struct intel_connector *connector) { @@ -933,8 +1016,18 @@ static int bdw_setup_backlight(struct intel_connector *connector) pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); panel->backlight.max = pch_ctl2 >> 16; - if (!panel->backlight.max) - return -ENODEV; + + if (!panel->backlight.max) { + u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; + + if (!pwm_freq_hz) + return -ENODEV; + + DRM_DEBUG_KMS("setting backlight frequency to %u Hz from VBT\n", + pwm_freq_hz); + + panel->backlight.max = hsw_hz_to_pwm(dev, pwm_freq_hz); + } val = bdw_get_backlight(connector); panel->backlight.level = intel_panel_compute_brightness(connector, val); @@ -957,8 +1050,21 @@ static int pch_setup_backlight(struct intel_connector *connector) pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); panel->backlight.max = pch_ctl2 >> 16; - if (!panel->backlight.max) - return -ENODEV; + + if (!panel->backlight.max) { + u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; + + if (!pwm_freq_hz) + return -ENODEV; + + DRM_DEBUG_KMS("setting backlight frequency to %u Hz from VBT\n", + pwm_freq_hz); + + if (IS_HASWELL(dev)) + panel->backlight.max = hsw_hz_to_pwm(dev, pwm_freq_hz); + else + panel->backlight.max = pch_hz_to_pwm(dev, pwm_freq_hz); + } val = pch_get_backlight(connector); panel->backlight.level = intel_panel_compute_brightness(connector, val); @@ -986,12 +1092,23 @@ static int i9xx_setup_backlight(struct intel_connector *connector) panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; panel->backlight.max = ctl >> 17; + + if (!panel->backlight.max) { + u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; + + if (!pwm_freq_hz) + return -ENODEV; + + DRM_DEBUG_KMS("setting backlight frequency to %u Hz from VBT\n", + pwm_freq_hz); + + panel->backlight.max = i9xx_hz_to_pwm(dev, pwm_freq_hz); + panel->backlight.max >>= 1; + } + if (panel->backlight.combination_mode) panel->backlight.max *= 0xff; - if (!panel->backlight.max) - return -ENODEV; - val = i9xx_get_backlight(connector); panel->backlight.level = intel_panel_compute_brightness(connector, val); @@ -1013,12 +1130,22 @@ static int i965_setup_backlight(struct intel_connector *connector) ctl = I915_READ(BLC_PWM_CTL); panel->backlight.max = ctl >> 16; + + if (!panel->backlight.max) { + u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; + + if (!pwm_freq_hz) + return -ENODEV; + + DRM_DEBUG_KMS("setting backlight frequency to %u Hz from VBT\n", + pwm_freq_hz); + + panel->backlight.max = i965_hz_to_pwm(dev, pwm_freq_hz); + } + if (panel->backlight.combination_mode) panel->backlight.max *= 0xff; - if (!panel->backlight.max) - return -ENODEV; - val = i9xx_get_backlight(connector); panel->backlight.level = intel_panel_compute_brightness(connector, val); @@ -1033,30 +1160,44 @@ static int vlv_setup_backlight(struct intel_connector *connector) struct drm_device *dev = connector->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_panel *panel = &connector->panel; - enum pipe pipe; + enum pipe p, pipe = PIPE_A; u32 ctl, ctl2, val; - for_each_pipe(pipe) { - u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); - - /* Skip if the modulation freq is already set */ - if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) - continue; + /* prefer a pipe that's configured and enabled, fall back to A */ + for_each_pipe(p) { + ctl = I915_READ(VLV_BLC_PWM_CTL(p)); + if (ctl >> 16) { + pipe = p; - cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | - cur_val); + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(p)); + if (ctl2 & BLM_PWM_ENABLE) + break; + } } - ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); + ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; - ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); + ctl = I915_READ(VLV_BLC_PWM_CTL(pipe)); panel->backlight.max = ctl >> 16; - if (!panel->backlight.max) - return -ENODEV; - val = _vlv_get_backlight(dev, PIPE_A); + if (!panel->backlight.max) { + u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; + + if (!pwm_freq_hz) { + pwm_freq_hz = 400; + DRM_DEBUG_KMS("defaulting to %u Hz backlight on %s\n", + pwm_freq_hz, + drm_get_connector_name(&connector->base)); + } else { + DRM_DEBUG_KMS("setting backlight frequency to %u Hz from VBT\n", + pwm_freq_hz); + } + + panel->backlight.max = vlv_hz_to_pwm(dev, pwm_freq_hz); + } + + val = _vlv_get_backlight(dev, pipe); panel->backlight.level = intel_panel_compute_brightness(connector, val); panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && -- 1.7.10.4 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx