On Thu, Jun 21, 2012 at 1:21 AM, Jani Nikula <jani.nikula at linux.intel.com>wrote: > On Thu, 21 Jun 2012, St?phane Marchesin <marcheu at chromium.org> wrote: > > This is an initial implementation of i915 adaptive backlight support. > > The intended use for the adaptive backlight is to generate interrupts > > whenever the luminance of the screen changes by some thresholds. The > > main caveat with that implementation is that those additional > > interrupts will wake up the CPU and consume more power. Instead, we > > hook into the vblank handler and handle it from there. This makes the > > implementation a little less intuitive but a lot more efficient. > > We also need to compute the gamma correction from the interrupt > > handler so we do this with a (new) fixed point module. > > Hi St?phane, interesting work. > > My understanding is that content adaptive backlight control is basically > a function that tries to reduce backlight brightness to save power while > adjusting gamma to ensure there is no user detectable change in > image. Like this: > > (reduced_brightness, gamma) = f(brightness, luminance) > > In my view, the histogram information, interrupt on its meaningful > change, brightness and gamma setting are clearly mechanisms the driver > should provide. I'm not at all sure if the function that defines the > policy for brightness and gamma changes should be part of the driver. > > Yes, I don't like it either, but the problem is that if we want fast response time we have to do it from the irq handler, or at least the kernel. > In fact, looking at the histogram_find_correction_level() and > adaptive_backlight_compute_correction() functions below, they are filled > with policy conditions. Usually it's preferred to have the policy in > user space. The fixed point troubles would all go away as well in user > space. And there's the added benefit of being able to handle the user's > desired brightness and possible ambient light sensor based adjustment to > brightness in a single point of truth. > > I guess the question is how to define sensible interfaces to the > mechanisms in a way that the adaptive backlight function is feasible to > implement in user space, and the power saving goal could still be > reached. I would at least like this to be looked into first. > > The issue is that if you have to wake up a user space process every time you want to recompute the backlight, you're going to offset the backlight savings with some CPU losses. I wanted to avoid that. St?phane > > BR, > Jani. > > > > > > > > Change-Id: I9b9631cacc7d90e2801a542a3789118521bc25f0 > > Signed-off-by: St?phane Marchesin <marcheu at chromium.org> > > --- > > drivers/gpu/drm/i915/Makefile | 1 + > > drivers/gpu/drm/i915/i915_dma.c | 16 ++ > > drivers/gpu/drm/i915/i915_drv.h | 10 + > > drivers/gpu/drm/i915/i915_irq.c | 8 +- > > drivers/gpu/drm/i915/i915_reg.h | 22 ++ > > drivers/gpu/drm/i915/intel_adaptive_backlight.c | 266 > +++++++++++++++++++++++ > > drivers/gpu/drm/i915/intel_fixedpoint.h | 140 ++++++++++++ > > drivers/gpu/drm/i915/intel_panel.c | 6 + > > include/drm/i915_drm.h | 2 + > > 9 files changed, 469 insertions(+), 2 deletions(-) > > create mode 100644 drivers/gpu/drm/i915/intel_adaptive_backlight.c > > create mode 100644 drivers/gpu/drm/i915/intel_fixedpoint.h > > > > diff --git a/drivers/gpu/drm/i915/Makefile > b/drivers/gpu/drm/i915/Makefile > > index ce7fc77..5c125c3 100644 > > --- a/drivers/gpu/drm/i915/Makefile > > +++ b/drivers/gpu/drm/i915/Makefile > > @@ -13,6 +13,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ > > i915_gem_gtt.o \ > > i915_gem_tiling.o \ > > i915_trace_points.o \ > > + intel_adaptive_backlight.o \ > > intel_display.o \ > > intel_crt.o \ > > intel_lvds.o \ > > diff --git a/drivers/gpu/drm/i915/i915_dma.c > b/drivers/gpu/drm/i915/i915_dma.c > > index ba60f3c..c2626d6 100644 > > --- a/drivers/gpu/drm/i915/i915_dma.c > > +++ b/drivers/gpu/drm/i915/i915_dma.c > > @@ -828,6 +828,22 @@ static int i915_setparam(struct drm_device *dev, > void *data, > > /* Userspace can use first N regs */ > > dev_priv->fence_reg_start = param->value; > > break; > > + case I915_SETPARAM_ADAPTIVE_BACKLIGHT_ENABLE: > > + if (INTEL_INFO(dev)->gen == 6) { > > + dev_priv->adaptive_backlight_enabled = > param->value; > > + } else { > > + DRM_ERROR("No adaptive backlight on !GEN6\n"); > > + return -EINVAL; > > + } > > + break; > > + case I915_SETPARAM_PANEL_GAMMA: > > + if (INTEL_INFO(dev)->gen == 6) { > > + dev_priv->adaptive_backlight_panel_gamma = > param->value; > > + } else { > > + DRM_ERROR("No adaptive backlight on !GEN6\n"); > > + return -EINVAL; > > + } > > + break; > > default: > > DRM_DEBUG_DRIVER("unknown parameter %d\n", > > param->param); > > diff --git a/drivers/gpu/drm/i915/i915_drv.h > b/drivers/gpu/drm/i915/i915_drv.h > > index d89f585..f778f93 100644 > > --- a/drivers/gpu/drm/i915/i915_drv.h > > +++ b/drivers/gpu/drm/i915/i915_drv.h > > @@ -401,6 +401,13 @@ typedef struct drm_i915_private { > > struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ > > struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ > > > > + /* Adaptive backlight */ > > + bool adaptive_backlight_enabled; > > + int backlight_correction_level; > > + int backlight_correction_count; > > + int backlight_correction_direction; > > + int adaptive_backlight_panel_gamma; > > + > > /* Feature bits from the VBIOS */ > > unsigned int int_tv_support:1; > > unsigned int lvds_dither:1; > > @@ -1358,6 +1365,9 @@ extern int i915_restore_state(struct drm_device > *dev); > > extern int i915_save_state(struct drm_device *dev); > > extern int i915_restore_state(struct drm_device *dev); > > > > +/* intel_adaptive_backlight.c */ > > +extern void intel_adaptive_backlight(struct drm_device *dev, int pipe); > > + > > /* intel_i2c.c */ > > extern int intel_setup_gmbus(struct drm_device *dev); > > extern void intel_teardown_gmbus(struct drm_device *dev); > > diff --git a/drivers/gpu/drm/i915/i915_irq.c > b/drivers/gpu/drm/i915/i915_irq.c > > index afd4e03..948da6b 100644 > > --- a/drivers/gpu/drm/i915/i915_irq.c > > +++ b/drivers/gpu/drm/i915/i915_irq.c > > @@ -619,11 +619,15 @@ static irqreturn_t > ironlake_irq_handler(DRM_IRQ_ARGS) > > intel_finish_page_flip_plane(dev, 1); > > } > > > > - if (de_iir & DE_PIPEA_VBLANK) > > + if (de_iir & DE_PIPEA_VBLANK) { > > drm_handle_vblank(dev, 0); > > + intel_adaptive_backlight(dev, 0); > > + } > > > > - if (de_iir & DE_PIPEB_VBLANK) > > + if (de_iir & DE_PIPEB_VBLANK) { > > drm_handle_vblank(dev, 1); > > + intel_adaptive_backlight(dev, 1); > > + } > > > > /* check event from PCH */ > > if (de_iir & DE_PCH_EVENT) { > > diff --git a/drivers/gpu/drm/i915/i915_reg.h > b/drivers/gpu/drm/i915/i915_reg.h > > index 552264c..2db874d 100644 > > --- a/drivers/gpu/drm/i915/i915_reg.h > > +++ b/drivers/gpu/drm/i915/i915_reg.h > > @@ -3587,6 +3587,28 @@ > > #define PWM_PIPE_B (1 << 29) > > #define BLC_PWM_CPU_CTL 0x48254 > > > > +#define BLM_HIST_CTL 0x48260 > > +#define ENH_HIST_ENABLE (1<<31) > > +#define ENH_MODIF_TBL_ENABLE (1<<30) > > +#define ENH_PIPE_A_SELECT (0<<29) > > +#define ENH_PIPE_B_SELECT (1<<29) > > +#define ENH_PIPE(pipe) _PIPE(pipe, ENH_PIPE_A_SELECT, > ENH_PIPE_B_SELECT) > > +#define HIST_MODE_YUV (0<<24) > > +#define HIST_MODE_HSV (1<<24) > > +#define ENH_MODE_DIRECT (0<<13) > > +#define ENH_MODE_ADDITIVE (1<<13) > > +#define ENH_MODE_MULTIPLICATIVE (2<<13) > > +#define BIN_REGISTER_SET (1<<11) > > +#define ENH_NUM_BINS 32 > > + > > +#define BLM_HIST_ENH 0x48264 > > + > > +#define BLM_HIST_GUARD_BAND 0x48268 > > +#define BLM_HIST_INTR_ENABLE (1<<31) > > +#define BLM_HIST_EVENT_STATUS (1<<30) > > +#define BLM_HIST_INTR_DELAY_MASK (0xFF<<22) > > +#define BLM_HIST_INTR_DELAY_SHIFT 22 > > + > > #define BLC_PWM_PCH_CTL1 0xc8250 > > #define PWM_PCH_ENABLE (1 << 31) > > #define PWM_POLARITY_ACTIVE_LOW (1 << 29) > > diff --git a/drivers/gpu/drm/i915/intel_adaptive_backlight.c > b/drivers/gpu/drm/i915/intel_adaptive_backlight.c > > new file mode 100644 > > index 0000000..4234962 > > --- /dev/null > > +++ b/drivers/gpu/drm/i915/intel_adaptive_backlight.c > > @@ -0,0 +1,266 @@ > > +/* > > + * Copyright 2012 The Chromium OS Authors. > > + * All Rights Reserved. > > + * > > + * Permission is hereby granted, free of charge, to any person > obtaining a > > + * copy of this software and associated documentation files (the > > + * "Software"), to deal in the Software without restriction, including > > + * without limitation the rights to use, copy, modify, merge, publish, > > + * distribute, sub license, and/or sell copies of the Software, and to > > + * permit persons to whom the Software is furnished to do so, subject to > > + * the following conditions: > > + * > > + * The above copyright notice and this permission notice (including the > > + * next paragraph) shall be included in all copies or substantial > portions > > + * of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS > > + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > > + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND > NON-INFRINGEMENT. > > + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR > > + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF > CONTRACT, > > + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE > > + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. > > + * > > + */ > > + > > + > > +#include "drmP.h" > > +#include "drm.h" > > +#include "i915_drm.h" > > +#include "i915_drv.h" > > +#include "i915_reg.h" > > +#include "intel_drv.h" > > +#include "intel_fixedpoint.h" > > + > > +/* > > + * This function takes a histogram of buckets as input and determines an > > + * acceptable target backlight level. > > + */ > > +static int histogram_find_correction_level(int *levels) > > +{ > > + int i, sum = 0; > > + int ratio, distortion, prev_distortion = 0, off, final_ratio, > target; > > + > > + for (i = 0; i < ENH_NUM_BINS; i++) > > + sum += levels[i]; > > + > > + /* Allow 0.33/256 distortion per pixel, on average */ > > + target = sum / 3; > > + > > + /* Special case where we only have less than 100 pixels > > + * outside of the darkest bin. > > + */ > > + if (sum - levels[0] <= 100) > > + return 70; > > + > > + for (ratio = ENH_NUM_BINS - 1; ratio >= 0 ; ratio--) { > > + distortion = 0; > > + for (i = ratio; i < ENH_NUM_BINS; i++) { > > + int pixel_distortion = (i - ratio)*8; > > + int num_pixels = levels[i]; > > + distortion += num_pixels * pixel_distortion; > > + } > > + if (distortion > target) > > + break; > > + else > > + prev_distortion = distortion; > > + } > > + > > + ratio++; > > + > > + /* If we're not exactly at the border between two buckets, > extrapolate > > + * to get 3 extra bits of accuracy. > > + */ > > + if (distortion - prev_distortion) > > + off = 8 * (target - prev_distortion) / > > + (distortion - prev_distortion); > > + else > > + off = 0; > > + > > + final_ratio = ratio * 255 / 31 + off; > > + > > + if (final_ratio > 255) > > + final_ratio = 255; > > + > > + /* Never aim for less than 50% of the total backlight */ > > + if (final_ratio < 128) > > + final_ratio = 128; > > + > > + return final_ratio; > > +} > > + > > +static void histogram_get_levels(struct drm_device *dev, int pipe, int > *levels) > > +{ > > + drm_i915_private_t *dev_priv = dev->dev_private; > > + int i; > > + > > + for (i = 0; i < ENH_NUM_BINS; i++) { > > + I915_WRITE(BLM_HIST_CTL, ENH_HIST_ENABLE | > > + ENH_MODIF_TBL_ENABLE | > > + ENH_PIPE(pipe) | > > + HIST_MODE_YUV | > > + ENH_MODE_ADDITIVE | > > + i); > > + levels[i] = I915_READ(BLM_HIST_ENH); > > + } > > +} > > + > > +static void histogram_set_levels(struct drm_device *dev, int pipe, int > *levels) > > +{ > > + drm_i915_private_t *dev_priv = dev->dev_private; > > + int i; > > + > > + for (i = 0; i < ENH_NUM_BINS; i++) { > > + I915_WRITE(BLM_HIST_CTL, ENH_HIST_ENABLE | > > + ENH_MODIF_TBL_ENABLE | > > + ENH_PIPE(pipe) | > > + HIST_MODE_YUV | > > + ENH_MODE_ADDITIVE | > > + BIN_REGISTER_SET | > > + i); > > + I915_WRITE(BLM_HIST_ENH, levels[i]); > > + } > > +} > > + > > +/* > > + * This function computes the backlight correction level for an > acceptable > > + * distortion and fills up the correction bins adequately. > > + */ > > +static void > > +adaptive_backlight_compute_correction(struct drm_device *dev, int > *levels) > > +{ > > + drm_i915_private_t *dev_priv = dev->dev_private; > > + int correction_level; > > + int i, multiplier, one_over_gamma; > > + > > + /* Find the correction level for an acceptable distortion */ > > + correction_level = histogram_find_correction_level(levels); > > + > > + /* If we're not yet at our correction target, we need to decide by > how > > + * much to move. > > + */ > > + if (dev_priv->backlight_correction_level != correction_level) { > > + int delta, direction; > > + > > + direction = (correction_level > > > + dev_priv->backlight_correction_level); > > + > > + if (direction == dev_priv->backlight_correction_direction) > { > > + dev_priv->backlight_correction_count++; > > + } else { > > + dev_priv->backlight_correction_count = 0; > > + dev_priv->backlight_correction_direction = > direction; > > + } > > + > > + delta = abs(correction_level - > > + dev_priv->backlight_correction_level)/4; > > + > > + if (delta < 1) > > + delta = 1; > > + > > + /* For increasing the brightness, we do it instantly. > > + * For lowering the brightness, we require at least 10 > frames > > + * below the current value. This avoids ping-ponging of the > > + * backlight level. > > + * > > + * We also never increase the backlight by more than 6% per > > + * frame, and never lower it by more than 3% per frame, > because > > + * the backlight needs time to adjust and the LCD > correction > > + * would be "ahead" otherwise. > > + */ > > + if (correction_level > > dev_priv->backlight_correction_level) { > > + if (delta > 15) > > + delta = 15; > > + dev_priv->backlight_correction_level += delta; > > + } else if ((dev_priv->backlight_correction_count > 10) && > > + (correction_level < > dev_priv->backlight_correction_level)) { > > + if (delta > 7) > > + delta = 7; > > + dev_priv->backlight_correction_level -= delta; > > + } > > + } > > + > > + /* We need to invert the gamma correction of the LCD values, > > + * but not of the backlight which is linear. > > + */ > > + one_over_gamma = intel_fixed_div(FIXED_ONE, > > + dev_priv->adaptive_backlight_panel_gamma); > > + multiplier = intel_fixed_pow(dev_priv->backlight_correction_level > * 256, > > + one_over_gamma); > > + > > + for (i = 0; i < ENH_NUM_BINS; i++) { > > + int base_value = i * 8 * 4; > > + levels[i] = base_value - base_value * multiplier / 65536; > > + } > > +} > > + > > +/* > > + * A quick note about the adaptive backlight implementation: > > + * If we let it run as designed, it will generate a lot of interrupts > which > > + * tends to wake the CPU up and waste power. This is a bad idea for a > power > > + * saving feature. Instead, we couple it to the vblank interrupt since > that > > + * means we drew something. This means that we do not react to > non-vsynced GL > > + * updates, or updates to the front buffer, and also adds a little bit > of > > + * extra latency. But it is an acceptable tradeoff to make. > > + */ > > +void intel_adaptive_backlight(struct drm_device *dev, int > pipe_vblank_event) > > +{ > > + drm_i915_private_t *dev_priv = dev->dev_private; > > + int levels[ENH_NUM_BINS]; > > + int pipe; > > + struct drm_connector *connector; > > + struct intel_crtc *intel_crtc; > > + > > + if (!dev_priv->adaptive_backlight_enabled) > > + return; > > + > > + /* Find the connector */ > > + if (dev_priv->int_lvds_connector) > > + connector = dev_priv->int_lvds_connector; > > + else if (dev_priv->int_edp_connector) > > + connector = dev_priv->int_edp_connector; > > + else > > + return; > > + > > + if (!connector) > > + return; > > + > > + if (!connector->encoder) > > + return; > > + > > + if (!connector->encoder->crtc) > > + return; > > + > > + /* Find the pipe for the panel. */ > > + intel_crtc = to_intel_crtc(connector->encoder->crtc); > > + pipe = intel_crtc->pipe; > > + > > + /* The callback happens for both pipe A & B. Now that we know which > > + * pipe we're doing adaptive backlight on, check that it's the > right > > + * one. Bail if it isn't. > > + */ > > + if (pipe != pipe_vblank_event) > > + return; > > + > > + /* Return if no event. */ > > + if (I915_READ(BLM_HIST_GUARD_BAND) & BLM_HIST_EVENT_STATUS == 0) > > + return; > > + > > + /* Make sure we ack the previous event. Even though we do not get > the > > + * IRQs (see above explanation), we must still ack the events > otherwise > > + * the histogram data doesn't get updated any more. > > + */ > > + I915_WRITE(BLM_HIST_GUARD_BAND, BLM_HIST_INTR_ENABLE | > > + BLM_HIST_EVENT_STATUS | > > + (1 << BLM_HIST_INTR_DELAY_SHIFT)); > > + > > + histogram_get_levels(dev, pipe, levels); > > + > > + adaptive_backlight_compute_correction(dev, levels); > > + > > + histogram_set_levels(dev, pipe, levels); > > + > > + intel_panel_set_backlight(dev, dev_priv->backlight_level); > > +} > > + > > diff --git a/drivers/gpu/drm/i915/intel_fixedpoint.h > b/drivers/gpu/drm/i915/intel_fixedpoint.h > > new file mode 100644 > > index 0000000..fff5f0b > > --- /dev/null > > +++ b/drivers/gpu/drm/i915/intel_fixedpoint.h > > @@ -0,0 +1,140 @@ > > +/* > > + * Copyright 2012 The Chromium OS Authors. > > + * All Rights Reserved. > > + * > > + * Permission is hereby granted, free of charge, to any person > obtaining a > > + * copy of this software and associated documentation files (the > > + * "Software"), to deal in the Software without restriction, including > > + * without limitation the rights to use, copy, modify, merge, publish, > > + * distribute, sub license, and/or sell copies of the Software, and to > > + * permit persons to whom the Software is furnished to do so, subject to > > + * the following conditions: > > + * > > + * The above copyright notice and this permission notice (including the > > + * next paragraph) shall be included in all copies or substantial > portions > > + * of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS > > + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > > + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND > NON-INFRINGEMENT. > > + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR > > + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF > CONTRACT, > > + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE > > + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. > > + * > > + */ > > + > > +/* > > + * The backlight is corrected in linear space. However the LCD > correction is > > + * corrected in gama space. So to be able to compute the correction > value for > > + * the LCD, we have to compute the inverse gamma. To do so, we carry > this > > + * small fixed point module which allows us to use pow() to compute > inverse > > + * gamma. > > + * > > + * The fixed point format used here is 16.16. > > + */ > > + > > +/* intel_fixed_exp_tbl[x*32] = exp(x) * 65536 */ > > +static const int intel_fixed_exp_tbl[33] = { > > +0x00010000, 0x00010820, 0x00011083, 0x00011929, 0x00012216, 0x00012b4b, > > +0x000134cc, 0x00013e99, 0x000148b6, 0x00015325, 0x00015de9, 0x00016905, > > +0x0001747a, 0x0001804d, 0x00018c80, 0x00019916, 0x0001a613, 0x0001b378, > > +0x0001c14b, 0x0001cf8e, 0x0001de45, 0x0001ed74, 0x0001fd1e, 0x00020d47, > > +0x00021df4, 0x00022f28, 0x000240e8, 0x00025338, 0x0002661d, 0x0002799b, > > +0x00028db8, 0x0002a278, 0x0002b7e1 > > +}; > > + > > +/* intel_fixed_log_tbl[x*32] = log(x) * 65536 */ > > +static const int intel_fixed_log_tbl[33] = { > > +0x80000000, 0xfffc88c6, 0xfffd3a38, 0xfffda204, 0xfffdebaa, 0xfffe24ca, > > +0xfffe5376, 0xfffe7aed, 0xfffe9d1c, 0xfffebb43, 0xfffed63c, 0xfffeeea2, > > +0xffff04e8, 0xffff1966, 0xffff2c5f, 0xffff3e08, 0xffff4e8e, 0xffff5e13, > > +0xffff6cb5, 0xffff7a8c, 0xffff87ae, 0xffff942b, 0xffffa014, 0xffffab75, > > +0xffffb65a, 0xffffc0ce, 0xffffcad8, 0xffffd481, 0xffffddd1, 0xffffe6cd, > > +0xffffef7a, 0xfffff7df, 0xffffffff > > +}; > > + > > +/* e * 65536 */ > > +#define FIXED_E (intel_fixed_exp_tbl[32]) > > +/* 1 * 65536 */ > > +#define FIXED_ONE 65536 > > + > > +static int intel_fixed_mul(int a, int b) > > +{ > > + return (int) ((int64_t)a * (int64_t)b / 65536LL); > > +} > > + > > +static int intel_fixed_div(int a, int b) > > +{ > > + return (int) ((int64_t)a * 65536LL / (int64_t)b); > > +} > > + > > +/* > > + * Approximate fixed point log function. > > + * Only works for inputs in [0,1[ > > + */ > > +static int intel_fixed_log(int val) > > +{ > > + int index = val * 32 / FIXED_ONE; > > + int remainder = (val & 0x7ff) << 5; > > + int v1 = intel_fixed_log_tbl[index]; > > + int v2 = intel_fixed_log_tbl[index+1]; > > + int final = v1 + intel_fixed_mul(v2 - v1, remainder); > > + return final; > > +} > > + > > +/* > > + * Approximate fixed point exp function. > > + */ > > +static int intel_fixed_exp(int val) > > +{ > > + int count = 0; > > + int index, remainder; > > + int int_part = FIXED_ONE, frac_part; > > + int i, v, v1, v2; > > + > > + while (val < 0) { > > + val += FIXED_ONE; > > + count--; > > + } > > + > > + while (val > FIXED_ONE) { > > + val -= FIXED_ONE; > > + count++; > > + } > > + > > + index = val * 32 / FIXED_ONE; > > + remainder = (val & 0x7ff) << 5; > > + > > + v1 = intel_fixed_exp_tbl[index]; > > + v2 = intel_fixed_exp_tbl[index+1]; > > + frac_part = v1 + intel_fixed_mul(v2 - v1, remainder); > > + > > + if (count < 0) { > > + for (i = 0; i < -count; i++) > > + int_part = intel_fixed_mul(int_part, FIXED_E); > > + > > + v = intel_fixed_div(frac_part, int_part); > > + } else { > > + for (i = 0; i < count; i++) > > + int_part = intel_fixed_mul(int_part, FIXED_E); > > + > > + v = intel_fixed_mul(frac_part, int_part); > > + } > > + return (v >= 0) ? v : 0; > > +} > > + > > +/* > > + * Approximate fixed point pow function. > > + * Only works for x in [0,1[ > > + */ > > +static int intel_fixed_pow(int x, int y) > > +{ > > + int e, p, r; > > + e = intel_fixed_log(x); > > + p = intel_fixed_mul(e, y); > > + r = intel_fixed_exp(p); > > + return r; > > +} > > + > > + > > diff --git a/drivers/gpu/drm/i915/intel_panel.c > b/drivers/gpu/drm/i915/intel_panel.c > > index 3f9249b..ae95163 100644 > > --- a/drivers/gpu/drm/i915/intel_panel.c > > +++ b/drivers/gpu/drm/i915/intel_panel.c > > @@ -251,6 +251,8 @@ static void > intel_panel_actually_set_backlight(struct drm_device *dev, u32 level > > struct drm_i915_private *dev_priv = dev->dev_private; > > u32 tmp; > > > > + level = level * dev_priv->backlight_correction_level >> 8; > > + > > DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); > > > > if (HAS_PCH_SPLIT(dev)) > > @@ -306,6 +308,10 @@ static void intel_panel_init_backlight(struct > drm_device *dev) > > > > dev_priv->backlight_level = intel_panel_get_backlight(dev); > > dev_priv->backlight_enabled = dev_priv->backlight_level != 0; > > + dev_priv->adaptive_backlight_enabled = 0; > > + /* 2.2 as 16.16 fixed point */ > > + dev_priv->adaptive_backlight_panel_gamma = 144179; > > + dev_priv->backlight_correction_level = 256; > > } > > > > enum drm_connector_status > > diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h > > index da929bb..70c9cfc 100644 > > --- a/include/drm/i915_drm.h > > +++ b/include/drm/i915_drm.h > > @@ -309,6 +309,8 @@ typedef struct drm_i915_getparam { > > #define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2 > > #define I915_SETPARAM_ALLOW_BATCHBUFFER 3 > > #define I915_SETPARAM_NUM_USED_FENCES 4 > > +#define I915_SETPARAM_ADAPTIVE_BACKLIGHT_ENABLE 5 > > +#define I915_SETPARAM_PANEL_GAMMA 6 > > > > typedef struct drm_i915_setparam { > > int param; > > -- > > 1.7.5.3.367.ga9930 > > > > _______________________________________________ > > Intel-gfx mailing list > > Intel-gfx at lists.freedesktop.org > > http://lists.freedesktop.org/mailman/listinfo/intel-gfx > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.freedesktop.org/archives/intel-gfx/attachments/20120621/ff300dd7/attachment-0001.html>