diff mbox

[4/6] drm/i915/chv: Implement color management

Message ID 1450378678-24296-5-git-send-email-lionel.g.landwerlin@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lionel Landwerlin Dec. 17, 2015, 6:57 p.m. UTC
From: Shashank Sharma <shashank.sharma@intel.com>

Implement degamma, csc and gamma steps on CHV.

Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
---
 drivers/gpu/drm/i915/Makefile              |   3 +-
 drivers/gpu/drm/i915/i915_drv.c            |   5 +-
 drivers/gpu/drm/i915/i915_drv.h            |   2 +
 drivers/gpu/drm/i915/i915_reg.h            |  26 +++
 drivers/gpu/drm/i915/intel_color_manager.c | 353 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_color_manager.h |  91 ++++++++
 drivers/gpu/drm/i915/intel_display.c       |   2 +
 drivers/gpu/drm/i915/intel_drv.h           |   4 +
 8 files changed, 484 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_color_manager.c
 create mode 100644 drivers/gpu/drm/i915/intel_color_manager.h

Comments

Daniel Stone Dec. 18, 2015, 4:53 p.m. UTC | #1
Hi,

On 17 December 2015 at 18:57, Lionel Landwerlin
<lionel.g.landwerlin@intel.com> wrote:
> @@ -311,7 +312,9 @@ static const struct intel_device_info intel_cherryview_info = {
>         .gen = 8, .num_pipes = 3,
>         .need_gfx_hws = 1, .has_hotplug = 1,
>         .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
> -       .is_cherryview = 1,
> +       .is_valleyview = 1,

... ?!

> +       .num_samples_after_ctm = CHV_10BIT_GAMMA_MAX_VALS,
> +       .num_samples_before_ctm = CHV_DEGAMMA_MAX_VALS,

Switch the order of these please.

> +static u16 chv_prepare_csc_coeff(s64 csc_coeff)
> +{
> +       u16 csc_s3_12_format = 0;
> +       u16 csc_int_value;
> +       u16 csc_fract_value;
> +
> +       if (csc_coeff < 0)
> +               csc_s3_12_format = CSC_COEFF_SIGN;
> +       csc_coeff = abs(csc_coeff);
> +       csc_coeff += CHV_CSC_FRACT_ROUNDOFF;
> +       if (csc_coeff > CHV_CSC_COEFF_MAX + 1)
> +               csc_coeff = CHV_CSC_COEFF_MAX + 1;
> +       else if (csc_coeff > CHV_CSC_COEFF_MAX)
> +               csc_coeff = CHV_CSC_COEFF_MAX;
> +
> +       csc_int_value = csc_coeff >> CHV_CSC_COEFF_SHIFT;
> +       csc_int_value <<= CHV_CSC_COEFF_INT_SHIFT;
> +
> +       csc_fract_value = csc_coeff >> CHV_CSC_COEFF_FRACT_SHIFT;
> +
> +       csc_s3_12_format |= csc_int_value | csc_fract_value;

Um. I'm at a loss trying to disentangle these. Here, (1 << 15) /
0x8000 is used as the sign bit; fair enough.

But, anything above 0x7ffffffff generates 0x8000 as a result, which
s3.12 would lead me to read as -7.999...; 0x7ffffffff itself generates
+7.999.... So huge positive numbers wrap around into your minimum
signed value. Is this deliberate? Is it covered by IGT?

> +static int chv_set_csc(struct drm_device *dev, struct drm_property_blob *blob,
> +               struct drm_crtc *crtc)
> +{
> +       u16 temp;
> +       u32 word = 0;
> +       int count = 0;
> +       i915_reg_t val;
> +       struct drm_ctm *csc_data;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       enum pipe pipe;
> +
> +       if (WARN_ON(!blob))
> +               return -EINVAL;

Why not let blob == NULL just disable CSC here? (How do you even disable it?)

> +       if (blob->length != sizeof(struct drm_ctm)) {
> +               DRM_ERROR("Invalid length of data received\n");
> +               return -EINVAL;
> +       }

This needs to be checked earlier (in the atomic_set_property hook):
failing commit is not OK.

> +static int chv_set_degamma(struct drm_device *dev,
> +       struct drm_property_blob *blob, struct drm_crtc *crtc)

What I said about the documentation around post-CTM vs. degamma makes
even more sense now. ;)

> +{
> +       u16 red_fract, green_fract, blue_fract;
> +       u32 red, green, blue;
> +       u32 num_samples;
> +       u32 word = 0;
> +       u32 count, cgm_control, cgm_degamma_reg;
> +       i915_reg_t val;
> +       enum pipe pipe;
> +       struct drm_palette *degamma_data;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct drm_r32g32b32 *correction_values = NULL;
> +       struct drm_crtc_state *state = crtc->state;
> +
> +       if (WARN_ON(!blob))
> +               return -EINVAL;

Same comment as above.

> +       degamma_data = (struct drm_palette *)blob->data;
> +       pipe = to_intel_crtc(crtc)->pipe;
> +       num_samples = blob->length / sizeof(struct drm_r32g32b32);
> +
> +       switch (num_samples) {
> +       case GAMMA_DISABLE_VALS:
> +               /* Disable DeGamma functionality on Pipe - CGM Block */

Just use blob == NULL for this.

> +               val = _MMIO(_PIPE_CGM_CONTROL(pipe));
> +               cgm_control = I915_READ(val);
> +               cgm_control &= ~CGM_DEGAMMA_EN;
> +               state->palette_before_ctm_blob = NULL;

This is really broken. In order to disable, you create a blob with len
== 0, which instantly drops itself without unreferencing, i.e. no
leak.

Also, I thought RMW of registers was frowned upon? Maybe not.

> +       default:
> +               DRM_ERROR("Invalid number of samples for DeGamma LUT\n");
> +               return -EINVAL;
> +       }

This could just become another early-exit path. But again, this needs
to be checked in, well, atomic_check, not commit.

> +static int chv_set_gamma(struct drm_device *dev, struct drm_property_blob *blob,
> +               struct drm_crtc *crtc)
> +{
> +       enum pipe pipe;
> +       u16 red_fract, green_fract, blue_fract;
> +       u32 red, green, blue, num_samples;
> +       u32 word = 0;
> +       u32 count, cgm_gamma_reg, cgm_control;
> +       i915_reg_t val;
> +       struct drm_r32g32b32 *correction_values;
> +       struct drm_palette *gamma_data;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct drm_crtc_state *state = crtc->state;
> +
> +       if (WARN_ON(!blob))
> +               return -EINVAL;

As above.

> +       switch (num_samples) {
> +       case GAMMA_DISABLE_VALS:

Ditto.

> +               /* Disable Gamma functionality on Pipe - CGM Block */
> +               val = _MMIO(_PIPE_CGM_CONTROL(pipe));
> +               cgm_control = I915_READ(val);
> +               cgm_control &= ~CGM_GAMMA_EN;
> +               I915_WRITE(val, cgm_control);
> +               state->palette_after_ctm_blob = NULL;

AOL.

> +       case CHV_8BIT_GAMMA_MAX_VALS:
> +       case CHV_10BIT_GAMMA_MAX_VALS:

Hm. At no point does the following code account for the difference
between these two. What happens if you set once with
10BIT_GAMMA_MAX_VALS followed by once with 8BIT_MAX_VALS? Won't that
break expectation of the second user, because you never wrote to the
257th entry?

Also, this just reads 10 bits out of the values regardless. Has 8-bit
been tested on CHV? It seems like it'd be totally broken, as this just
assumes a 10-bit range regardless.

> +       default:
> +               DRM_ERROR("Invalid number of samples (%u) for Gamma LUT\n",
> +                               num_samples);
> +               return -EINVAL;
> +       }

See previous.

> +void intel_color_manager_commit(struct drm_device *dev,
> +                               struct drm_crtc_state *crtc_state)
> +{
> +       struct drm_property_blob *blob;
> +       struct drm_crtc *crtc = crtc_state->crtc;
> +       int ret = -EINVAL;

Why is this initialised, especially when not actually used as a return value?

> +       blob = crtc_state->palette_after_ctm_blob;
> +       if (blob) {

Drop the conditional and pass it through regardless, so you can use
NULL to disable.

> +               /* Gamma correction is platform specific */
> +               if (IS_CHERRYVIEW(dev))
> +                       ret = chv_set_gamma(dev, blob, crtc);
> +
> +               if (ret)
> +                       DRM_ERROR("set Gamma correction failed\n");
> +               else
> +                       DRM_DEBUG_DRIVER("Gamma correction success\n");
> +       }

So we just error but carry on? Again, this (and all the following)
need to be in check, not commit. And you can just drop the 'success'
message.

> +void intel_crtc_attach_color_properties(struct drm_crtc *crtc)
> +{
> +}

... ?

> +/* Color management bit utilities */
> +#define GET_BIT_MASK(n) ((1 << n) - 1)
> +
> +/* Read bits of a word from bit no. 'start'(lsb) till 'n' bits */
> +#define GET_BITS(x, start, nbits) ((x >> start) & GET_BIT_MASK(nbits))
>
> +/* Round off by adding 1 to the immediate lower bit */
> +#define GET_BITS_ROUNDOFF(x, start, nbits) \
> +       ((GET_BITS(x, start, (nbits + 1)) + 1) >> 1)
> +
> +/* Clear bits of a word from bit no. 'start' till nbits */
> +#define CLEAR_BITS(x, start, nbits) ( \
> +               x &= ~((GET_BIT_MASK(nbits) << start)))
> +
> +/* Write bit_pattern of no_bits bits in a target word */
> +#define SET_BITS(target, bit_pattern, start_bit, no_bits) \
> +               do { \
> +                       CLEAR_BITS(target, start_bit, no_bits); \
> +                       target |= (bit_pattern << start_bit);  \
> +               } while (0)

Is there actually no common set of macros for these? I would also
expect to see this as lowest_bit -> highest_bit, rather than start_bit
-> (start_bit -> start_bit + nbits/no_bits).

> +/* CHV */
> +#define CHV_10BIT_GAMMA_MAX_VALS               257

Delete this, as it's already declared in the 'Gamma on CHV' block.

> +#define CHV_DEGAMMA_MAX_VALS                   65

Move this to that block.

> +/* No of coeff for disabling gamma is 0 */
> +#define GAMMA_DISABLE_VALS                     0

... and delete this.

> +/* Gamma on CHV */
> +#define CHV_10BIT_GAMMA_MAX_VALS               257
> +#define CHV_8BIT_GAMMA_MAX_VALS                256
> +#define CHV_10BIT_GAMMA_MSB_SHIFT              6
> +#define CHV_GAMMA_SHIFT_GREEN                  16
> +#define CHV_MAX_GAMMA                          ((1 << 24) - 1)

Shouldn't drm_palette or similar declare that the range of gamma
values is [0,(1 << 24) -1], or just do some normalisation, rather than
relying on people to know that CHV has a different gamma range than
the type would lead you to believe?

> +/*
> + * CSC values are 64-bit values. For CHV, the maximum CSC value that
> + * user can program is 7.99999..., which can be represented in fixed point
> + * S31.32 format like this, with all fractional bits as 1
> + */

As with (de)gamma, might help to note that CSC is CTM.

Also, this means that the comment I noted in the drm_ctm structure is
wrong: the range really is [0..8.0) rather than [0..1.0].
> +#define CSC_MAX_VALS                           9

Isn't MAX_VALS fixed at 9 everywhere ... ?

> +/* Degamma on CHV */
> +#define CHV_DEGAMMA_MSB_SHIFT                  2
> +#define CHV_DEGAMMA_GREEN_SHIFT                16

Slightly baffling, and also unused ... but what does it mean?

Cheers,
Daniel
Daniel Vetter Dec. 21, 2015, 12:49 p.m. UTC | #2
On Thu, Dec 17, 2015 at 06:57:56PM +0000, Lionel Landwerlin wrote:
> From: Shashank Sharma <shashank.sharma@intel.com>
> 
> Implement degamma, csc and gamma steps on CHV.
> 
> Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
> Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
> ---
>  drivers/gpu/drm/i915/Makefile              |   3 +-
>  drivers/gpu/drm/i915/i915_drv.c            |   5 +-
>  drivers/gpu/drm/i915/i915_drv.h            |   2 +
>  drivers/gpu/drm/i915/i915_reg.h            |  26 +++
>  drivers/gpu/drm/i915/intel_color_manager.c | 353 +++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_color_manager.h |  91 ++++++++
>  drivers/gpu/drm/i915/intel_display.c       |   2 +
>  drivers/gpu/drm/i915/intel_drv.h           |   4 +
>  8 files changed, 484 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_color_manager.c
>  create mode 100644 drivers/gpu/drm/i915/intel_color_manager.h
> 
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 0851de07..c66d56a 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -64,7 +64,8 @@ i915-y += intel_audio.o \
>  	  intel_overlay.o \
>  	  intel_psr.o \
>  	  intel_sideband.o \
> -	  intel_sprite.o
> +	  intel_sprite.o \
> +	  intel_color_manager.o
>  i915-$(CONFIG_ACPI)		+= intel_acpi.o intel_opregion.o
>  i915-$(CONFIG_DRM_FBDEV_EMULATION)	+= intel_fbdev.o
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 3ac616d..4396300 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -34,6 +34,7 @@
>  #include "i915_drv.h"
>  #include "i915_trace.h"
>  #include "intel_drv.h"
> +#include "intel_color_manager.h"
>  
>  #include <linux/console.h>
>  #include <linux/module.h>
> @@ -311,7 +312,9 @@ static const struct intel_device_info intel_cherryview_info = {
>  	.gen = 8, .num_pipes = 3,
>  	.need_gfx_hws = 1, .has_hotplug = 1,
>  	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
> -	.is_cherryview = 1,
> +	.is_valleyview = 1,
> +	.num_samples_after_ctm = CHV_10BIT_GAMMA_MAX_VALS,
> +	.num_samples_before_ctm = CHV_DEGAMMA_MAX_VALS,
>  	.display_mmio_offset = VLV_DISPLAY_BASE,
>  	GEN_CHV_PIPEOFFSETS,
>  	CURSOR_OFFSETS,
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1d28d90..4eb0fab 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -793,6 +793,8 @@ struct intel_device_info {
>  	u8 num_sprites[I915_MAX_PIPES];
>  	u8 gen;
>  	u8 ring_mask; /* Rings supported by the HW */
> +	u16 num_samples_after_ctm;
> +	u16 num_samples_before_ctm;
>  	DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
>  	/* Register offsets for the various display pipes and transcoders */
>  	int pipe_offsets[I915_MAX_TRANSCODERS];
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 007ae83..36bb320 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -8154,4 +8154,30 @@ enum skl_disp_power_wells {
>  #define GEN9_VEBOX_MOCS(i)	_MMIO(0xcb00 + (i) * 4)	/* Video MOCS registers */
>  #define GEN9_BLT_MOCS(i)	_MMIO(0xcc00 + (i) * 4)	/* Blitter MOCS registers */
>  
> +/* Color Management */
> +#define PIPEA_CGM_CONTROL			(VLV_DISPLAY_BASE + 0x67A00)
> +#define PIPEB_CGM_CONTROL			(VLV_DISPLAY_BASE + 0x69A00)
> +#define PIPEC_CGM_CONTROL			(VLV_DISPLAY_BASE + 0x6BA00)
> +#define PIPEA_CGM_GAMMA			(VLV_DISPLAY_BASE + 0x67000)
> +#define PIPEB_CGM_GAMMA			(VLV_DISPLAY_BASE + 0x69000)
> +#define PIPEC_CGM_GAMMA			(VLV_DISPLAY_BASE + 0x6B000)
> +#define _PIPE_CGM_CONTROL(pipe) \
> +	(_PIPE3(pipe, PIPEA_CGM_CONTROL, PIPEB_CGM_CONTROL, PIPEC_CGM_CONTROL))
> +#define _PIPE_GAMMA_BASE(pipe) \
> +	(_PIPE3(pipe, PIPEA_CGM_GAMMA, PIPEB_CGM_GAMMA, PIPEC_CGM_GAMMA))
> +
> +#define PIPEA_CGM_DEGAMMA                      (VLV_DISPLAY_BASE + 0x66000)
> +#define PIPEB_CGM_DEGAMMA                      (VLV_DISPLAY_BASE + 0x68000)
> +#define PIPEC_CGM_DEGAMMA                      (VLV_DISPLAY_BASE + 0x6A000)
> +#define _PIPE_DEGAMMA_BASE(pipe) \
> +	(_PIPE3(pipe, PIPEA_CGM_DEGAMMA, PIPEB_CGM_DEGAMMA, PIPEC_CGM_DEGAMMA))
> +
> +#define PIPEA_CGM_CSC				(VLV_DISPLAY_BASE + 0x67900)
> +#define PIPEB_CGM_CSC				(VLV_DISPLAY_BASE + 0x69900)
> +#define PIPEC_CGM_CSC				(VLV_DISPLAY_BASE + 0x6B900)
> +#define _PIPE_CSC_BASE(pipe) \
> +	(_PIPE3(pipe, PIPEA_CGM_CSC, PIPEB_CGM_CSC, PIPEC_CGM_CSC))
> +
> +
> +
>  #endif /* _I915_REG_H_ */
> diff --git a/drivers/gpu/drm/i915/intel_color_manager.c b/drivers/gpu/drm/i915/intel_color_manager.c
> new file mode 100644
> index 0000000..02eee98
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_color_manager.c
> @@ -0,0 +1,353 @@
> +/*
> + * Copyright © 2015 Intel Corporation
> + *
> + * 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, sublicense,
> + * 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 NONINFRINGEMENT.  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.
> + *
> + * Authors:
> + * Shashank Sharma <shashank.sharma@intel.com>
> + * Kausal Malladi <Kausal.Malladi@intel.com>
> + */
> +
> +#include "intel_color_manager.h"
> +
> +static u16 chv_prepare_csc_coeff(s64 csc_coeff)
> +{
> +	u16 csc_s3_12_format = 0;
> +	u16 csc_int_value;
> +	u16 csc_fract_value;
> +
> +	if (csc_coeff < 0)
> +		csc_s3_12_format = CSC_COEFF_SIGN;
> +	csc_coeff = abs(csc_coeff);
> +	csc_coeff += CHV_CSC_FRACT_ROUNDOFF;
> +	if (csc_coeff > CHV_CSC_COEFF_MAX + 1)
> +		csc_coeff = CHV_CSC_COEFF_MAX + 1;
> +	else if (csc_coeff > CHV_CSC_COEFF_MAX)
> +		csc_coeff = CHV_CSC_COEFF_MAX;
> +
> +	csc_int_value = csc_coeff >> CHV_CSC_COEFF_SHIFT;
> +	csc_int_value <<= CHV_CSC_COEFF_INT_SHIFT;
> +
> +	csc_fract_value = csc_coeff >> CHV_CSC_COEFF_FRACT_SHIFT;
> +
> +	csc_s3_12_format |= csc_int_value | csc_fract_value;
> +
> +	return csc_s3_12_format;
> +}
> +
> +static int chv_set_csc(struct drm_device *dev, struct drm_property_blob *blob,
> +		struct drm_crtc *crtc)
> +{
> +	u16 temp;
> +	u32 word = 0;
> +	int count = 0;
> +	i915_reg_t val;
> +	struct drm_ctm *csc_data;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	enum pipe pipe;
> +
> +	if (WARN_ON(!blob))
> +		return -EINVAL;
> +
> +	if (blob->length != sizeof(struct drm_ctm)) {
> +		DRM_ERROR("Invalid length of data received\n");
> +		return -EINVAL;
> +	}
> +
> +	csc_data = (struct drm_ctm *)blob->data;
> +	pipe = to_intel_crtc(crtc)->pipe;
> +
> +	/* Disable CSC functionality */
> +	val = _MMIO(_PIPE_CGM_CONTROL(pipe));
> +	I915_WRITE(val, I915_READ(val) & (~CGM_CSC_EN));
> +
> +	DRM_DEBUG_DRIVER("Disabled CSC Functionality on Pipe %c\n",
> +			pipe_name(pipe));
> +
> +	val = _MMIO(_PIPE_CSC_BASE(pipe));
> +
> +	/*
> +	* First 8 of 9 CSC correction values go in pair, to first
> +	* 4 CSC register (bit 0:15 and 16:31)
> +	*/
> +	while (count < CSC_MAX_VALS - 1) {
> +		temp = chv_prepare_csc_coeff(
> +					csc_data->ctm_coeff[count]);
> +		SET_BITS(word, temp, 0, 16);
> +		count++;
> +
> +		temp = chv_prepare_csc_coeff(
> +				csc_data->ctm_coeff[count]);
> +		SET_BITS(word, temp, 16, 16);
> +		count++;
> +
> +		I915_WRITE(val, word);
> +		val.reg += 4;
> +	}
> +
> +	/* 9th coeff goes to 5th register, bit 0:16 */
> +	temp = chv_prepare_csc_coeff(
> +			csc_data->ctm_coeff[count]);
> +	SET_BITS(word, temp, 0, 16);
> +	I915_WRITE(val, word);
> +
> +	/* Enable CSC functionality */
> +	val = _MMIO(_PIPE_CGM_CONTROL(pipe));
> +	I915_WRITE(val, I915_READ(val) | CGM_CSC_EN);
> +	DRM_DEBUG_DRIVER("CSC enabled on Pipe %c\n", pipe_name(pipe));
> +	return 0;
> +}
> +
> +static int chv_set_degamma(struct drm_device *dev,
> +	struct drm_property_blob *blob, struct drm_crtc *crtc)
> +{
> +	u16 red_fract, green_fract, blue_fract;
> +	u32 red, green, blue;
> +	u32 num_samples;
> +	u32 word = 0;
> +	u32 count, cgm_control, cgm_degamma_reg;
> +	i915_reg_t val;
> +	enum pipe pipe;
> +	struct drm_palette *degamma_data;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct drm_r32g32b32 *correction_values = NULL;
> +	struct drm_crtc_state *state = crtc->state;
> +
> +	if (WARN_ON(!blob))
> +		return -EINVAL;
> +
> +	degamma_data = (struct drm_palette *)blob->data;
> +	pipe = to_intel_crtc(crtc)->pipe;
> +	num_samples = blob->length / sizeof(struct drm_r32g32b32);
> +
> +	switch (num_samples) {
> +	case GAMMA_DISABLE_VALS:

If we implement my suggestion for a num_samples helper, we could put the
NULL->0 samples logic into that one and nicely unify things. And probably
we should also reject a gamma table with size 0 as nonsens then.

> +		/* Disable DeGamma functionality on Pipe - CGM Block */
> +		val = _MMIO(_PIPE_CGM_CONTROL(pipe));
> +		cgm_control = I915_READ(val);
> +		cgm_control &= ~CGM_DEGAMMA_EN;
> +		state->palette_before_ctm_blob = NULL;
> +
> +		I915_WRITE(val, cgm_control);
> +		DRM_DEBUG_DRIVER("DeGamma disabled on Pipe %c\n",
> +				pipe_name(pipe));
> +		break;
> +
> +	case CHV_DEGAMMA_MAX_VALS:
> +		cgm_degamma_reg = _PIPE_DEGAMMA_BASE(pipe);
> +		count = 0;
> +		correction_values = degamma_data->lut;
> +		while (count < CHV_DEGAMMA_MAX_VALS) {
> +			blue = correction_values[count].b32;
> +			green = correction_values[count].g32;
> +			red = correction_values[count].r32;
> +
> +			if (blue > CHV_MAX_GAMMA)
> +				blue = CHV_MAX_GAMMA;
> +
> +			if (green > CHV_MAX_GAMMA)
> +				green = CHV_MAX_GAMMA;
> +
> +			if (red > CHV_MAX_GAMMA)
> +				red = CHV_MAX_GAMMA;
> +
> +			blue_fract = GET_BITS(blue, 10, 14);
> +			green_fract = GET_BITS(green, 10, 14);
> +			red_fract = GET_BITS(red, 10, 14);
> +
> +			/* Green (29:16) and Blue (13:0) in DWORD1 */
> +			SET_BITS(word, green_fract, 16, 14);
> +			SET_BITS(word, blue_fract, 0, 14);
> +			val = _MMIO(cgm_degamma_reg);
> +			I915_WRITE(val, word);
> +			cgm_degamma_reg += 4;
> +
> +			/* Red (13:0) to be written to DWORD2 */
> +			word = red_fract;
> +			val = _MMIO(cgm_degamma_reg);
> +			I915_WRITE(val, word);
> +			cgm_degamma_reg += 4;
> +			count++;
> +		}
> +
> +		DRM_DEBUG_DRIVER("DeGamma LUT loaded for Pipe %c\n",
> +				pipe_name(pipe));
> +
> +		/* Enable DeGamma on Pipe */
> +		val = _MMIO(_PIPE_CGM_CONTROL(pipe));
> +		I915_WRITE(val, I915_READ(val) | CGM_DEGAMMA_EN);
> +		DRM_DEBUG_DRIVER("DeGamma correction enabled on Pipe %c\n",
> +				pipe_name(pipe));
> +		break;
> +
> +	default:
> +		DRM_ERROR("Invalid number of samples for DeGamma LUT\n");
> +		return -EINVAL;

This is a relict from pre-atomic and won't work anymore: There's no way to
pass error code from _commit functions up to userspace, and there's also
no way to abort an atomic commit at that stage. Input validation must
happen in atomic_check callbacks (or compute_config, as we tend to call
them in i915 itself).
-Daniel
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0851de07..c66d56a 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -64,7 +64,8 @@  i915-y += intel_audio.o \
 	  intel_overlay.o \
 	  intel_psr.o \
 	  intel_sideband.o \
-	  intel_sprite.o
+	  intel_sprite.o \
+	  intel_color_manager.o
 i915-$(CONFIG_ACPI)		+= intel_acpi.o intel_opregion.o
 i915-$(CONFIG_DRM_FBDEV_EMULATION)	+= intel_fbdev.o
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 3ac616d..4396300 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -34,6 +34,7 @@ 
 #include "i915_drv.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
+#include "intel_color_manager.h"
 
 #include <linux/console.h>
 #include <linux/module.h>
@@ -311,7 +312,9 @@  static const struct intel_device_info intel_cherryview_info = {
 	.gen = 8, .num_pipes = 3,
 	.need_gfx_hws = 1, .has_hotplug = 1,
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
-	.is_cherryview = 1,
+	.is_valleyview = 1,
+	.num_samples_after_ctm = CHV_10BIT_GAMMA_MAX_VALS,
+	.num_samples_before_ctm = CHV_DEGAMMA_MAX_VALS,
 	.display_mmio_offset = VLV_DISPLAY_BASE,
 	GEN_CHV_PIPEOFFSETS,
 	CURSOR_OFFSETS,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1d28d90..4eb0fab 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -793,6 +793,8 @@  struct intel_device_info {
 	u8 num_sprites[I915_MAX_PIPES];
 	u8 gen;
 	u8 ring_mask; /* Rings supported by the HW */
+	u16 num_samples_after_ctm;
+	u16 num_samples_before_ctm;
 	DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
 	/* Register offsets for the various display pipes and transcoders */
 	int pipe_offsets[I915_MAX_TRANSCODERS];
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 007ae83..36bb320 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -8154,4 +8154,30 @@  enum skl_disp_power_wells {
 #define GEN9_VEBOX_MOCS(i)	_MMIO(0xcb00 + (i) * 4)	/* Video MOCS registers */
 #define GEN9_BLT_MOCS(i)	_MMIO(0xcc00 + (i) * 4)	/* Blitter MOCS registers */
 
+/* Color Management */
+#define PIPEA_CGM_CONTROL			(VLV_DISPLAY_BASE + 0x67A00)
+#define PIPEB_CGM_CONTROL			(VLV_DISPLAY_BASE + 0x69A00)
+#define PIPEC_CGM_CONTROL			(VLV_DISPLAY_BASE + 0x6BA00)
+#define PIPEA_CGM_GAMMA			(VLV_DISPLAY_BASE + 0x67000)
+#define PIPEB_CGM_GAMMA			(VLV_DISPLAY_BASE + 0x69000)
+#define PIPEC_CGM_GAMMA			(VLV_DISPLAY_BASE + 0x6B000)
+#define _PIPE_CGM_CONTROL(pipe) \
+	(_PIPE3(pipe, PIPEA_CGM_CONTROL, PIPEB_CGM_CONTROL, PIPEC_CGM_CONTROL))
+#define _PIPE_GAMMA_BASE(pipe) \
+	(_PIPE3(pipe, PIPEA_CGM_GAMMA, PIPEB_CGM_GAMMA, PIPEC_CGM_GAMMA))
+
+#define PIPEA_CGM_DEGAMMA                      (VLV_DISPLAY_BASE + 0x66000)
+#define PIPEB_CGM_DEGAMMA                      (VLV_DISPLAY_BASE + 0x68000)
+#define PIPEC_CGM_DEGAMMA                      (VLV_DISPLAY_BASE + 0x6A000)
+#define _PIPE_DEGAMMA_BASE(pipe) \
+	(_PIPE3(pipe, PIPEA_CGM_DEGAMMA, PIPEB_CGM_DEGAMMA, PIPEC_CGM_DEGAMMA))
+
+#define PIPEA_CGM_CSC				(VLV_DISPLAY_BASE + 0x67900)
+#define PIPEB_CGM_CSC				(VLV_DISPLAY_BASE + 0x69900)
+#define PIPEC_CGM_CSC				(VLV_DISPLAY_BASE + 0x6B900)
+#define _PIPE_CSC_BASE(pipe) \
+	(_PIPE3(pipe, PIPEA_CGM_CSC, PIPEB_CGM_CSC, PIPEC_CGM_CSC))
+
+
+
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/intel_color_manager.c b/drivers/gpu/drm/i915/intel_color_manager.c
new file mode 100644
index 0000000..02eee98
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_color_manager.c
@@ -0,0 +1,353 @@ 
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * 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, sublicense,
+ * 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 NONINFRINGEMENT.  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.
+ *
+ * Authors:
+ * Shashank Sharma <shashank.sharma@intel.com>
+ * Kausal Malladi <Kausal.Malladi@intel.com>
+ */
+
+#include "intel_color_manager.h"
+
+static u16 chv_prepare_csc_coeff(s64 csc_coeff)
+{
+	u16 csc_s3_12_format = 0;
+	u16 csc_int_value;
+	u16 csc_fract_value;
+
+	if (csc_coeff < 0)
+		csc_s3_12_format = CSC_COEFF_SIGN;
+	csc_coeff = abs(csc_coeff);
+	csc_coeff += CHV_CSC_FRACT_ROUNDOFF;
+	if (csc_coeff > CHV_CSC_COEFF_MAX + 1)
+		csc_coeff = CHV_CSC_COEFF_MAX + 1;
+	else if (csc_coeff > CHV_CSC_COEFF_MAX)
+		csc_coeff = CHV_CSC_COEFF_MAX;
+
+	csc_int_value = csc_coeff >> CHV_CSC_COEFF_SHIFT;
+	csc_int_value <<= CHV_CSC_COEFF_INT_SHIFT;
+
+	csc_fract_value = csc_coeff >> CHV_CSC_COEFF_FRACT_SHIFT;
+
+	csc_s3_12_format |= csc_int_value | csc_fract_value;
+
+	return csc_s3_12_format;
+}
+
+static int chv_set_csc(struct drm_device *dev, struct drm_property_blob *blob,
+		struct drm_crtc *crtc)
+{
+	u16 temp;
+	u32 word = 0;
+	int count = 0;
+	i915_reg_t val;
+	struct drm_ctm *csc_data;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum pipe pipe;
+
+	if (WARN_ON(!blob))
+		return -EINVAL;
+
+	if (blob->length != sizeof(struct drm_ctm)) {
+		DRM_ERROR("Invalid length of data received\n");
+		return -EINVAL;
+	}
+
+	csc_data = (struct drm_ctm *)blob->data;
+	pipe = to_intel_crtc(crtc)->pipe;
+
+	/* Disable CSC functionality */
+	val = _MMIO(_PIPE_CGM_CONTROL(pipe));
+	I915_WRITE(val, I915_READ(val) & (~CGM_CSC_EN));
+
+	DRM_DEBUG_DRIVER("Disabled CSC Functionality on Pipe %c\n",
+			pipe_name(pipe));
+
+	val = _MMIO(_PIPE_CSC_BASE(pipe));
+
+	/*
+	* First 8 of 9 CSC correction values go in pair, to first
+	* 4 CSC register (bit 0:15 and 16:31)
+	*/
+	while (count < CSC_MAX_VALS - 1) {
+		temp = chv_prepare_csc_coeff(
+					csc_data->ctm_coeff[count]);
+		SET_BITS(word, temp, 0, 16);
+		count++;
+
+		temp = chv_prepare_csc_coeff(
+				csc_data->ctm_coeff[count]);
+		SET_BITS(word, temp, 16, 16);
+		count++;
+
+		I915_WRITE(val, word);
+		val.reg += 4;
+	}
+
+	/* 9th coeff goes to 5th register, bit 0:16 */
+	temp = chv_prepare_csc_coeff(
+			csc_data->ctm_coeff[count]);
+	SET_BITS(word, temp, 0, 16);
+	I915_WRITE(val, word);
+
+	/* Enable CSC functionality */
+	val = _MMIO(_PIPE_CGM_CONTROL(pipe));
+	I915_WRITE(val, I915_READ(val) | CGM_CSC_EN);
+	DRM_DEBUG_DRIVER("CSC enabled on Pipe %c\n", pipe_name(pipe));
+	return 0;
+}
+
+static int chv_set_degamma(struct drm_device *dev,
+	struct drm_property_blob *blob, struct drm_crtc *crtc)
+{
+	u16 red_fract, green_fract, blue_fract;
+	u32 red, green, blue;
+	u32 num_samples;
+	u32 word = 0;
+	u32 count, cgm_control, cgm_degamma_reg;
+	i915_reg_t val;
+	enum pipe pipe;
+	struct drm_palette *degamma_data;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_r32g32b32 *correction_values = NULL;
+	struct drm_crtc_state *state = crtc->state;
+
+	if (WARN_ON(!blob))
+		return -EINVAL;
+
+	degamma_data = (struct drm_palette *)blob->data;
+	pipe = to_intel_crtc(crtc)->pipe;
+	num_samples = blob->length / sizeof(struct drm_r32g32b32);
+
+	switch (num_samples) {
+	case GAMMA_DISABLE_VALS:
+		/* Disable DeGamma functionality on Pipe - CGM Block */
+		val = _MMIO(_PIPE_CGM_CONTROL(pipe));
+		cgm_control = I915_READ(val);
+		cgm_control &= ~CGM_DEGAMMA_EN;
+		state->palette_before_ctm_blob = NULL;
+
+		I915_WRITE(val, cgm_control);
+		DRM_DEBUG_DRIVER("DeGamma disabled on Pipe %c\n",
+				pipe_name(pipe));
+		break;
+
+	case CHV_DEGAMMA_MAX_VALS:
+		cgm_degamma_reg = _PIPE_DEGAMMA_BASE(pipe);
+		count = 0;
+		correction_values = degamma_data->lut;
+		while (count < CHV_DEGAMMA_MAX_VALS) {
+			blue = correction_values[count].b32;
+			green = correction_values[count].g32;
+			red = correction_values[count].r32;
+
+			if (blue > CHV_MAX_GAMMA)
+				blue = CHV_MAX_GAMMA;
+
+			if (green > CHV_MAX_GAMMA)
+				green = CHV_MAX_GAMMA;
+
+			if (red > CHV_MAX_GAMMA)
+				red = CHV_MAX_GAMMA;
+
+			blue_fract = GET_BITS(blue, 10, 14);
+			green_fract = GET_BITS(green, 10, 14);
+			red_fract = GET_BITS(red, 10, 14);
+
+			/* Green (29:16) and Blue (13:0) in DWORD1 */
+			SET_BITS(word, green_fract, 16, 14);
+			SET_BITS(word, blue_fract, 0, 14);
+			val = _MMIO(cgm_degamma_reg);
+			I915_WRITE(val, word);
+			cgm_degamma_reg += 4;
+
+			/* Red (13:0) to be written to DWORD2 */
+			word = red_fract;
+			val = _MMIO(cgm_degamma_reg);
+			I915_WRITE(val, word);
+			cgm_degamma_reg += 4;
+			count++;
+		}
+
+		DRM_DEBUG_DRIVER("DeGamma LUT loaded for Pipe %c\n",
+				pipe_name(pipe));
+
+		/* Enable DeGamma on Pipe */
+		val = _MMIO(_PIPE_CGM_CONTROL(pipe));
+		I915_WRITE(val, I915_READ(val) | CGM_DEGAMMA_EN);
+		DRM_DEBUG_DRIVER("DeGamma correction enabled on Pipe %c\n",
+				pipe_name(pipe));
+		break;
+
+	default:
+		DRM_ERROR("Invalid number of samples for DeGamma LUT\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int chv_set_gamma(struct drm_device *dev, struct drm_property_blob *blob,
+		struct drm_crtc *crtc)
+{
+	enum pipe pipe;
+	u16 red_fract, green_fract, blue_fract;
+	u32 red, green, blue, num_samples;
+	u32 word = 0;
+	u32 count, cgm_gamma_reg, cgm_control;
+	i915_reg_t val;
+	struct drm_r32g32b32 *correction_values;
+	struct drm_palette *gamma_data;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc_state *state = crtc->state;
+
+	if (WARN_ON(!blob))
+		return -EINVAL;
+
+	gamma_data = (struct drm_palette *)blob->data;
+	pipe = to_intel_crtc(crtc)->pipe;
+	num_samples = blob->length / sizeof(struct drm_r32g32b32);
+
+	switch (num_samples) {
+	case GAMMA_DISABLE_VALS:
+
+		/* Disable Gamma functionality on Pipe - CGM Block */
+		val = _MMIO(_PIPE_CGM_CONTROL(pipe));
+		cgm_control = I915_READ(val);
+		cgm_control &= ~CGM_GAMMA_EN;
+		I915_WRITE(val, cgm_control);
+		state->palette_after_ctm_blob = NULL;
+		DRM_DEBUG_DRIVER("Gamma disabled on Pipe %c\n",
+			pipe_name(pipe));
+		return 0;
+
+	case CHV_8BIT_GAMMA_MAX_VALS:
+	case CHV_10BIT_GAMMA_MAX_VALS:
+
+		count = 0;
+		cgm_gamma_reg = _PIPE_GAMMA_BASE(pipe);
+		correction_values = gamma_data->lut;
+
+		while (count < num_samples) {
+			blue = correction_values[count].b32;
+			green = correction_values[count].g32;
+			red = correction_values[count].r32;
+
+			if (blue > CHV_MAX_GAMMA)
+				blue = CHV_MAX_GAMMA;
+
+			if (green > CHV_MAX_GAMMA)
+				green = CHV_MAX_GAMMA;
+
+			if (red > CHV_MAX_GAMMA)
+				red = CHV_MAX_GAMMA;
+
+			/* get MSB 10 bits from fraction part (14:23) */
+			blue_fract = GET_BITS(blue, 14, 10);
+			green_fract = GET_BITS(green, 14, 10);
+			red_fract = GET_BITS(red, 14, 10);
+
+			/* Green (25:16) and Blue (9:0) to be written */
+			SET_BITS(word, green_fract, 16, 10);
+			SET_BITS(word, blue_fract, 0, 10);
+			val = _MMIO(cgm_gamma_reg);
+			I915_WRITE(val, word);
+			cgm_gamma_reg += 4;
+
+			/* Red (9:0) to be written */
+			word = red_fract;
+			val = _MMIO(cgm_gamma_reg);
+			I915_WRITE(val, word);
+			cgm_gamma_reg += 4;
+			count++;
+		}
+
+		/* Enable (CGM) Gamma on Pipe */
+		val = _MMIO(_PIPE_CGM_CONTROL(pipe));
+		I915_WRITE(val, I915_READ(val) | CGM_GAMMA_EN);
+		DRM_DEBUG_DRIVER("CGM Gamma enabled on Pipe %c\n",
+			pipe_name(pipe));
+		return 0;
+
+	default:
+		DRM_ERROR("Invalid number of samples (%u) for Gamma LUT\n",
+				num_samples);
+		return -EINVAL;
+	}
+}
+
+void intel_color_manager_commit(struct drm_device *dev,
+				struct drm_crtc_state *crtc_state)
+{
+	struct drm_property_blob *blob;
+	struct drm_crtc *crtc = crtc_state->crtc;
+	int ret = -EINVAL;
+
+	/*
+	* CRTC level color correction, once applied on the
+	* pipe, goes on forever, until disabled, so there is no
+	* need to program all those correction registers on every
+	* commit. Do this only when a new correction applied.
+	*/
+	if (!crtc_state->color_correction_changed)
+		return;
+
+	blob = crtc_state->palette_after_ctm_blob;
+	if (blob) {
+		/* Gamma correction is platform specific */
+		if (IS_CHERRYVIEW(dev))
+			ret = chv_set_gamma(dev, blob, crtc);
+
+		if (ret)
+			DRM_ERROR("set Gamma correction failed\n");
+		else
+			DRM_DEBUG_DRIVER("Gamma correction success\n");
+	}
+
+	blob = crtc_state->palette_before_ctm_blob;
+	if (blob) {
+		/* Degamma correction */
+		if (IS_CHERRYVIEW(dev))
+			ret = chv_set_degamma(dev, blob, crtc);
+
+		if (ret)
+			DRM_ERROR("set degamma correction failed\n");
+		else
+			DRM_DEBUG_DRIVER("degamma correction success\n");
+	}
+
+	blob = crtc_state->ctm_blob;
+	if (blob) {
+		/* CSC correction */
+		if (IS_CHERRYVIEW(dev))
+			ret = chv_set_csc(dev, blob, crtc);
+
+		if (ret)
+			DRM_ERROR("set CSC correction failed\n");
+		else
+			DRM_DEBUG_DRIVER("CSC correction success\n");
+	}
+
+	crtc_state->color_correction_changed = false;
+}
+
+void intel_crtc_attach_color_properties(struct drm_crtc *crtc)
+{
+}
diff --git a/drivers/gpu/drm/i915/intel_color_manager.h b/drivers/gpu/drm/i915/intel_color_manager.h
new file mode 100644
index 0000000..04185ac
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_color_manager.h
@@ -0,0 +1,91 @@ 
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * 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, sublicense,
+ * 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 NONINFRINGEMENT.  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.
+ *
+ * Authors:
+ * Shashank Sharma <shashank.sharma@intel.com>
+ * Kausal Malladi <Kausal.Malladi@intel.com>
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include "i915_drv.h"
+
+/* Color management bit utilities */
+#define GET_BIT_MASK(n) ((1 << n) - 1)
+
+/* Read bits of a word from bit no. 'start'(lsb) till 'n' bits */
+#define GET_BITS(x, start, nbits) ((x >> start) & GET_BIT_MASK(nbits))
+
+/* Round off by adding 1 to the immediate lower bit */
+#define GET_BITS_ROUNDOFF(x, start, nbits) \
+	((GET_BITS(x, start, (nbits + 1)) + 1) >> 1)
+
+/* Clear bits of a word from bit no. 'start' till nbits */
+#define CLEAR_BITS(x, start, nbits) ( \
+		x &= ~((GET_BIT_MASK(nbits) << start)))
+
+/* Write bit_pattern of no_bits bits in a target word */
+#define SET_BITS(target, bit_pattern, start_bit, no_bits) \
+		do { \
+			CLEAR_BITS(target, start_bit, no_bits); \
+			target |= (bit_pattern << start_bit);  \
+		} while (0)
+
+/* CHV */
+#define CHV_10BIT_GAMMA_MAX_VALS		257
+#define CHV_DEGAMMA_MAX_VALS                   65
+
+/* No of coeff for disabling gamma is 0 */
+#define GAMMA_DISABLE_VALS			0
+
+/* Gamma on CHV */
+#define CHV_10BIT_GAMMA_MAX_VALS               257
+#define CHV_8BIT_GAMMA_MAX_VALS                256
+#define CHV_10BIT_GAMMA_MSB_SHIFT              6
+#define CHV_GAMMA_SHIFT_GREEN                  16
+#define CHV_MAX_GAMMA                          ((1 << 24) - 1)
+
+/*
+ * CSC on CHV
+ * Fractional part is 32 bit, and we need only 12 MSBs for programming
+ * into registers. ROUNDOFF is required to minimize loss of precision.
+ */
+#define CHV_CSC_FRACT_ROUNDOFF                 (1 << 19)
+/*
+ * CSC values are 64-bit values. For CHV, the maximum CSC value that
+ * user can program is 7.99999..., which can be represented in fixed point
+ * S31.32 format like this, with all fractional bits as 1
+ */
+#define CHV_CSC_COEFF_MAX                      0x00000007FFFFFFFF
+#define CHV_CSC_COEFF_SHIFT                    32
+#define CHV_CSC_COEFF_INT_SHIFT                12
+#define CSC_COEFF_SIGN                         (1 << 15)
+#define CHV_CSC_COEFF_FRACT_SHIFT              20
+#define CSC_MAX_VALS                           9
+
+/* Degamma on CHV */
+#define CHV_DEGAMMA_MSB_SHIFT                  2
+#define CHV_DEGAMMA_GREEN_SHIFT                16
+
+/* CHV CGM Block */
+#define CGM_GAMMA_EN                           (1 << 2)
+#define CGM_CSC_EN                             (1 << 1)
+#define CGM_DEGAMMA_EN                         (1 << 0)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a05ba28..b9eb507 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13940,6 +13940,8 @@  static void intel_begin_crtc_commit(struct drm_crtc *crtc,
 		intel_update_pipe_config(intel_crtc, old_intel_state);
 	else if (INTEL_INFO(dev)->gen >= 9)
 		skl_detach_scalers(intel_crtc);
+
+	intel_color_manager_commit(dev, crtc->state);
 }
 
 static void intel_finish_crtc_commit(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d523ebb..2ee655a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1604,4 +1604,8 @@  void intel_plane_destroy_state(struct drm_plane *plane,
 			       struct drm_plane_state *state);
 extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
 
+/* intel_color_manager.c */
+void intel_crtc_attach_color_properties(struct drm_crtc *crtc);
+void intel_color_manager_commit(struct drm_device *dev,
+				struct drm_crtc_state *crtc_state);
 #endif /* __INTEL_DRV_H__ */