From: Matthew Garrett <mjg59@srcf.ucam.org>
To: Sergio Monteiro Basto <sergio@sergiomb.no-ip.org>
Cc: intel-gfx <intel-gfx@lists.freedesktop.org>
Subject: Re: BACKLIGHT_CONTROL and xrandr
Date: Mon, 12 Apr 2010 18:36:05 +0100 [thread overview]
Message-ID: <20100412173605.GA1544@srcf.ucam.org> (raw)
In-Reply-To: <20100412171920.GB1106@srcf.ucam.org>
On Mon, Apr 12, 2010 at 06:19:20PM +0100, Matthew Garrett wrote:
> Can you give this patch a try? It's not ready for upstream yet, but
> ought to work.
It would, of course, be more useful if I included the patch.
commit bd599ffa48a679679434109ead29fcdf108ccc77
Author: Matthew Garrett <mjg@redhat.com>
Date: Wed Mar 31 16:36:00 2010 -0400
intel: Add native backlight control
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 <linux/io-mapping.h>
+#include <linux/backlight.h>
/* 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 <linux/acpi.h>
+#include <linux/backlight.h>
/* 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:
--
Matthew Garrett | mjg59@srcf.ucam.org
next prev parent reply other threads:[~2010-04-12 17:36 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1270568618.8947.13.camel@segulix>
[not found] ` <1270600597.3611.32.camel@localhost.localdomain>
[not found] ` <1270649792.2455.1.camel@segulix>
[not found] ` <1270691913.3611.59.camel@localhost.localdomain>
[not found] ` <20100408082646.GI8821@zhen-devel.sh.intel.com>
[not found] ` <1270845726.29931.5.camel@segulix>
[not found] ` <q2qdfb03c971004101041k234c9923zfe24804c29a0022c@mail.gmail.com>
[not found] ` <1270952553.14102.35.camel@segulix>
2010-04-12 17:19 ` BACKLIGHT_CONTROL and xrandr Matthew Garrett
2010-04-12 17:36 ` Matthew Garrett [this message]
2010-04-12 19:45 ` Sergio Monteiro Basto
2010-04-12 20:46 ` Matthew Garrett
2010-04-12 20:57 ` Sergio Monteiro Basto
2010-04-12 22:02 ` Matthew Garrett
2010-04-15 20:10 ` Sergio Monteiro Basto
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100412173605.GA1544@srcf.ucam.org \
--to=mjg59@srcf.ucam.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=sergio@sergiomb.no-ip.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.