From patchwork Mon Feb 22 17:05:06 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 81187 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 o1MH5JZw019024 for ; Mon, 22 Feb 2010 17:05:54 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 820319E7D9; Mon, 22 Feb 2010 09:05:18 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by gabe.freedesktop.org (Postfix) with ESMTP id 57A339E85F for ; Mon, 22 Feb 2010 09:05:14 -0800 (PST) Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o1MH5EMZ018659 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 22 Feb 2010 12:05:14 -0500 Received: from cavan.codon.org.uk (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o1MH5CJW019814 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NO); Mon, 22 Feb 2010 12:05:13 -0500 Received: from lan-nat-pool-bos.redhat.com ([66.187.234.200] helo=localhost.localdomain) by cavan.codon.org.uk with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1NjbiZ-0006Ie-91; Mon, 22 Feb 2010 17:05:11 +0000 From: Matthew Garrett To: intel-gfx@lists.freedesktop.org Date: Mon, 22 Feb 2010 12:05:06 -0500 Message-Id: <1266858306-32609-1-git-send-email-mjg@redhat.com> X-SA-Do-Not-Run: Yes X-SA-Exim-Connect-IP: 66.187.234.200 X-SA-Exim-Mail-From: mjg@redhat.com X-SA-Exim-Scanned: No (on cavan.codon.org.uk); SAEximRunCond expanded to false X-Scanned-By: MIMEDefang 2.67 on 10.5.11.18 Subject: [Intel-gfx] [PATCH] i915: Add native backlight support 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: , MIME-Version: 1.0 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, 22 Feb 2010 17:05:54 +0000 (UTC) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b99b6a8..e77ecc2 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: */ @@ -590,6 +591,7 @@ typedef struct drm_i915_private { int child_dev_num; struct child_device_config *child_dev; struct drm_connector *int_lvds_connector; + 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..d62a05d 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) @@ -149,39 +149,8 @@ struct opregion_asle { 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); + intel_lvds_set_backlight(dev, max * bclp / 255); return 0; } @@ -247,36 +216,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 +239,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 a51573d..9b898c9 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 b1d0acb..56220d4 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,41 +48,160 @@ struct intel_lvds_priv { }; /** + * Returns the maximum level of the backlight duty cycle field. + */ +u32 intel_lvds_get_max_backlight(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + int value; + bool combo; + + 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; + + value = ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; + + if (combo) { + value *= 0xff; + value /= 2; + } + + return value; +} + +/** + * Returns the level of the backlight duty cycle field. + */ +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 (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; + + value = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK; + + 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(). */ -static void intel_lvds_set_backlight(struct drm_device *dev, int level) +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; + } + blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK; I915_WRITE(reg, (blc_pwm_ctl | - (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); + (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); } -/** - * Returns the maximum level of the backlight duty cycle field. - */ -static u32 intel_lvds_get_max_backlight(struct drm_device *dev) +#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); +} + +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; - u32 reg; + struct backlight_properties props; + + props.max_brightness = intel_lvds_get_max_backlight(dev); + props.type = BACKLIGHT_RAW; + 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; + } + dev_priv->backlight->props.brightness = intel_lvds_get_backlight(dev); + return 0; +} - if (IS_IRONLAKE(dev)) - reg = BLC_PWM_PCH_CTL2; - else - reg = BLC_PWM_CTL; +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; +} - return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> - BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; +static void intel_lvds_backlight_destroy(struct drm_device *dev) +{ + return; } +#endif /** * Sets the power state for the panel. @@ -745,6 +865,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) @@ -1156,6 +1278,9 @@ out: /* keep the LVDS connector */ dev_priv->int_lvds_connector = connector; drm_sysfs_connector_add(connector); + + intel_lvds_backlight_setup(dev); + return; failed: