From patchwork Mon Apr 12 17:36:05 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 92062 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o3CHaBCA008896 for ; Mon, 12 Apr 2010 17:36:47 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 994199E853; Mon, 12 Apr 2010 10:36:11 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from cavan.codon.org.uk (cavan.codon.org.uk [93.93.128.6]) by gabe.freedesktop.org (Postfix) with ESMTP id 731359E79F for ; Mon, 12 Apr 2010 10:36:09 -0700 (PDT) Received: from mjg59 by cavan.codon.org.uk with local (Exim 4.69) (envelope-from ) id 1O1NYL-0000Pz-4f; Mon, 12 Apr 2010 18:36:05 +0100 Date: Mon, 12 Apr 2010 18:36:05 +0100 From: Matthew Garrett To: Sergio Monteiro Basto Message-ID: <20100412173605.GA1544@srcf.ucam.org> References: <1270568618.8947.13.camel@segulix> <1270600597.3611.32.camel@localhost.localdomain> <1270649792.2455.1.camel@segulix> <1270691913.3611.59.camel@localhost.localdomain> <20100408082646.GI8821@zhen-devel.sh.intel.com> <1270845726.29931.5.camel@segulix> <1270952553.14102.35.camel@segulix> <20100412171920.GB1106@srcf.ucam.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20100412171920.GB1106@srcf.ucam.org> User-Agent: Mutt/1.5.18 (2008-05-17) X-SA-Exim-Connect-IP: X-SA-Exim-Mail-From: mjg59@cavan.codon.org.uk X-SA-Exim-Scanned: No (on cavan.codon.org.uk); SAEximRunCond expanded to false Cc: intel-gfx Subject: Re: [Intel-gfx] BACKLIGHT_CONTROL and xrandr X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 12 Apr 2010 17:36:48 +0000 (UTC) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index aba8260..40f6684 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -33,6 +33,7 @@ #include "i915_reg.h" #include "intel_bios.h" #include +#include /* General customization: */ @@ -628,6 +629,8 @@ typedef struct drm_i915_private { u8 max_delay; enum no_fbc_reason no_fbc_reason; + + struct backlight_device *backlight; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index 7cc8410..ea71e65 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c @@ -31,9 +31,9 @@ #include "drmP.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" #define PCI_ASLE 0xe4 -#define PCI_LBPC 0xf4 #define PCI_ASLS 0xfc #define OPREGION_SZ (8*1024) @@ -151,37 +151,10 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; struct opregion_asle *asle = dev_priv->opregion.asle; - u32 blc_pwm_ctl, blc_pwm_ctl2; - u32 max_backlight, level, shift; - - if (!(bclp & ASLE_BCLP_VALID)) - return ASLE_BACKLIGHT_FAIL; - - bclp &= ASLE_BCLP_MSK; - if (bclp < 0 || bclp > 255) - return ASLE_BACKLIGHT_FAIL; - - blc_pwm_ctl = I915_READ(BLC_PWM_CTL); - blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2); - - if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE)) - pci_write_config_dword(dev->pdev, PCI_LBPC, bclp); - else { - if (IS_PINEVIEW(dev)) { - blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); - max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT; - shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1; - } else { - blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; - max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; - shift = BACKLIGHT_DUTY_CYCLE_SHIFT; - } - level = (bclp * max_backlight) / 255; - I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift)); - } - asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; + u32 max = intel_lvds_get_max_backlight(dev); + + asle->cblv = (bclp * 100 / 255) | ASLE_CBLV_VALID; + intel_lvds_set_backlight(dev, max * bclp / 255); return 0; } @@ -247,36 +220,6 @@ void opregion_asle_intr(struct drm_device *dev) asle->aslc = asle_stat; } -static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; - u32 cpu_pwm_ctl, pch_pwm_ctl2; - u32 max_backlight, level; - - if (!(bclp & ASLE_BCLP_VALID)) - return ASLE_BACKLIGHT_FAILED; - - bclp &= ASLE_BCLP_MSK; - if (bclp < 0 || bclp > 255) - return ASLE_BACKLIGHT_FAILED; - - cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL); - pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); - /* get the max PWM frequency */ - max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK; - /* calculate the expected PMW frequency */ - level = (bclp * max_backlight) / 255; - /* reserve the high 16 bits */ - cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK); - /* write the updated PWM frequency */ - I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level); - - asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; - - return 0; -} - void ironlake_opregion_gse_intr(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -300,7 +243,7 @@ void ironlake_opregion_gse_intr(struct drm_device *dev) } if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp); + asle_stat |= asle_set_backlight(dev, asle->bclp); if (asle_req & ASLE_SET_PFIT) { DRM_DEBUG_DRIVER("Pfit is not supported\n"); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3a467ca..1c35f67 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -171,6 +171,9 @@ extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj); extern void intel_lvds_init(struct drm_device *dev); +extern u32 intel_lvds_get_max_backlight(struct drm_device *dev); +extern u32 intel_lvds_get_backlight(struct drm_device *dev); +extern void intel_lvds_set_backlight(struct drm_device *dev, int level); extern void intel_dp_init(struct drm_device *dev, int dp_reg); void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2b3fa7a..ee2a06f 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -38,6 +38,7 @@ #include "i915_drm.h" #include "i915_drv.h" #include +#include /* Private structure for the integrated LVDS support */ struct intel_lvds_priv { @@ -47,43 +48,174 @@ struct intel_lvds_priv { }; /** - * Sets the backlight level. - * - * \param level backlight level, from 0 to intel_lvds_get_max_backlight(). + * Returns the maximum level of the backlight duty cycle field. */ -static void intel_lvds_set_backlight(struct drm_device *dev, int level) +u32 intel_lvds_get_max_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 blc_pwm_ctl, reg; + u32 reg; + int value; + bool combo; - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_CPU_CTL; + if (IS_I965G(dev)) + combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; + else + combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; + + if (IS_IRONLAKE(dev)) + reg = BLC_PWM_PCH_CTL2; else reg = BLC_PWM_CTL; - blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(reg, (blc_pwm_ctl | - (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); + value = ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT); + + if (!IS_PINEVIEW(dev)) + value *= 2; + + if (combo) { + value *= 0xff; + value /= 2; + } + + return value; } /** - * Returns the maximum level of the backlight duty cycle field. + * Returns the level of the backlight duty cycle field. */ -static u32 intel_lvds_get_max_backlight(struct drm_device *dev) +u32 intel_lvds_get_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg; + u8 lbpc; + int value; + bool combo; - if (HAS_PCH_SPLIT(dev)) - reg = BLC_PWM_PCH_CTL2; + if (IS_I965G(dev)) + combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; + else + combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; + + if (IS_IRONLAKE(dev)) + reg = BLC_PWM_CPU_CTL; else reg = BLC_PWM_CTL; - return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + value = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK; + + if (IS_PINEVIEW(dev)) + value /= 2; + + if (combo) { + value &= ~0x1; + pci_read_config_byte(dev->pdev, LBB, &lbpc); + value *= lbpc; + value /= 2; + } + + return value; } /** + * Sets the backlight level. + * + * \param level backlight level, from 0 to intel_lvds_get_max_backlight(). + */ +void intel_lvds_set_backlight(struct drm_device *dev, int level) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 blc_pwm_ctl, reg; + bool combo; + u8 lbpc; + + if (IS_I965G(dev)) + combo = I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; + else + combo = I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; + + if (IS_IRONLAKE(dev)) + reg = BLC_PWM_CPU_CTL; + else + reg = BLC_PWM_CTL; + + if (combo) { + int maximum = intel_lvds_get_max_backlight(dev); + lbpc = level * 0xfe / maximum; + lbpc += 1; + pci_write_config_byte(dev->pdev, LBB, lbpc); + level /= lbpc; + level <<= 1; + } + + if (IS_PINEVIEW(dev)) { + blc_pwm_ctl = I915_READ(reg) & ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); + I915_WRITE(reg, (blc_pwm_ctl | + (level << (BACKLIGHT_DUTY_CYCLE_SHIFT + 1)))); + } else { + blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(reg, blc_pwm_ctl | + (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); + } +} + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +static int intel_lvds_update_status(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + intel_lvds_set_backlight(dev, bd->props.brightness); + return 0; +} + +static int intel_lvds_get_brightness(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + return intel_lvds_get_backlight(dev); +} + +static const struct backlight_ops intel_lvds_bl_ops = { + .update_status = intel_lvds_update_status, + .get_brightness = intel_lvds_get_brightness, +}; + +static int intel_lvds_backlight_setup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct backlight_properties props; + + props.max_brightness = intel_lvds_get_max_backlight(dev); + dev_priv->backlight = backlight_device_register("intel_backlight", + &dev->pdev->dev, dev, + &intel_lvds_bl_ops, + &props); + if (IS_ERR(dev_priv->backlight)) { + DRM_ERROR("Failed to register backlight: %ld\n", + PTR_ERR(dev_priv->backlight)); + dev_priv->backlight = NULL; + return -ENODEV; + } + dev_priv->backlight->props.brightness = intel_lvds_get_backlight(dev); + return 0; +} + +static void intel_lvds_backlight_destroy(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; + if (dev_priv->backlight) + backlight_device_unregister(dev_priv->backlight); +} +#else +static int intel_lvds_backlight_setup(struct drm_device *dev) +{ + return 0; +} + +static void intel_lvds_backlight_destroy(struct drm_device *dev) +{ + return; +} +#endif + +/** * Sets the power state for the panel. */ static void intel_lvds_set_power(struct drm_device *dev, bool on) @@ -164,8 +296,7 @@ static void intel_lvds_save(struct drm_connector *connector) dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg); dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg); dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg); - dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & - BACKLIGHT_DUTY_CYCLE_MASK); + dev_priv->backlight_duty_cycle = intel_lvds_get_backlight(dev); /* * If the light is off at server startup, just make it full brightness @@ -562,8 +693,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) reg = BLC_PWM_CTL; dev_priv->saveBLC_PWM_CTL = I915_READ(reg); - dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & - BACKLIGHT_DUTY_CYCLE_MASK); + dev_priv->backlight_duty_cycle = intel_lvds_get_backlight(dev); intel_lvds_set_power(dev, false); } @@ -717,6 +847,8 @@ static void intel_lvds_destroy(struct drm_connector *connector) struct intel_output *intel_output = to_intel_output(connector); struct drm_i915_private *dev_priv = dev->dev_private; + intel_lvds_backlight_destroy(dev); + if (intel_output->ddc_bus) intel_i2c_destroy(intel_output->ddc_bus); if (dev_priv->lid_notifier.notifier_call) @@ -1128,6 +1260,9 @@ out: /* keep the LVDS connector */ dev_priv->int_lvds_connector = connector; drm_sysfs_connector_add(connector); + + intel_lvds_backlight_setup(dev); + return; failed: