From patchwork Tue Jun 22 23:58:27 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bryan Freed X-Patchwork-Id: 107557 Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o5N7MWhI001393 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Wed, 23 Jun 2010 07:23:08 GMT Received: from localhost ([127.0.0.1] helo=sfs-ml-2.v29.ch3.sourceforge.com) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1ORKGu-0001Cr-4Z; Wed, 23 Jun 2010 07:21:20 +0000 Received: from sfi-mx-4.v28.ch3.sourceforge.com ([172.29.28.124] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1ORDMx-0002Vq-Nn for dri-devel@lists.sourceforge.net; Tue, 22 Jun 2010 23:59:07 +0000 Received-SPF: pass (sfi-mx-4.v28.ch3.sourceforge.com: domain of google.com designates 74.125.121.35 as permitted sender) client-ip=74.125.121.35; envelope-from=bfreed@google.com; helo=smtp-out.google.com; Received: from smtp-out.google.com ([74.125.121.35]) by sfi-mx-4.v28.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.69) id 1ORDMv-0007rh-36 for dri-devel@lists.sourceforge.net; Tue, 22 Jun 2010 23:59:07 +0000 Received: from kpbe19.cbf.corp.google.com (kpbe19.cbf.corp.google.com [172.25.105.83]) by smtp-out.google.com with ESMTP id o5MNwZcx029031; Tue, 22 Jun 2010 16:58:35 -0700 Received: from bstar.mtv.corp.google.com (bstar.mtv.corp.google.com [172.22.72.32]) by kpbe19.cbf.corp.google.com with ESMTP id o5MNwVTq030193; Tue, 22 Jun 2010 16:58:31 -0700 Received: by bstar.mtv.corp.google.com (Postfix, from userid 103270) id 4DC1984AB9; Tue, 22 Jun 2010 16:58:31 -0700 (PDT) From: Bryan Freed To: airlied@linux.ie Subject: [PATCH] Implement direct pineview backlight control. Date: Tue, 22 Jun 2010 16:58:27 -0700 Message-Id: <1277251107-24828-1-git-send-email-bfreed@chromium.org> X-Mailer: git-send-email 1.7.0.1 X-System-Of-Record: true X-Spam-Score: -1.5 (-) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -1.5 SPF_CHECK_PASS SPF reports sender host as permitted sender for sender-domain -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1ORDMv-0007rh-36 X-Mailman-Approved-At: Wed, 23 Jun 2010 07:21:19 +0000 Cc: mateusz.kaduk@gmail.com, Bryan Freed , linux-kernel@vger.kernel.org, jbarnes@virtuousgeek.org, apw@canonical.com, airlied@redhat.com, dri-devel@lists.sourceforge.net, ben@decadent.org.uk, bgamari.foss@gmail.com X-BeenThere: dri-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.sourceforge.net X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 23 Jun 2010 07:23:09 +0000 (UTC) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 305c590..14e21c3 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -124,6 +124,18 @@ config DRM_I915_KMS the driver to bind to PCI devices, which precludes loading things like intelfb. +config DRM_I915_DIRECT_BACKLIGHT + bool "Enable direct backlight control" + depends on DRM_I915 + help + Choose this option if you want the i915 driver to provide direct + backlight control via /sys/class/backlight/i915_backlight. This + is in addition to the ACPI interface (which may also be in that + directory) that uses ASLE (ACPI Source Language Events) events to + get to i915_opregion.c code. + Direct backlight control gives finer granularity (0-256) than ACPI + and does not require BIOS support. + endchoice config DRM_MGA diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 9929f84..a2d6c52 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -31,5 +31,6 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ i915-$(CONFIG_ACPI) += i915_opregion.o i915-$(CONFIG_COMPAT) += i915_ioc32.o +i915-$(CONFIG_DRM_I915_DIRECT_BACKLIGHT) += i915_backlight.o obj-$(CONFIG_DRM_I915) += i915.o diff --git a/drivers/gpu/drm/i915/i915_backlight.c b/drivers/gpu/drm/i915/i915_backlight.c new file mode 100644 index 0000000..18e33e7 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_backlight.c @@ -0,0 +1,120 @@ +/* + * i915_backlight.c - ChromeOS specific backlight support for pineview + * + * + * Copyright (C) 2010 ChromeOS contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "drmP.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* + * Somewhat arbitrarily choose a max brightness level of 256 (as full "on") + * and a PWM frequency of 0x1000. The frequency can be as high as 0x7fff, + * but we do not need that level of flexibility. + */ +#define MAX_BRIGHTNESS 256 +#define PWM_FREQUENCY 0x1000 + +/* + * The Pineview LVDS Backlight PWM Control register is a 32 bit word split + * into two unsigned 16 bit words: the high order short is the cycle frequency, + * and the low order word is the duty cycle. According to i915_opregion.c, + * the low order bit of each short is unused. + * + * While the frequency is hardcoded, these macros provide masking and shifting + * for the duty cycle. + */ +#define CTL_TO_PWM(ctl) ((ctl & BACKLIGHT_DUTY_CYCLE_MASK) >> 1) +#define PWM_TO_CTL(pwm) ((pwm << 1) & BACKLIGHT_DUTY_CYCLE_MASK) + +static int i915_get_intensity(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + struct drm_i915_private *dev_priv = dev->dev_private; + u32 blc_pwm_ctl; + int level, pwm_val; + + blc_pwm_ctl = I915_READ(BLC_PWM_CTL); + pwm_val = CTL_TO_PWM(blc_pwm_ctl); + level = (pwm_val * MAX_BRIGHTNESS) / PWM_FREQUENCY; + + return level; +} + +static int i915_set_intensity(struct backlight_device *bd) +{ + struct drm_device *dev = bl_get_data(bd); + struct drm_i915_private *dev_priv = dev->dev_private; + int level, pwm_val; + u32 blc_pwm_ctl; + + level = bd->props.brightness; + if (level > MAX_BRIGHTNESS) + level = MAX_BRIGHTNESS; + + pwm_val = (level * PWM_FREQUENCY) / MAX_BRIGHTNESS; + blc_pwm_ctl = (PWM_FREQUENCY << BACKLIGHT_MODULATION_FREQ_SHIFT) | + PWM_TO_CTL(pwm_val); + I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl); + + return 0; +} + +static struct backlight_ops i915_bl_ops = { + .get_brightness = i915_get_intensity, + .update_status = i915_set_intensity, +}; + +void i915_backlight_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct backlight_device *bd; + + if (!IS_PINEVIEW(dev)) { + dev_printk(KERN_WARNING, &dev->pdev->dev, + "i915_backlight_init only supports the pineview version\n"); + return; + } + + bd = backlight_device_register("i915_backlight", + &dev->pdev->dev, dev, &i915_bl_ops); + if (IS_ERR(bd)) { + dev_printk(KERN_WARNING, &dev->pdev->dev, + "Unable to register i915 backlight.\n"); + return; + } + + dev_priv->backlight = bd; + bd->props.max_brightness = MAX_BRIGHTNESS; + bd->props.brightness = 0; + backlight_update_status(bd); + return; +} + +void i915_backlight_exit(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->backlight) { + backlight_device_unregister(dev_priv->backlight); + dev_priv->backlight = NULL; + } +} diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b24e814..fe4d41c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1504,6 +1504,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); + + i915_backlight_init(dev); + return 0; out_workqueue_free: @@ -1523,6 +1526,8 @@ int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + i915_backlight_exit(dev); + destroy_workqueue(dev_priv->wq); del_timer_sync(&dev_priv->hangcheck_timer); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b99b6a8..6c82752 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -34,6 +34,10 @@ #include "intel_bios.h" #include +#ifdef CONFIG_DRM_I915_DIRECT_BACKLIGHT +#include +#endif + /* General customization: */ @@ -590,6 +594,12 @@ typedef struct drm_i915_private { int child_dev_num; struct child_device_config *child_dev; struct drm_connector *int_lvds_connector; + +#ifdef CONFIG_DRM_I915_DIRECT_BACKLIGHT + /* direct backlight interface */ + struct backlight_device *backlight; +#endif + } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ @@ -939,6 +949,15 @@ static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; static inline void opregion_enable_asle(struct drm_device *dev) { return; } #endif +#ifdef CONFIG_DRM_I915_DIRECT_BACKLIGHT +/* i915_backlight.c */ +extern void i915_backlight_init(struct drm_device *dev); +extern void i915_backlight_exit(struct drm_device *dev); +#else +extern inline void i915_backlight_init(struct drm_device *dev) { return; } +extern inline void i915_backlight_exit(struct drm_device *dev) { return; } +#endif + /* modesetting */ extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev);