All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH 5/6] drm/i915: Implement color management on bdw/skl/bxt/kbl
Date: Fri, 22 Jan 2016 12:12:11 +0000	[thread overview]
Message-ID: <1453464732-17241-6-git-send-email-lionel.g.landwerlin@intel.com> (raw)
In-Reply-To: <1453464732-17241-1-git-send-email-lionel.g.landwerlin@intel.com>

v2: do not read GAMMA_MODE register to figure what mode we're in

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.c      |  24 ++-
 drivers/gpu/drm/i915/i915_drv.h      |   9 +
 drivers/gpu/drm/i915/i915_reg.h      |  22 +++
 drivers/gpu/drm/i915/intel_color.c   | 355 ++++++++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_display.c |  22 ++-
 drivers/gpu/drm/i915/intel_drv.h     |   6 +-
 6 files changed, 379 insertions(+), 59 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 706b8ea..1978fe5 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -63,6 +63,9 @@ static struct drm_driver driver;
 #define IVB_CURSOR_OFFSETS \
 	.cursor_offsets = { CURSOR_A_OFFSET, IVB_CURSOR_B_OFFSET, IVB_CURSOR_C_OFFSET }
 
+#define BDW_COLORS \
+	.color = { .degamma_lut_size = 512, .gamma_lut_size = 512 }
+
 static const struct intel_device_info intel_i830_info = {
 	.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
 	.has_overlay = 1, .overlay_needs_physical = 1,
@@ -285,24 +288,28 @@ static const struct intel_device_info intel_haswell_m_info = {
 	.is_mobile = 1,
 };
 
+#define BDW_FEATURES \
+	HSW_FEATURES, \
+	BDW_COLORS
+
 static const struct intel_device_info intel_broadwell_d_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.gen = 8,
 };
 
 static const struct intel_device_info intel_broadwell_m_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.gen = 8, .is_mobile = 1,
 };
 
 static const struct intel_device_info intel_broadwell_gt3d_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.gen = 8,
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
 };
 
 static const struct intel_device_info intel_broadwell_gt3m_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.gen = 8, .is_mobile = 1,
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
 };
@@ -318,13 +325,13 @@ static const struct intel_device_info intel_cherryview_info = {
 };
 
 static const struct intel_device_info intel_skylake_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.is_skylake = 1,
 	.gen = 9,
 };
 
 static const struct intel_device_info intel_skylake_gt3_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.is_skylake = 1,
 	.gen = 9,
 	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
@@ -342,17 +349,18 @@ static const struct intel_device_info intel_broxton_info = {
 	.has_fbc = 1,
 	GEN_DEFAULT_PIPEOFFSETS,
 	IVB_CURSOR_OFFSETS,
+	BDW_COLORS,
 };
 
 static const struct intel_device_info intel_kabylake_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.is_preliminary = 1,
 	.is_kabylake = 1,
 	.gen = 9,
 };
 
 static const struct intel_device_info intel_kabylake_gt3_info = {
-	HSW_FEATURES,
+	BDW_FEATURES,
 	.is_preliminary = 1,
 	.is_kabylake = 1,
 	.gen = 9,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 204661f..4a38b15 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -659,6 +659,10 @@ struct drm_i915_display_funcs {
 	/* render clock increase/decrease */
 	/* display clock increase/decrease */
 	/* pll clock increase/decrease */
+
+	void (*load_degamma_lut)(struct drm_crtc *crtc);
+	void (*load_csc_matrix)(struct drm_crtc *crtc);
+	void (*load_gamma_lut)(struct drm_crtc *crtc);
 };
 
 enum forcewake_domain_id {
@@ -806,6 +810,11 @@ struct intel_device_info {
 	u8 has_slice_pg:1;
 	u8 has_subslice_pg:1;
 	u8 has_eu_pg:1;
+
+	struct color_luts {
+		u16 degamma_lut_size;
+		u16 gamma_lut_size;
+	} color;
 };
 
 #undef DEFINE_FLAG
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 46143f8..ccbcf63 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7637,6 +7637,28 @@ enum skl_disp_power_wells {
 #define PIPE_CSC_POSTOFF_ME(pipe)	_MMIO_PIPE3(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME, _PIPE_C_CSC_POSTOFF_ME)
 #define PIPE_CSC_POSTOFF_LO(pipe)	_MMIO_PIPE3(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO, _PIPE_C_CSC_POSTOFF_LO)
 
+/* pipe degamma/gamma LUTs on IVB+ */
+#define _PAL_PREC_INDEX_A	0x4A400
+#define _PAL_PREC_INDEX_B	0x4AC00
+#define _PAL_PREC_INDEX_C	0x4B400
+#define   PAL_PREC_10_12_BIT		(0 << 31)
+#define   PAL_PREC_SPLIT_MODE		(1 << 31)
+#define   PAL_PREC_AUTO_INCREMENT	(1 << 15)
+#define _PAL_PREC_DATA_A	0x4A404
+#define _PAL_PREC_DATA_B	0x4AC04
+#define _PAL_PREC_DATA_C	0x4B404
+#define _PAL_PREC_GC_MAX_A	0x4A410
+#define _PAL_PREC_GC_MAX_B	0x4AC10
+#define _PAL_PREC_GC_MAX_C	0x4B410
+#define _PAL_PREC_EXT_GC_MAX_A	0x4A420
+#define _PAL_PREC_EXT_GC_MAX_B	0x4AC20
+#define _PAL_PREC_EXT_GC_MAX_C	0x4B420
+
+#define PREC_PAL_INDEX(pipe)		_MMIO_PIPE3(pipe, _PAL_PREC_INDEX_A, _PAL_PREC_INDEX_B, _PAL_PREC_INDEX_C)
+#define PREC_PAL_DATA(pipe)		_MMIO_PIPE3(pipe, _PAL_PREC_DATA_A, _PAL_PREC_DATA_B, _PAL_PREC_DATA_C)
+#define PREC_PAL_GC_MAX(pipe, i)	_MMIO(_PIPE3(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B, _PAL_PREC_GC_MAX_C) + (i) * 4)
+#define PREC_PAL_EXT_GC_MAX(pipe, i)	_MMIO(_PIPE3(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B, _PAL_PREC_EXT_GC_MAX_C) + (i) * 4)
+
 /* MIPI DSI registers */
 
 #define _MIPI_PORT(port, a, c)	_PORT3(port, a, 0, c)	/* ports A and C only */
diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c
index 39ca215..24f3f28 100644
--- a/drivers/gpu/drm/i915/intel_color.c
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -24,44 +24,169 @@
 
 #include "intel_drv.h"
 
+#define CTM_COEFF_SIGN	(1ULL << 63)
+
+#define CTM_COEFF_1_0	(1ULL << 32)
+#define CTM_COEFF_2_0	(CTM_COEFF_1_0 << 1)
+#define CTM_COEFF_4_0	(CTM_COEFF_2_0 << 1)
+#define CTM_COEFF_0_5	(CTM_COEFF_1_0 >> 1)
+#define CTM_COEFF_0_25	(CTM_COEFF_0_5 >> 1)
+#define CTM_COEFF_0_125	(CTM_COEFF_0_25 >> 1)
+
+#define CTM_COEFF_LIMITED_RANGE ((235ULL - 16ULL) * CTM_COEFF_1_0 / 255)
+
+#define CTM_COEFF_NEGATIVE(coeff)	(((coeff) & CTM_COEFF_SIGN) != 0)
+#define CTM_COEFF_ABS(coeff)		((coeff) & (CTM_COEFF_SIGN - 1))
+
+/*
+ * Extract the CSC coefficient from a CTM coefficient (in U32.32 fixed point
+ * format). This macro takes the coefficient we want transformed and the
+ * number of fractional bits.
+ *
+ * We only have a 9 bits precision window which slides depending on the value
+ * of the CTM coefficient and we write the value from bit 3. We also round the
+ * value.
+ */
+#define I9XX_CSC_COEFF_FP(coeff, fbits)	\
+	(clamp_val(((coeff) >> (32 - (fbits) - 3)) + 4, 0, 0xfff) & 0xff8)
+
+#define I9XX_CSC_COEFF_LIMITED_RANGE	\
+	I9XX_CSC_COEFF_FP(CTM_COEFF_LIMITED_RANGE, 9)
+#define I9XX_CSC_COEFF_1_0		\
+	((7 << 12) | I9XX_CSC_COEFF_FP(CTM_COEFF_1_0, 8))
+
+/*
+ * When using limited range, multiply the matrix given by userspace by
+ * the matrix that we would use for the limited range. We do the
+ * multiplication in U2.30 format.
+ */
+static void ctm_matrix_mult_by_limited(uint64_t *result,
+				       int64_t *input)
+{
+	int i, j;
+	uint64_t limited_coeffs[9] = { CTM_COEFF_LIMITED_RANGE, 0, 0,
+				       0, CTM_COEFF_LIMITED_RANGE, 0,
+				       0, 0, CTM_COEFF_LIMITED_RANGE };
+
+	for (i = 0; i < ARRAY_SIZE(limited_coeffs); i++) {
+		int column = i % 3, row = i / 3;
+		int negative = 0;
+
+		input[i] = 0;
+		for (j = 0; j < 3; j++) {
+			int64_t user_coeff = input[j * 3 + column];
+			uint64_t limited_coeff =
+				limited_coeffs[row * 3 + j] >> 2;
+			uint64_t abs_coeff =
+				clamp_val(CTM_COEFF_ABS(user_coeff),
+					  0,
+					  CTM_COEFF_4_0 - 1) >> 2;
+
+			if (CTM_COEFF_NEGATIVE(user_coeff))
+				negative = !negative;
+			result[i] += limited_coeff * abs_coeff;
+		}
+
+		result[i] >>= 27;
+		if (negative)
+			result[i] |= CTM_COEFF_SIGN;
+	}
+}
+
 /*
  * Set up the pipe CSC unit.
  *
- * Currently only full range RGB to limited range RGB conversion
- * is supported, but eventually this should handle various
- * RGB<->YCbCr scenarios as well.
+ * Currently only full range RGB to limited range RGB conversion is supported,
+ * but eventually this should handle various RGB<->YCbCr scenarios as well.
  */
 static void i9xx_load_csc_matrix(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
+	struct drm_crtc_state *crtc_state = crtc->state;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int pipe = intel_crtc->pipe;
-	uint16_t coeff = 0x7800; /* 1.0 */
+	int i, pipe = intel_crtc->pipe;
+	uint16_t coeffs[9] = { 0, };
 
-	/*
-	 * TODO: Check what kind of values actually come out of the pipe
-	 * with these coeff/postoff values and adjust to get the best
-	 * accuracy. Perhaps we even need to take the bpc value into
-	 * consideration.
-	 */
+	if (crtc_state->ctm_matrix) {
+		struct drm_color_ctm *ctm =
+			(struct drm_color_ctm *)crtc_state->ctm_matrix->data;
+		uint64_t input[9] = { 0, };
+
+		if (intel_crtc->config->limited_color_range)
+			ctm_matrix_mult_by_limited(input, ctm->matrix);
+		else {
+			for (i = 0; i < ARRAY_SIZE(input); i++)
+				input[i] = ctm->matrix[i];
+		}
 
-	if (intel_crtc->config->limited_color_range)
-		coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
+
+		/*
+		 * Convert fixed point S31.32 input to format supported by the
+		 * hardware.
+		 */
+		for (i = 0; i < ARRAY_SIZE(coeffs); i++) {
+			uint64_t abs_coeff = ((1ULL << 63) - 1) & input[i];
+
+			/*
+			 * Clamp input value to min/max supported by
+			 * hardware.
+			 */
+			abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1);
+
+			/* sign bit */
+			if (CTM_COEFF_NEGATIVE(input[i]))
+				coeffs[i] |= 1 << 15;
+
+			if (abs_coeff < CTM_COEFF_0_125)
+				coeffs[i] |= (3 << 12) |
+					I9XX_CSC_COEFF_FP(abs_coeff, 12);
+			else if (abs_coeff < CTM_COEFF_0_25)
+				coeffs[i] |= (2 << 12) |
+					I9XX_CSC_COEFF_FP(abs_coeff, 11);
+			else if (abs_coeff < CTM_COEFF_0_5)
+				coeffs[i] |= (1 << 12) |
+					I9XX_CSC_COEFF_FP(abs_coeff, 10);
+			else if (abs_coeff < CTM_COEFF_1_0)
+				coeffs[i] |= I9XX_CSC_COEFF_FP(abs_coeff, 9);
+			else if (abs_coeff < CTM_COEFF_2_0)
+				coeffs[i] |= (7 << 12) |
+					I9XX_CSC_COEFF_FP(abs_coeff, 8);
+			else
+				coeffs[i] |= (6 << 12) |
+					I9XX_CSC_COEFF_FP(abs_coeff, 7);
+		}
+	} else {
+		/*
+		 * Load an identify matrix if no coefficients are provided.
+		 *
+		 * TODO: Check what kind of values actually come out of the
+		 * pipe with these coeff/postoff values and adjust to get the
+		 * best accuracy. Perhaps we even need to take the bpc value
+		 * into consideration.
+		 */
+		for (i = 0; i < 3; i++) {
+			if (intel_crtc->config->limited_color_range)
+				coeffs[i * 3 + i] =
+					I9XX_CSC_COEFF_LIMITED_RANGE;
+			else
+				coeffs[i * 3 + i] = I9XX_CSC_COEFF_1_0;
+		}
+	}
 
 	/*
 	 * GY/GU and RY/RU should be the other way around according
 	 * to BSpec, but reality doesn't agree. Just set them up in
 	 * a way that results in the correct picture.
 	 */
-	I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16);
-	I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0);
+	I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeffs[0] << 16 | coeffs[1]);
+	I915_WRITE(PIPE_CSC_COEFF_BY(pipe), coeffs[2] << 16);
 
-	I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff);
-	I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0);
+	I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeffs[3] << 16 | coeffs[4]);
+	I915_WRITE(PIPE_CSC_COEFF_BU(pipe), coeffs[5] << 16);
 
-	I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0);
-	I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16);
+	I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), coeffs[6] << 16 | coeffs[7]);
+	I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeffs[8] << 16);
 
 	I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0);
 	I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0);
@@ -88,21 +213,134 @@ static void i9xx_load_csc_matrix(struct drm_crtc *crtc)
 	}
 }
 
-void intel_color_set_csc(struct drm_crtc *crtc)
+/** Loads the legacy palette/gamma unit for the CRTC with the prepared
+ * values.
+ */
+static void i9xx_load_legacy_gamma_lut(struct drm_crtc *crtc)
 {
-	i9xx_load_csc_matrix(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_crtc_state *intel_state = to_intel_crtc_state(crtc->state);
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+	int i;
+
+	for (i = 0; i < 256; i++) {
+		uint32_t word = (intel_crtc->lut_r[i] << 16) |
+			(intel_crtc->lut_g[i] << 8) |
+			intel_crtc->lut_b[i];
+		if (HAS_GMCH_DISPLAY(dev))
+			I915_WRITE(PALETTE(pipe, i), word);
+		else
+			I915_WRITE(LGC_PALETTE(pipe, i), word);
+	}
+
+	intel_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
+	I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
 }
 
-/** Loads the palette/gamma unit for the CRTC with the prepared values on  */
-static void i9xx_load_legacy_gamma_lut(struct drm_crtc *crtc)
+static void broadwell_load_degamma_lut(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc_state *state = crtc->state;
+	struct intel_crtc_state *intel_state = to_intel_crtc_state(state);
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+	uint32_t i, lut_size = INTEL_INFO(dev)->color.degamma_lut_size;
+
+	I915_WRITE(PREC_PAL_INDEX(pipe),
+		   PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT);
+
+	if (state->degamma_lut) {
+		struct drm_color_lut *lut =
+			(struct drm_color_lut *) state->degamma_lut->data;
+
+		for (i = 0; i < lut_size; i++) {
+			uint32_t word =
+			drm_color_lut_get_value(lut[i].red, 10) << 20 |
+			drm_color_lut_get_value(lut[i].green, 10) << 10 |
+			drm_color_lut_get_value(lut[i].blue, 10);
+
+			I915_WRITE(PREC_PAL_DATA(pipe), word);
+		}
+	} else {
+		for (i = 0; i < lut_size; i++) {
+			uint32_t v = (i * ((1 << 10) - 1)) / (lut_size - 1);
+
+			I915_WRITE(PREC_PAL_DATA(pipe),
+				   (v << 20) | (v << 10) | v);
+		}
+	}
+
+	intel_state->gamma_mode = GAMMA_MODE_MODE_SPLIT;
+	I915_WRITE(GAMMA_MODE(pipe), GAMMA_MODE_MODE_SPLIT);
+	POSTING_READ(GAMMA_MODE(pipe));
+
+	/* Reset the index, otherwise it prevents the legacy palette to be
+	 * written properly.
+	 */
+	I915_WRITE(PREC_PAL_INDEX(pipe), 0);
+}
+
+static void broadwell_load_gamma_lut(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc_state *state = crtc->state;
+	struct intel_crtc_state *intel_state = to_intel_crtc_state(state);
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+	uint32_t i, lut_offset = INTEL_INFO(dev)->color.degamma_lut_size,
+		lut_size = INTEL_INFO(dev)->color.gamma_lut_size;
+
+
+	I915_WRITE(PREC_PAL_INDEX(pipe),
+		   PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT | lut_offset);
+
+	if (state->gamma_lut) {
+		struct drm_color_lut *lut =
+			(struct drm_color_lut *) state->gamma_lut->data;
+
+		for (i = 0; i < lut_size; i++) {
+			uint32_t word =
+			(drm_color_lut_get_value(lut[i].red, 10) << 20) |
+			(drm_color_lut_get_value(lut[i].green, 10) << 10) |
+			drm_color_lut_get_value(lut[i].blue, 10);
+
+			I915_WRITE(PREC_PAL_DATA(pipe), word);
+		}
+	} else {
+		for (i = 0; i < lut_size; i++) {
+			uint32_t v = (i * ((1 << 10) - 1)) / (lut_size - 1);
+
+			I915_WRITE(PREC_PAL_DATA(pipe),
+				   (v << 20) | (v << 10) | v);
+		}
+	}
+
+	intel_state->gamma_mode = GAMMA_MODE_MODE_SPLIT;
+	I915_WRITE(GAMMA_MODE(pipe), GAMMA_MODE_MODE_SPLIT);
+	POSTING_READ(GAMMA_MODE(pipe));
+
+	/* Reset the index, otherwise it prevents the legacy palette to be
+	 * written properly.
+	 */
+	I915_WRITE(PREC_PAL_INDEX(pipe), 0);
+}
+
+static void intel_color_load_luts_internal(struct drm_crtc *crtc,
+					  bool legacy)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	int i;
+	struct intel_crtc_state *intel_state = to_intel_crtc_state(crtc->state);
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
 	bool reenable_ips = false;
 
+	/* The clocks have to be on to load the palette. */
+	if (!crtc->state->active)
+		return;
+
 	if (HAS_GMCH_DISPLAY(dev)) {
 		if (intel_crtc->config->has_dsi_encoder)
 			assert_dsi_pll_enabled(dev_priv);
@@ -114,42 +352,32 @@ static void i9xx_load_legacy_gamma_lut(struct drm_crtc *crtc)
 	 * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
 	 */
 	if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
-	    ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
-	     GAMMA_MODE_MODE_SPLIT)) {
+	    intel_state->gamma_mode == GAMMA_MODE_MODE_SPLIT) {
 		hsw_disable_ips(intel_crtc);
 		reenable_ips = true;
 	}
 
-	for (i = 0; i < 256; i++) {
-		uint32_t word = (intel_crtc->lut_r[i] << 16) |
-			(intel_crtc->lut_g[i] << 8) |
-			intel_crtc->lut_b[i];
-		if (HAS_GMCH_DISPLAY(dev))
-			I915_WRITE(PALETTE(pipe, i), word);
-		else
-			I915_WRITE(LGC_PALETTE(pipe, i), word);
+	if (legacy)
+		i9xx_load_legacy_gamma_lut(crtc);
+	else {
+		dev_priv->display.load_degamma_lut(crtc);
+		dev_priv->display.load_gamma_lut(crtc);
 	}
 
-	I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
-
 	if (reenable_ips)
 		hsw_enable_ips(intel_crtc);
 }
 
-void intel_color_load_gamma_lut(struct drm_crtc *crtc)
+void intel_color_legacy_load_lut(struct drm_crtc *crtc)
 {
-	/* The clocks have to be on to load the palette. */
-	if (!crtc->state->active)
-		return;
-
-	i9xx_load_legacy_gamma_lut(crtc);
+	intel_color_load_luts_internal(crtc, true);
 }
 
 void intel_color_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 				  u16 *blue, uint32_t start, uint32_t size)
 {
-	int end = (start + size > 256) ? 256 : start + size, i;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int end = (start + size > 256) ? 256 : start + size, i;
 
 	for (i = start; i < end; i++) {
 		intel_crtc->lut_r[i] = red[i] >> 8;
@@ -157,11 +385,29 @@ void intel_color_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 		intel_crtc->lut_b[i] = blue[i] >> 8;
 	}
 
-	intel_color_load_gamma_lut(crtc);
+	intel_color_load_luts_internal(crtc, true);
+}
+
+void intel_color_load_luts(struct drm_crtc *crtc)
+{
+	intel_color_load_luts_internal(crtc,
+				       !crtc->state->degamma_lut &&
+				       !crtc->state->gamma_lut);
+}
+
+void intel_color_set_csc(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (dev_priv->display.load_csc_matrix)
+		dev_priv->display.load_csc_matrix(crtc);
 }
 
 void intel_color_init(struct drm_crtc *crtc)
 {
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int i;
 
@@ -171,4 +417,23 @@ void intel_color_init(struct drm_crtc *crtc)
 		intel_crtc->lut_g[i] = i;
 		intel_crtc->lut_b[i] = i;
 	}
+
+	if (IS_BROADWELL(dev) || IS_SKYLAKE(dev) ||
+	    IS_BROXTON(dev) || IS_KABYLAKE(dev)) {
+		dev_priv->display.load_degamma_lut = broadwell_load_degamma_lut;
+		dev_priv->display.load_gamma_lut = broadwell_load_gamma_lut;
+		dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
+	} else {
+		dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
+	}
+
+	if (INTEL_INFO(dev)->color.degamma_lut_size != 0 &&
+	    INTEL_INFO(dev)->color.gamma_lut_size != 0) {
+		WARN_ON(!dev_priv->display.load_degamma_lut ||
+			!dev_priv->display.load_gamma_lut ||
+			!dev_priv->display.load_csc_matrix);
+		drm_helper_crtc_enable_color_mgmt(crtc,
+					INTEL_INFO(dev)->color.degamma_lut_size,
+					INTEL_INFO(dev)->color.gamma_lut_size);
+	}
 }
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a0ebc85..eaa8e5c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4858,7 +4858,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 	 * On ILK+ LUT must be loaded before the pipe is running but with
 	 * clocks enabled
 	 */
-	intel_color_load_gamma_lut(crtc);
+	intel_color_load_luts(crtc);
 
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
@@ -4955,7 +4955,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 	 * On ILK+ LUT must be loaded before the pipe is running but with
 	 * clocks enabled
 	 */
-	intel_color_load_gamma_lut(crtc);
+	intel_color_load_luts(crtc);
 
 	intel_ddi_set_pipe_settings(crtc);
 	if (!intel_crtc->config->has_dsi_encoder)
@@ -6176,7 +6176,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
 	i9xx_pfit_enable(intel_crtc);
 
-	intel_color_load_gamma_lut(crtc);
+	intel_color_load_luts(crtc);
 
 	intel_enable_pipe(intel_crtc);
 
@@ -6229,7 +6229,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
 	i9xx_pfit_enable(intel_crtc);
 
-	intel_color_load_gamma_lut(crtc);
+	intel_color_load_luts(crtc);
 
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
@@ -11937,7 +11937,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 
 static const struct drm_crtc_helper_funcs intel_helper_funcs = {
 	.mode_set_base_atomic = intel_pipe_set_base_atomic,
-	.load_lut = intel_color_load_gamma_lut,
+	.load_lut = intel_color_legacy_load_lut,
 	.atomic_begin = intel_begin_crtc_commit,
 	.atomic_flush = intel_finish_crtc_commit,
 	.atomic_check = intel_crtc_atomic_check,
@@ -13464,6 +13464,17 @@ static int intel_atomic_commit(struct drm_device *dev,
 			hw_check = true;
 		}
 
+		if (!modeset &&
+		    crtc->state->active &&
+		    crtc->state->color_mgmt_changed) {
+			/* Only update color management when not doing
+			 * a modeset as this will be done by
+			 * crtc_enable already.
+			 */
+			intel_color_set_csc(crtc);
+			intel_color_load_luts(crtc);
+		}
+
 		if (!modeset)
 			intel_pre_plane_update(intel_crtc);
 
@@ -13552,6 +13563,7 @@ out:
 static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.gamma_set = intel_color_legacy_gamma_set,
 	.set_config = drm_atomic_helper_set_config,
+	.set_property = drm_atomic_helper_crtc_set_property,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
 	.atomic_duplicate_state = intel_crtc_duplicate_state,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index abc128a..a462861 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -505,6 +505,8 @@ struct intel_crtc_state {
 	/* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */
 	bool disable_lp_wm;
 
+	uint32_t gamma_mode;
+
 	struct {
 		/*
 		 * optimal watermarks, programmed post-vblank when this state
@@ -1616,9 +1618,11 @@ extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
 
 /* intel_color.c */
 void intel_color_init(struct drm_crtc *crtc);
+void intel_color_update(struct drm_crtc *crtc);
 void intel_color_set_csc(struct drm_crtc *crtc);
-void intel_color_load_gamma_lut(struct drm_crtc *crtc);
+void intel_color_load_luts(struct drm_crtc *crtc);
 void intel_color_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 				  u16 *blue, uint32_t start, uint32_t size);
+void intel_color_legacy_load_lut(struct drm_crtc *crtc);
 
 #endif /* __INTEL_DRV_H__ */
-- 
2.6.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

  parent reply	other threads:[~2016-01-22 12:12 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-22 12:12 [PATCH 0/6] Pipe level color management V2 Lionel Landwerlin
2016-01-22 12:12 ` [PATCH 1/6] drm/i915: Extract out gamma table and CSC to their own file Lionel Landwerlin
2016-01-22 12:12 ` [PATCH 2/6] drm: introduce color correction properties Lionel Landwerlin
2016-01-22 21:20   ` Matt Roper
2016-01-25 10:57     ` Daniel Stone
2016-01-27  9:02       ` Matt Roper
2016-01-22 12:12 ` [PATCH 3/6] drm/i915: enable CSC for pipe C Lionel Landwerlin
2016-01-22 12:12 ` [PATCH 4/6] drm/i915: enable legacy palette " Lionel Landwerlin
2016-01-22 12:12 ` Lionel Landwerlin [this message]
2016-01-22 12:12 ` [PATCH 6/6] drm/i915: Implement color management on chv Lionel Landwerlin
2016-01-22 13:14 ` ✗ Fi.CI.BAT: failure for Pipe level color management (rev2) Patchwork
  -- strict thread matches above, loose matches on Subject: below --
2016-02-09 12:19 [PATCH 0/6] Pipe level color management V4 Lionel Landwerlin
2016-02-09 12:19 ` [PATCH 5/6] drm/i915: Implement color management on bdw/skl/bxt/kbl Lionel Landwerlin
2016-02-19  0:42   ` Matt Roper
2016-02-01 15:18 [PATCH 0/6] Pipe level color management V3 Lionel Landwerlin
2016-02-01 15:18 ` [PATCH 5/6] drm/i915: Implement color management on bdw/skl/bxt/kbl Lionel Landwerlin
2016-01-21 15:03 [PATCH 0/6] Pipe level color management Lionel Landwerlin
2016-01-21 15:03 ` [PATCH 5/6] drm/i915: Implement color management on bdw/skl/bxt/kbl Lionel Landwerlin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1453464732-17241-6-git-send-email-lionel.g.landwerlin@intel.com \
    --to=lionel.g.landwerlin@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.