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

Jani Nikula jani.nikula at linux.intel.com
Thu Jun 21 10:21:55 CEST 2012


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.

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.


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



More information about the Intel-gfx mailing list