[Intel-gfx] [PATCH] drm/i915: Adaptive backlight support

Daniel Vetter daniel at ffwll.ch
Thu Jun 21 11:34:02 CEST 2012


On Wed, Jun 20, 2012 at 03:12:35PM -0700, Stéphane Marchesin 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.
> 
> Change-Id: I9b9631cacc7d90e2801a542a3789118521bc25f0
> Signed-off-by: Stéphane Marchesin <marcheu at chromium.org>

A few quick comments:
- I don't like setparam for this too much. Imo exposing this as an
  lvds/eDP connector property makes more sense, and also makes the feature
  more accessible to mere mortals. btw I think we should do the same with
  the downclock stuff and expose a panel_downclock_freq plus a
  panel_downclock enable which is simply initialized at driver load time
  with the defaults, but could be freely changed afterwards.
- With connector properties we could also expose tuneables in an easy way,
  at least partially addressing Jani's comment (like the display gamma and
  maybe also other parameters).
- We need to somehow cope with front-rendering X. Yeah, I know this sucks
  and all, but such is life. We already mark framebuffers as busys when
  rendering into them directly, I guess we could hook into to that either
  disable this feature until the next pageflip. Or switch to a different
  mode. The disable needs to be gradually, obviously.
- I'm unsure whether we shouldn't move the fixed-point stuff to a common
  place. Wrt all the fixed-point constant I think a little macro to
  convert double to 16.16 fixed point would massively help code
  readability.

Yours, Daniel

> ---
>  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

-- 
Daniel Vetter
Mail: daniel at ffwll.ch
Mobile: +41 (0)79 365 57 48



More information about the Intel-gfx mailing list