* [PATCH 1/5] drm/i915: Extract out gamma table and CSC to their own file
2016-02-25 15:33 [PATCH 0/5] Pipe level color management V9 Lionel Landwerlin
@ 2016-02-25 15:33 ` Lionel Landwerlin
2016-02-25 15:33 ` [PATCH 2/5] drm/i915: Do not read GAMMA_MODE register Lionel Landwerlin
` (4 subsequent siblings)
5 siblings, 0 replies; 16+ messages in thread
From: Lionel Landwerlin @ 2016-02-25 15:33 UTC (permalink / raw)
To: intel-gfx, dri-devel; +Cc: kausalmalladi, kiran.s.kumar
The moves a couple of functions programming the gamma LUT and CSC
units into their own file.
On generations prior to Haswell there is only a gamma LUT. From
haswell on there is also a new enhanced color correction unit that
isn't used yet. This is why we need to set the GAMMA_MODE register,
either we're using the legacy 8bits LUT or enhanced LUTs (of 10 or
12bits).
The CSC unit is only available from Haswell on.
We also need to make a special case for CherryView which is recognized
as a gen 8 but doesn't have the same enhanced color correction unit
from Haswell on.
v2: Fix access to GAMMA_MODE register on older generations than
Haswell (from Matt Roper's comments)
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
---
drivers/gpu/drm/i915/Makefile | 1 +
drivers/gpu/drm/i915/i915_drv.h | 2 +
drivers/gpu/drm/i915/intel_color.c | 190 +++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_display.c | 163 +++---------------------------
drivers/gpu/drm/i915/intel_drv.h | 10 ++
5 files changed, 215 insertions(+), 151 deletions(-)
create mode 100644 drivers/gpu/drm/i915/intel_color.c
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0851de07..0516300 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -55,6 +55,7 @@ i915-y += intel_audio.o \
intel_atomic.o \
intel_atomic_plane.o \
intel_bios.o \
+ intel_color.o \
intel_display.o \
intel_fbc.o \
intel_fifo_underrun.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9e76bfc..8cb4418 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -662,6 +662,8 @@ struct drm_i915_display_funcs {
/* render clock increase/decrease */
/* display clock increase/decrease */
/* pll clock increase/decrease */
+
+ void (*load_luts)(struct drm_crtc *crtc);
};
enum forcewake_domain_id {
diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c
new file mode 100644
index 0000000..5e0b997
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "intel_drv.h"
+
+/*
+ * 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.
+ */
+static void i9xx_load_csc_matrix(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 pipe = intel_crtc->pipe;
+ uint16_t coeff = 0x7800; /* 1.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 (intel_crtc->config->limited_color_range)
+ coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
+
+ I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16);
+ I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0);
+
+ I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff);
+ I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0);
+
+ I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0);
+ I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16);
+
+ I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0);
+ I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0);
+ I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0);
+
+ if (INTEL_INFO(dev)->gen > 6) {
+ uint16_t postoff = 0;
+
+ if (intel_crtc->config->limited_color_range)
+ postoff = (16 * (1 << 12) / 255) & 0x1fff;
+
+ I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
+ I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff);
+ I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff);
+
+ I915_WRITE(PIPE_CSC_MODE(pipe), 0);
+ } else {
+ uint32_t mode = CSC_MODE_YUV_TO_RGB;
+
+ if (intel_crtc->config->limited_color_range)
+ mode |= CSC_BLACK_SCREEN_OFFSET;
+
+ I915_WRITE(PIPE_CSC_MODE(pipe), mode);
+ }
+}
+
+void intel_color_set_csc(struct drm_crtc *crtc)
+{
+ i9xx_load_csc_matrix(crtc);
+}
+
+/* Loads the palette/gamma unit for the CRTC with the prepared values. */
+static void i9xx_load_luts(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);
+ enum pipe pipe = intel_crtc->pipe;
+ int i;
+
+ if (HAS_GMCH_DISPLAY(dev)) {
+ if (intel_crtc->config->has_dsi_encoder)
+ assert_dsi_pll_enabled(dev_priv);
+ else
+ assert_pll_enabled(dev_priv, pipe);
+ }
+
+ 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);
+ }
+}
+
+/* Loads the legacy palette/gamma unit for the CRTC on Haswell+. */
+static void haswell_load_luts(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);
+ bool reenable_ips = false;
+
+ /*
+ * Workaround : Do not read or write the pipe palette/gamma data while
+ * 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(intel_crtc->pipe)) & GAMMA_MODE_MODE_MASK) ==
+ GAMMA_MODE_MODE_SPLIT)) {
+ hsw_disable_ips(intel_crtc);
+ reenable_ips = true;
+ }
+ I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
+
+ i9xx_load_luts(crtc);
+
+ if (reenable_ips)
+ hsw_enable_ips(intel_crtc);
+}
+
+void intel_color_load_luts(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /* The clocks have to be on to load the palette. */
+ if (!crtc->state->active)
+ return;
+
+ dev_priv->display.load_luts(crtc);
+}
+
+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);
+
+ for (i = start; i < end; i++) {
+ intel_crtc->lut_r[i] = red[i] >> 8;
+ intel_crtc->lut_g[i] = green[i] >> 8;
+ intel_crtc->lut_b[i] = blue[i] >> 8;
+ }
+
+ intel_color_load_luts(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;
+
+ drm_mode_crtc_set_gamma_size(crtc, 256);
+ for (i = 0; i < 256; i++) {
+ intel_crtc->lut_r[i] = i;
+ intel_crtc->lut_g[i] = i;
+ intel_crtc->lut_b[i] = i;
+ }
+
+ if (IS_HASWELL(dev) ||
+ (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)))
+ dev_priv->display.load_luts = haswell_load_luts;
+ else
+ dev_priv->display.load_luts = i9xx_load_luts;
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9a18613..cd47f5b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -101,7 +101,6 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
struct intel_link_m_n *m2_n2);
static void ironlake_set_pipeconf(struct drm_crtc *crtc);
static void haswell_set_pipeconf(struct drm_crtc *crtc);
-static void intel_set_pipe_csc(struct drm_crtc *crtc);
static void vlv_prepare_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
static void chv_prepare_pll(struct intel_crtc *crtc,
@@ -1165,7 +1164,7 @@ void assert_pll(struct drm_i915_private *dev_priv,
}
/* XXX: the dsi pll is shared between MIPI DSI ports */
-static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
+void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
{
u32 val;
bool cur_state;
@@ -1179,8 +1178,6 @@ static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
"DSI PLL state assertion failure (expected %s, current %s)\n",
onoff(state), onoff(cur_state));
}
-#define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true)
-#define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false)
struct intel_shared_dpll *
intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
@@ -3315,7 +3312,7 @@ static void intel_update_pipe_config(struct intel_crtc *crtc,
pipe_config->pipe_src_w, pipe_config->pipe_src_h);
if (HAS_DDI(dev))
- intel_set_pipe_csc(&crtc->base);
+ intel_color_set_csc(&crtc->base);
/*
* Update pipe size and adjust fitter if needed: the reason for this is
@@ -4626,55 +4623,6 @@ void hsw_disable_ips(struct intel_crtc *crtc)
intel_wait_for_vblank(dev, crtc->pipe);
}
-/** Loads the palette/gamma unit for the CRTC with the prepared values */
-static void intel_crtc_load_lut(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);
- enum pipe pipe = intel_crtc->pipe;
- int i;
- bool reenable_ips = false;
-
- /* The clocks have to be on to load the palette. */
- if (!crtc->state->active)
- return;
-
- if (HAS_GMCH_DISPLAY(dev_priv->dev)) {
- if (intel_crtc->config->has_dsi_encoder)
- assert_dsi_pll_enabled(dev_priv);
- else
- assert_pll_enabled(dev_priv, pipe);
- }
-
- /* Workaround : Do not read or write the pipe palette/gamma data while
- * 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)) {
- hsw_disable_ips(intel_crtc);
- reenable_ips = true;
- }
-
- for (i = 0; i < 256; i++) {
- i915_reg_t palreg;
-
- if (HAS_GMCH_DISPLAY(dev))
- palreg = PALETTE(pipe, i);
- else
- palreg = LGC_PALETTE(pipe, i);
-
- I915_WRITE(palreg,
- (intel_crtc->lut_r[i] << 16) |
- (intel_crtc->lut_g[i] << 8) |
- intel_crtc->lut_b[i]);
- }
-
- if (reenable_ips)
- hsw_enable_ips(intel_crtc);
-}
-
static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc)
{
if (intel_crtc->overlay) {
@@ -4923,7 +4871,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_crtc_load_lut(crtc);
+ intel_color_load_luts(crtc);
intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
@@ -4989,7 +4937,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
haswell_set_pipeconf(crtc);
- intel_set_pipe_csc(crtc);
+ intel_color_set_csc(crtc);
intel_crtc->active = true;
@@ -5018,7 +4966,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_crtc_load_lut(crtc);
+ intel_color_load_luts(crtc);
intel_ddi_set_pipe_settings(crtc);
if (!intel_crtc->config->has_dsi_encoder)
@@ -6211,7 +6159,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
i9xx_pfit_enable(intel_crtc);
- intel_crtc_load_lut(crtc);
+ intel_color_load_luts(crtc);
intel_enable_pipe(intel_crtc);
@@ -6264,7 +6212,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
i9xx_pfit_enable(intel_crtc);
- intel_crtc_load_lut(crtc);
+ intel_color_load_luts(crtc);
intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
@@ -8719,70 +8667,6 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc)
POSTING_READ(PIPECONF(pipe));
}
-/*
- * 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.
- */
-static void intel_set_pipe_csc(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 pipe = intel_crtc->pipe;
- uint16_t coeff = 0x7800; /* 1.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 (intel_crtc->config->limited_color_range)
- coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
-
- /*
- * 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_RU_GU(pipe), coeff);
- I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0);
-
- I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0);
- I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16);
-
- I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0);
- I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0);
- I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0);
-
- if (INTEL_INFO(dev)->gen > 6) {
- uint16_t postoff = 0;
-
- if (intel_crtc->config->limited_color_range)
- postoff = (16 * (1 << 12) / 255) & 0x1fff;
-
- I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
- I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff);
- I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff);
-
- I915_WRITE(PIPE_CSC_MODE(pipe), 0);
- } else {
- uint32_t mode = CSC_MODE_YUV_TO_RGB;
-
- if (intel_crtc->config->limited_color_range)
- mode |= CSC_BLACK_SCREEN_OFFSET;
-
- I915_WRITE(PIPE_CSC_MODE(pipe), mode);
- }
-}
-
static void haswell_set_pipeconf(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -8805,9 +8689,6 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
I915_WRITE(PIPECONF(cpu_transcoder), val);
POSTING_READ(PIPECONF(cpu_transcoder));
- I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
- POSTING_READ(GAMMA_MODE(intel_crtc->pipe));
-
if (IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
val = 0;
@@ -10220,21 +10101,6 @@ static bool cursor_size_ok(struct drm_device *dev,
return true;
}
-static void intel_crtc_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);
-
- for (i = start; i < end; i++) {
- intel_crtc->lut_r[i] = red[i] >> 8;
- intel_crtc->lut_g[i] = green[i] >> 8;
- intel_crtc->lut_b[i] = blue[i] >> 8;
- }
-
- intel_crtc_load_lut(crtc);
-}
-
/* VESA 640x480x72Hz mode to set on the pipe */
static struct drm_display_mode load_detect_mode = {
DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
@@ -11983,7 +11849,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_crtc_load_lut,
+ .load_lut = intel_color_load_luts,
.atomic_begin = intel_begin_crtc_commit,
.atomic_flush = intel_finish_crtc_commit,
.atomic_check = intel_crtc_atomic_check,
@@ -13609,7 +13475,7 @@ out:
#undef for_each_intel_crtc_masked
static const struct drm_crtc_funcs intel_crtc_funcs = {
- .gamma_set = intel_crtc_gamma_set,
+ .gamma_set = intel_color_legacy_gamma_set,
.set_config = drm_atomic_helper_set_config,
.destroy = intel_crtc_destroy,
.page_flip = intel_crtc_page_flip,
@@ -14216,7 +14082,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
struct intel_crtc_state *crtc_state = NULL;
struct drm_plane *primary = NULL;
struct drm_plane *cursor = NULL;
- int i, ret;
+ int ret;
intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
if (intel_crtc == NULL)
@@ -14252,13 +14118,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
if (ret)
goto fail;
- drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
- for (i = 0; i < 256; i++) {
- intel_crtc->lut_r[i] = i;
- intel_crtc->lut_g[i] = i;
- intel_crtc->lut_b[i] = i;
- }
-
/*
* On gen2/3 only plane A can do fbc, but the panel fitter and lvds port
* is hooked to pipe B. Hence we want plane A feeding pipe B.
@@ -14283,6 +14142,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+ intel_color_init(&intel_crtc->base);
+
WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
return;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4852049..7532f61 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1166,6 +1166,9 @@ void assert_pll(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state);
#define assert_pll_enabled(d, p) assert_pll(d, p, true)
#define assert_pll_disabled(d, p) assert_pll(d, p, false)
+void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state);
+#define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true)
+#define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false)
void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state);
#define assert_fdi_rx_pll_enabled(d, p) assert_fdi_rx_pll(d, p, true)
@@ -1618,4 +1621,11 @@ 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.c */
+void intel_color_init(struct drm_crtc *crtc);
+void intel_color_set_csc(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);
+
#endif /* __INTEL_DRV_H__ */
--
2.7.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/5] drm/i915: Do not read GAMMA_MODE register
2016-02-25 15:33 [PATCH 0/5] Pipe level color management V9 Lionel Landwerlin
2016-02-25 15:33 ` [PATCH 1/5] drm/i915: Extract out gamma table and CSC to their own file Lionel Landwerlin
@ 2016-02-25 15:33 ` Lionel Landwerlin
2016-02-25 15:33 ` [PATCH 3/5] drm: introduce pipe color correction properties Lionel Landwerlin
` (3 subsequent siblings)
5 siblings, 0 replies; 16+ messages in thread
From: Lionel Landwerlin @ 2016-02-25 15:33 UTC (permalink / raw)
To: intel-gfx, dri-devel; +Cc: kausalmalladi
Implement Daniel Stone's recommendation to not read registers to infer
the hardware's state.
v2: Read GAMMA_MODE register value at init (Matt Roper's comment)
v3: Read GAMMA_MODE register in intel_modeset_readout_hw_state along
with other registers (Matt Roper's comment).
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
drivers/gpu/drm/i915/intel_color.c | 12 ++++++++----
drivers/gpu/drm/i915/intel_display.c | 2 ++
drivers/gpu/drm/i915/intel_drv.h | 3 +++
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c
index 5e0b997..16657eb 100644
--- a/drivers/gpu/drm/i915/intel_color.c
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -121,6 +121,8 @@ static void haswell_load_luts(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);
+ struct intel_crtc_state *intel_crtc_state =
+ to_intel_crtc_state(crtc->state);
bool reenable_ips = false;
/*
@@ -128,11 +130,12 @@ static void haswell_load_luts(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(intel_crtc->pipe)) & GAMMA_MODE_MODE_MASK) ==
- GAMMA_MODE_MODE_SPLIT)) {
+ (intel_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) {
hsw_disable_ips(intel_crtc);
reenable_ips = true;
}
+
+ intel_crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
i9xx_load_luts(crtc);
@@ -183,8 +186,9 @@ void intel_color_init(struct drm_crtc *crtc)
}
if (IS_HASWELL(dev) ||
- (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)))
+ (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev))) {
dev_priv->display.load_luts = haswell_load_luts;
- else
+ } else {
dev_priv->display.load_luts = i9xx_load_luts;
+ }
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index cd47f5b..154ac87 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9873,6 +9873,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
intel_get_pipe_timings(crtc, pipe_config);
+ pipe_config->gamma_mode = I915_READ(GAMMA_MODE(crtc->pipe));
+
if (INTEL_INFO(dev)->gen >= 9) {
skl_init_scalers(dev, crtc, pipe_config);
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7532f61..8c48131 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -517,6 +517,9 @@ struct intel_crtc_state {
struct skl_pipe_wm skl;
} optimal;
} wm;
+
+ /* Gamma mode programmed on the pipe */
+ uint32_t gamma_mode;
};
struct vlv_wm_state {
--
2.7.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 3/5] drm: introduce pipe color correction properties
2016-02-25 15:33 [PATCH 0/5] Pipe level color management V9 Lionel Landwerlin
2016-02-25 15:33 ` [PATCH 1/5] drm/i915: Extract out gamma table and CSC to their own file Lionel Landwerlin
2016-02-25 15:33 ` [PATCH 2/5] drm/i915: Do not read GAMMA_MODE register Lionel Landwerlin
@ 2016-02-25 15:33 ` Lionel Landwerlin
2016-02-25 15:33 ` [PATCH 4/5] drm/i915: Implement color management on bdw/skl/bxt/kbl Lionel Landwerlin
` (2 subsequent siblings)
5 siblings, 0 replies; 16+ messages in thread
From: Lionel Landwerlin @ 2016-02-25 15:33 UTC (permalink / raw)
To: intel-gfx, dri-devel; +Cc: Kumar, kausalmalladi
Patch based on a previous series by Shashank Sharma.
This introduces optional properties to enable color correction at the
pipe level. It relies on 3 transformations applied to every pixels
displayed. First a lookup into a degamma table, then a multiplication
of the rgb components by a 3x3 matrix and finally another lookup into
a gamma table.
The following properties can be added to a pipe :
- DEGAMMA_LUT : blob containing degamma LUT
- DEGAMMA_LUT_SIZE : number of elements in DEGAMMA_LUT
- CTM : transformation matrix applied after the degamma LUT
- GAMMA_LUT : blob containing gamma LUT
- GAMMA_LUT_SIZE : number of elements in GAMMA_LUT
DEGAMMA_LUT_SIZE and GAMMA_LUT_SIZE are read only properties, set by
the driver to tell userspace applications what sizes should be the
lookup tables in DEGAMMA_LUT and GAMMA_LUT.
A helper is also provided so legacy gamma correction is redirected
through these new properties.
v2: Register LUT size properties as range
v3: Fix round in drm_color_lut_get_value() helper
More docs on how degamma/gamma properties are used
v4: Update contributors
v5: Rename CTM_MATRIX property to CTM (Doh!)
Add legacy gamma_set atomic helper
Describe CTM/LUT acronyms in the kernel doc
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Signed-off-by: Kumar, Kiran S <kiran.s.kumar@intel.com>
Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
---
Documentation/DocBook/gpu.tmpl | 59 ++++++++++++++++++++-
drivers/gpu/drm/drm_atomic.c | 86 +++++++++++++++++++++++++++++-
drivers/gpu/drm/drm_atomic_helper.c | 103 ++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_crtc.c | 35 ++++++++++++
drivers/gpu/drm/drm_crtc_helper.c | 33 ++++++++++++
include/drm/drm_atomic_helper.h | 3 ++
include/drm/drm_crtc.h | 46 +++++++++++++++-
include/drm/drm_crtc_helper.h | 3 ++
include/uapi/drm/drm_mode.h | 15 ++++++
9 files changed, 378 insertions(+), 5 deletions(-)
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl
index fe6b36a..1692c4d 100644
--- a/Documentation/DocBook/gpu.tmpl
+++ b/Documentation/DocBook/gpu.tmpl
@@ -1816,7 +1816,7 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >Description/Restrictions</td>
</tr>
<tr>
- <td rowspan="37" valign="top" >DRM</td>
+ <td rowspan="42" valign="top" >DRM</td>
<td valign="top" >Generic</td>
<td valign="top" >“rotation”</td>
<td valign="top" >BITMASK</td>
@@ -2068,7 +2068,7 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >property to suggest an Y offset for a connector</td>
</tr>
<tr>
- <td rowspan="3" valign="top" >Optional</td>
+ <td rowspan="8" valign="top" >Optional</td>
<td valign="top" >“scaling mode”</td>
<td valign="top" >ENUM</td>
<td valign="top" >{ "None", "Full", "Center", "Full aspect" }</td>
@@ -2092,6 +2092,61 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >TBD</td>
</tr>
<tr>
+ <td valign="top" >“DEGAMMA_LUT”</td>
+ <td valign="top" >BLOB</td>
+ <td valign="top" >0</td>
+ <td valign="top" >CRTC</td>
+ <td valign="top" >DRM property to set the degamma lookup table
+ (LUT) mapping pixel data from the framebuffer before it is
+ given to the transformation matrix. The data is an interpreted
+ as an array of struct drm_color_lut elements. Hardware might
+ choose not to use the full precision of the LUT elements nor
+ use all the elements of the LUT (for example the hardware
+ might choose to interpolate between LUT[0] and LUT[4]). </td>
+ </tr>
+ <tr>
+ <td valign="top" >“DEGAMMA_LUT_SIZE”</td>
+ <td valign="top" >RANGE | IMMUTABLE</td>
+ <td valign="top" >Min=0, Max=UINT_MAX</td>
+ <td valign="top" >CRTC</td>
+ <td valign="top" >DRM property to gives the size of the lookup
+ table to be set on the DEGAMMA_LUT property (the size depends
+ on the underlying hardware).</td>
+ </tr>
+ <tr>
+ <td valign="top" >“CTM”</td>
+ <td valign="top" >BLOB</td>
+ <td valign="top" >0</td>
+ <td valign="top" >CRTC</td>
+ <td valign="top" >DRM property to set the current
+ transformation matrix (CTM) apply to pixel data after the
+ lookup through the degamma LUT and before the lookup through
+ the gamma LUT. The data is an interpreted as a struct
+ drm_color_ctm.</td>
+ </tr>
+ <tr>
+ <td valign="top" >“GAMMA_LUT”</td>
+ <td valign="top" >BLOB</td>
+ <td valign="top" >0</td>
+ <td valign="top" >CRTC</td>
+ <td valign="top" >DRM property to set the gamma lookup table
+ (LUT) mapping pixel data after to the transformation matrix to
+ data sent to the connector. The data is an interpreted as an
+ array of struct drm_color_lut elements. Hardware might choose
+ not to use the full precision of the LUT elements nor use all
+ the elements of the LUT (for example the hardware might choose
+ to interpolate between LUT[0] and LUT[4]).</td>
+ </tr>
+ <tr>
+ <td valign="top" >“GAMMA_LUT_SIZE”</td>
+ <td valign="top" >RANGE | IMMUTABLE</td>
+ <td valign="top" >Min=0, Max=UINT_MAX</td>
+ <td valign="top" >CRTC</td>
+ <td valign="top" >DRM property to gives the size of the lookup
+ table to be set on the GAMMA_LUT property (the size depends on
+ the underlying hardware).</td>
+ </tr>
+ <tr>
<td rowspan="20" valign="top" >i915</td>
<td rowspan="2" valign="top" >Generic</td>
<td valign="top" >"Broadcast RGB"</td>
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 092620c..b767a4f 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -28,6 +28,7 @@
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
+#include <drm/drm_mode.h>
#include <drm/drm_plane_helper.h>
/**
@@ -376,6 +377,57 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
/**
+ * drm_atomic_replace_property_blob - replace a blob property
+ * @blob: a pointer to the member blob to be replaced
+ * @new_blob: the new blob to replace with
+ * @expected_size: the expected size of the new blob
+ * @replaced: whether the blob has been replaced
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+static int
+drm_atomic_replace_property_blob(struct drm_property_blob **blob,
+ struct drm_property_blob *new_blob,
+ bool *replaced)
+{
+ struct drm_property_blob *old_blob = *blob;
+
+ if (old_blob == new_blob)
+ return 0;
+
+ if (old_blob)
+ drm_property_unreference_blob(old_blob);
+ if (new_blob)
+ drm_property_reference_blob(new_blob);
+ *blob = new_blob;
+ *replaced = true;
+
+ return 0;
+}
+
+static int
+drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
+ struct drm_property_blob **blob,
+ uint64_t blob_id,
+ ssize_t expected_size,
+ bool *replaced)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_property_blob *new_blob = NULL;
+
+ if (blob_id != 0) {
+ new_blob = drm_property_lookup_blob(dev, blob_id);
+ if (new_blob == NULL)
+ return -EINVAL;
+ if (expected_size > 0 && expected_size != new_blob->length)
+ return -EINVAL;
+ }
+
+ return drm_atomic_replace_property_blob(blob, new_blob, replaced);
+}
+
+/**
* drm_atomic_crtc_set_property - set property on CRTC
* @crtc: the drm CRTC to set a property on
* @state: the state object to update with the new property value
@@ -397,6 +449,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = &dev->mode_config;
+ bool replaced = false;
int ret;
if (property == config->prop_active)
@@ -407,8 +460,31 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
drm_property_unreference_blob(mode);
return ret;
- }
- else if (crtc->funcs->atomic_set_property)
+ } else if (property == config->degamma_lut_property) {
+ ret = drm_atomic_replace_property_blob_from_id(crtc,
+ &state->degamma_lut,
+ val,
+ -1,
+ &replaced);
+ state->color_mgmt_changed = replaced;
+ return ret;
+ } else if (property == config->ctm_property) {
+ ret = drm_atomic_replace_property_blob_from_id(crtc,
+ &state->ctm,
+ val,
+ sizeof(struct drm_color_ctm),
+ &replaced);
+ state->color_mgmt_changed = replaced;
+ return ret;
+ } else if (property == config->gamma_lut_property) {
+ ret = drm_atomic_replace_property_blob_from_id(crtc,
+ &state->gamma_lut,
+ val,
+ -1,
+ &replaced);
+ state->color_mgmt_changed = replaced;
+ return ret;
+ } else if (crtc->funcs->atomic_set_property)
return crtc->funcs->atomic_set_property(crtc, state, property, val);
else
return -EINVAL;
@@ -444,6 +520,12 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
*val = state->active;
else if (property == config->prop_mode_id)
*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
+ else if (property == config->degamma_lut_property)
+ *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
+ else if (property == config->ctm_property)
+ *val = (state->ctm) ? state->ctm->base.id : 0;
+ else if (property == config->gamma_lut_property)
+ *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
else if (crtc->funcs->atomic_get_property)
return crtc->funcs->atomic_get_property(crtc, state, property, val);
else
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 4da4f2a..7ab8040 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2513,10 +2513,17 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
if (state->mode_blob)
drm_property_reference_blob(state->mode_blob);
+ if (state->degamma_lut)
+ drm_property_reference_blob(state->degamma_lut);
+ if (state->ctm)
+ drm_property_reference_blob(state->ctm);
+ if (state->gamma_lut)
+ drm_property_reference_blob(state->gamma_lut);
state->mode_changed = false;
state->active_changed = false;
state->planes_changed = false;
state->connectors_changed = false;
+ state->color_mgmt_changed = false;
state->event = NULL;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
@@ -2557,6 +2564,9 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
drm_property_unreference_blob(state->mode_blob);
+ drm_property_unreference_blob(state->degamma_lut);
+ drm_property_unreference_blob(state->ctm);
+ drm_property_unreference_blob(state->gamma_lut);
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
@@ -2870,3 +2880,96 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
+
+/**
+ * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table
+ * @crtc: CRTC object
+ * @red: red correction table
+ * @green: green correction table
+ * @blue: green correction table
+ * @start:
+ * @size: size of the tables
+ *
+ * Implements support for legacy gamma correction table for drivers
+ * that support color management through the DEGAMMA_LUT/GAMMA_LUT
+ * properties.
+ */
+void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
+ u16 *red, u16 *green, u16 *blue,
+ uint32_t start, uint32_t size)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+ struct drm_atomic_state *state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_property_blob *blob = NULL;
+ struct drm_color_lut *blob_data;
+ int i, ret = 0;
+
+ state = drm_atomic_state_alloc(crtc->dev);
+ if (!state)
+ return;
+
+ blob = drm_property_create_blob(dev,
+ sizeof(struct drm_color_lut) * size,
+ NULL);
+
+ state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
+retry:
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ goto fail;
+ }
+
+ /* Reset DEGAMMA_LUT and CTM properties. */
+ ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+ config->degamma_lut_property, 0);
+ if (ret)
+ goto fail;
+ ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+ config->ctm_property, 0);
+ if (ret)
+ goto fail;
+
+ /* Set GAMMA_LUT with legacy values. */
+ if (blob == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ blob_data = (struct drm_color_lut *) blob->data;
+ for (i = 0; i < size; i++) {
+ blob_data[i].red = red[i];
+ blob_data[i].green = green[i];
+ blob_data[i].blue = blue[i];
+ }
+
+ ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+ config->gamma_lut_property, blob->base.id);
+ if (ret)
+ goto fail;
+
+ ret = drm_atomic_commit(state);
+ if (ret != 0)
+ goto fail;
+
+ drm_property_unreference_blob(blob);
+
+ /* Driver takes ownership of state on successful commit. */
+ return;
+fail:
+ if (ret == -EDEADLK)
+ goto backoff;
+
+ drm_atomic_state_free(state);
+ drm_property_unreference_blob(blob);
+
+ return;
+backoff:
+ drm_atomic_state_clear(state);
+ drm_atomic_legacy_backoff(state);
+
+ goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8451400..50066d1 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1554,6 +1554,41 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
return -ENOMEM;
dev->mode_config.prop_mode_id = prop;
+ prop = drm_property_create(dev,
+ DRM_MODE_PROP_BLOB,
+ "DEGAMMA_LUT", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.degamma_lut_property = prop;
+
+ prop = drm_property_create_range(dev,
+ DRM_MODE_PROP_IMMUTABLE,
+ "DEGAMMA_LUT_SIZE", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.degamma_lut_size_property = prop;
+
+ prop = drm_property_create(dev,
+ DRM_MODE_PROP_BLOB,
+ "CTM", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.ctm_property = prop;
+
+ prop = drm_property_create(dev,
+ DRM_MODE_PROP_BLOB,
+ "GAMMA_LUT", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.gamma_lut_property = prop;
+
+ prop = drm_property_create_range(dev,
+ DRM_MODE_PROP_IMMUTABLE,
+ "GAMMA_LUT_SIZE", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.gamma_lut_size_property = prop;
+
return 0;
}
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 7539eea..79555d2 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -1075,3 +1075,36 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
return drm_plane_helper_commit(plane, plane_state, old_fb);
}
EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
+
+/**
+ * drm_helper_crtc_enable_color_mgmt - enable color management properties
+ * @crtc: DRM CRTC
+ * @degamma_lut_size: the size of the degamma lut (before CSC)
+ * @gamma_lut_size: the size of the gamma lut (after CSC)
+ *
+ * This function lets the driver enable the color correction properties on a
+ * CRTC. This includes 3 degamma, csc and gamma properties that userspace can
+ * set and 2 size properties to inform the userspace of the lut sizes.
+ */
+void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+ int degamma_lut_size,
+ int gamma_lut_size)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ drm_object_attach_property(&crtc->base,
+ config->degamma_lut_property, 0);
+ drm_object_attach_property(&crtc->base,
+ config->ctm_property, 0);
+ drm_object_attach_property(&crtc->base,
+ config->gamma_lut_property, 0);
+
+ drm_object_attach_property(&crtc->base,
+ config->degamma_lut_size_property,
+ degamma_lut_size);
+ drm_object_attach_property(&crtc->base,
+ config->gamma_lut_size_property,
+ gamma_lut_size);
+}
+EXPORT_SYMBOL(drm_helper_crtc_enable_color_mgmt);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index fe5efad..9054598c 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -146,6 +146,9 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state);
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state);
+void drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
+ u16 *red, u16 *green, u16 *blue,
+ uint32_t start, uint32_t size);
/**
* drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 7fad193..f618803 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -305,6 +305,8 @@ struct drm_plane_helper_funcs;
* @mode_changed: crtc_state->mode or crtc_state->enable has been changed
* @active_changed: crtc_state->active has been toggled.
* @connectors_changed: connectors to this crtc have been updated
+ * @color_mgmt_changed: color management properties have changed (degamma or
+ * gamma LUT or CSC matrix)
* @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
* @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors
* @encoder_mask: bitmask of (1 << drm_encoder_index(encoder)) of attached encoders
@@ -312,6 +314,11 @@ struct drm_plane_helper_funcs;
* update to ensure framebuffer cleanup isn't done too early
* @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
* @mode: current mode timings
+ * @degamma_lut: Lookup table for converting framebuffer pixel data
+ * before apply the conversion matrix
+ * @ctm: Transformation matrix
+ * @gamma_lut: Lookup table for converting pixel data after the
+ * conversion matrix
* @event: optional pointer to a DRM event to signal upon completion of the
* state update
* @state: backpointer to global drm_atomic_state
@@ -333,6 +340,7 @@ struct drm_crtc_state {
bool mode_changed : 1;
bool active_changed : 1;
bool connectors_changed : 1;
+ bool color_mgmt_changed : 1;
/* attached planes bitmask:
* WARNING: transitional helpers do not maintain plane_mask so
@@ -355,6 +363,11 @@ struct drm_crtc_state {
/* blob property to expose current mode to atomic userspace */
struct drm_property_blob *mode_blob;
+ /* blob property to expose color management to userspace */
+ struct drm_property_blob *degamma_lut;
+ struct drm_property_blob *ctm;
+ struct drm_property_blob *gamma_lut;
+
struct drm_pending_vblank_event *event;
struct drm_atomic_state *state;
@@ -757,7 +770,7 @@ struct drm_crtc {
int x, y;
const struct drm_crtc_funcs *funcs;
- /* CRTC gamma size for reporting to userspace */
+ /* Legacy FB CRTC gamma size for reporting to userspace */
uint32_t gamma_size;
uint16_t *gamma_store;
@@ -2026,6 +2039,15 @@ struct drm_mode_config_funcs {
* @property_blob_list: list of all the blob property objects
* @blob_lock: mutex for blob property allocation and management
* @*_property: core property tracking
+ * @degamma_lut_property: LUT used to convert the framebuffer's colors to linear
+ * gamma
+ * @degamma_lut_size_property: size of the degamma LUT as supported by the
+ * driver (read-only)
+ * @ctm_property: Matrix used to convert colors after the lookup in the
+ * degamma LUT
+ * @gamma_lut_property: LUT used to convert the colors, after the CSC matrix, to
+ * the gamma space of the connected screen (read-only)
+ * @gamma_lut_size_property: size of the gamma LUT as supported by the driver
* @preferred_depth: preferred RBG pixel depth, used by fb helpers
* @prefer_shadow: hint to userspace to prefer shadow-fb rendering
* @async_page_flip: does this device support async flips on the primary plane?
@@ -2128,6 +2150,13 @@ struct drm_mode_config {
struct drm_property *aspect_ratio_property;
struct drm_property *dirty_info_property;
+ /* Optional color correction properties */
+ struct drm_property *degamma_lut_property;
+ struct drm_property *degamma_lut_size_property;
+ struct drm_property *ctm_property;
+ struct drm_property *gamma_lut_property;
+ struct drm_property *gamma_lut_size_property;
+
/* properties for virtual machine layout */
struct drm_property *suggested_x_property;
struct drm_property *suggested_y_property;
@@ -2554,6 +2583,21 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev,
return mo ? obj_to_property(mo) : NULL;
}
+/*
+ * Extract a degamma/gamma LUT value provided by user and round it to the
+ * precision supported by the hardware.
+ */
+static inline uint32_t drm_color_lut_extract(uint32_t user_input,
+ uint32_t bit_precision)
+{
+ uint32_t val = user_input + (1 << (16 - bit_precision - 1));
+ uint32_t max = 0xffff >> (16 - bit_precision);
+
+ val >>= 16 - bit_precision;
+
+ return clamp_val(val, 0, max);
+}
+
/* Plane list iterator for legacy (overlay only) planes. */
#define drm_for_each_legacy_plane(plane, dev) \
list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 4b37afa..97fa894 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -48,6 +48,9 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
int x, int y,
struct drm_framebuffer *old_fb);
+extern void drm_helper_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+ int degamma_lut_size,
+ int gamma_lut_size);
extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 50adb46..c021743 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -487,6 +487,21 @@ struct drm_mode_crtc_lut {
__u64 blue;
};
+struct drm_color_ctm {
+ /* Conversion matrix in S31.32 format. */
+ __s64 matrix[9];
+};
+
+struct drm_color_lut {
+ /*
+ * Data is U0.16 fixed point format.
+ */
+ __u16 red;
+ __u16 green;
+ __u16 blue;
+ __u16 reserved;
+};
+
#define DRM_MODE_PAGE_FLIP_EVENT 0x01
#define DRM_MODE_PAGE_FLIP_ASYNC 0x02
#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT|DRM_MODE_PAGE_FLIP_ASYNC)
--
2.7.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 4/5] drm/i915: Implement color management on bdw/skl/bxt/kbl
2016-02-25 15:33 [PATCH 0/5] Pipe level color management V9 Lionel Landwerlin
` (2 preceding siblings ...)
2016-02-25 15:33 ` [PATCH 3/5] drm: introduce pipe color correction properties Lionel Landwerlin
@ 2016-02-25 15:33 ` Lionel Landwerlin
2016-02-26 0:03 ` [Intel-gfx] " Matt Roper
2016-02-25 15:33 ` [PATCH 5/5] drm/i915: Implement color management on chv Lionel Landwerlin
2016-02-25 16:32 ` ✗ Fi.CI.BAT: failure for Pipe level color management (rev9) Patchwork
5 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2016-02-25 15:33 UTC (permalink / raw)
To: intel-gfx, dri-devel; +Cc: Kumar, kausalmalladi
Patch based on a previous series by Shashank Sharma.
v2: Do not read GAMMA_MODE register to figure what mode we're in
v3: Program PREC_PAL_GC_MAX to clamp pixel values > 1.0
Add documentation on how the Broadcast RGB property is affected by CTM
v4: Update contributors
v5: Refactor degamma/gamma LUTs load into a single function
v6: Fix missing intel_crtc variable (bisect issue)
v7: Fix & simplify limited range matrix multiplication
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Signed-off-by: Kumar, Kiran S <kiran.s.kumar@intel.com>
Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
---
Documentation/DocBook/gpu.tmpl | 6 +-
drivers/gpu/drm/i915/i915_drv.c | 24 ++-
drivers/gpu/drm/i915/i915_drv.h | 6 +
drivers/gpu/drm/i915/i915_reg.h | 22 +++
drivers/gpu/drm/i915/intel_color.c | 341 ++++++++++++++++++++++++++++++-----
drivers/gpu/drm/i915/intel_display.c | 22 ++-
drivers/gpu/drm/i915/intel_drv.h | 3 +-
drivers/gpu/drm/i915/intel_fbdev.c | 8 +
8 files changed, 369 insertions(+), 63 deletions(-)
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl
index 1692c4d..430e99b 100644
--- a/Documentation/DocBook/gpu.tmpl
+++ b/Documentation/DocBook/gpu.tmpl
@@ -2153,7 +2153,11 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >ENUM</td>
<td valign="top" >{ "Automatic", "Full", "Limited 16:235" }</td>
<td valign="top" >Connector</td>
- <td valign="top" >TBD</td>
+ <td valign="top" >When this property is set to Limited 16:235
+ and CTM is set, the hardware will be programmed with the
+ result of the multiplication of CTM by the limited range
+ matrix to ensure the pixels normaly in the range 0..1.0 are
+ remapped to the range 16/255..235/255.</td>
</tr>
<tr>
<td valign="top" >“audio”</td>
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 20e8200..3807b73 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -66,6 +66,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,
@@ -288,24 +291,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,
};
@@ -321,13 +328,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,
@@ -345,17 +352,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 8cb4418..e71dc9a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -663,6 +663,7 @@ struct drm_i915_display_funcs {
/* display clock increase/decrease */
/* pll clock increase/decrease */
+ void (*load_csc_matrix)(struct drm_crtc *crtc);
void (*load_luts)(struct drm_crtc *crtc);
};
@@ -812,6 +813,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 f76cbf3..76a9e49 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7651,6 +7651,28 @@ enum skl_disp_power_wells {
#define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
#define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_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_PIPE(pipe, _PAL_PREC_INDEX_A, _PAL_PREC_INDEX_B)
+#define PREC_PAL_DATA(pipe) _MMIO_PIPE(pipe, _PAL_PREC_DATA_A, _PAL_PREC_DATA_B)
+#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4)
+#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (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 16657eb..a6dc2af 100644
--- a/drivers/gpu/drm/i915/intel_color.c
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -24,39 +24,155 @@
#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))
+
+#define LEGACY_LUT_LENGTH (sizeof(struct drm_color_lut) * 256)
+
/*
- * Set up the pipe CSC unit.
+ * 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.
*
- * Currently only full range RGB to limited range RGB conversion
- * is supported, but eventually this should handle various
- * RGB<->YCbCr scenarios as well.
+ * 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))
+
+static bool crtc_state_is_legacy(struct drm_crtc_state *state)
+{
+ return !state->degamma_lut &&
+ !state->ctm &&
+ state->gamma_lut &&
+ state->gamma_lut->length == LEGACY_LUT_LENGTH;
+}
+
+/*
+ * 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_mult_by_limited(uint64_t *result, int64_t *input)
+{
+ int i;
+
+ for (i = 0; i < 9; i++)
+ result[i] = 0;
+
+ for (i = 0; i < 3; i++) {
+ int64_t user_coeff = input[i * 3 + i];
+ uint64_t limited_coeff = CTM_COEFF_LIMITED_RANGE >> 2;
+ uint64_t abs_coeff = clamp_val(CTM_COEFF_ABS(user_coeff),
+ 0,
+ CTM_COEFF_4_0 - 1) >> 2;
+
+ result[i * 3 + i] = (limited_coeff * abs_coeff) >> 27;
+ if (CTM_COEFF_NEGATIVE(user_coeff))
+ result[i * 3 + i] |= CTM_COEFF_SIGN;
+ }
+}
+
+/* Set up the pipe CSC unit. */
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) {
+ struct drm_color_ctm *ctm =
+ (struct drm_color_ctm *)crtc_state->ctm->data;
+ uint64_t input[9] = { 0, };
- if (intel_crtc->config->limited_color_range)
- coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
+ if (intel_crtc->config->limited_color_range)
+ ctm_mult_by_limited(input, ctm->matrix);
+ else {
+ for (i = 0; i < ARRAY_SIZE(input); i++)
+ input[i] = ctm->matrix[i];
+ }
+
+ /*
+ * 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;
+ }
+ }
- 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);
@@ -85,13 +201,18 @@ static void i9xx_load_csc_matrix(struct drm_crtc *crtc)
void intel_color_set_csc(struct drm_crtc *crtc)
{
- i9xx_load_csc_matrix(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);
}
-/* Loads the palette/gamma unit for the CRTC with the prepared values. */
+/* Loads the legacy palette/gamma unit for the CRTC. */
static void i9xx_load_luts(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
+ struct drm_crtc_state *state = crtc->state;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum pipe pipe = intel_crtc->pipe;
@@ -104,18 +225,33 @@ static void i9xx_load_luts(struct drm_crtc *crtc)
assert_pll_enabled(dev_priv, pipe);
}
- 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 (state->gamma_lut) {
+ struct drm_color_lut *lut =
+ (struct drm_color_lut *) state->gamma_lut->data;
+ for (i = 0; i < 256; i++) {
+ uint32_t word =
+ (drm_color_lut_extract(lut[i].red, 8) << 16) |
+ (drm_color_lut_extract(lut[i].green, 8) << 8) |
+ drm_color_lut_extract(lut[i].blue, 8);
+
+ if (HAS_GMCH_DISPLAY(dev))
+ I915_WRITE(PALETTE(pipe, i), word);
+ else
+ I915_WRITE(LGC_PALETTE(pipe, i), word);
+ }
+ } else {
+ for (i = 0; i < 256; i++) {
+ uint32_t word = (i << 16) | (i << 8) | i;
+
+ if (HAS_GMCH_DISPLAY(dev))
+ I915_WRITE(PALETTE(pipe, i), word);
+ else
+ I915_WRITE(LGC_PALETTE(pipe, i), word);
+ }
}
}
-/* Loads the legacy palette/gamma unit for the CRTC on Haswell+. */
+/* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
static void haswell_load_luts(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -144,6 +280,89 @@ static void haswell_load_luts(struct drm_crtc *crtc)
hsw_enable_ips(intel_crtc);
}
+/* Loads the palette/gamma unit for the CRTC on Broadwell+. */
+static void broadwell_load_luts(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc_state *state = crtc->state;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ 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;
+
+ if (crtc_state_is_legacy(state)) {
+ haswell_load_luts(crtc);
+ return;
+ }
+
+ 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_extract(lut[i].red, 10) << 20 |
+ drm_color_lut_extract(lut[i].green, 10) << 10 |
+ drm_color_lut_extract(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);
+ }
+ }
+
+ 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_extract(lut[i].red, 10) << 20) |
+ (drm_color_lut_extract(lut[i].green, 10) << 10) |
+ drm_color_lut_extract(lut[i].blue, 10);
+
+ I915_WRITE(PREC_PAL_DATA(pipe), word);
+ }
+
+ /* Program the max register to clamp values > 1.0. */
+ I915_WRITE(PREC_PAL_GC_MAX(pipe, 0),
+ drm_color_lut_extract(lut[i].red, 16));
+ I915_WRITE(PREC_PAL_GC_MAX(pipe, 1),
+ drm_color_lut_extract(lut[i].green, 16));
+ I915_WRITE(PREC_PAL_GC_MAX(pipe, 2),
+ drm_color_lut_extract(lut[i].blue, 16));
+ } 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);
+ }
+
+ I915_WRITE(PREC_PAL_GC_MAX(pipe, 0), (1 << 16) - 1);
+ I915_WRITE(PREC_PAL_GC_MAX(pipe, 1), (1 << 16) - 1);
+ I915_WRITE(PREC_PAL_GC_MAX(pipe, 2), (1 << 16) - 1);
+ }
+
+ 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);
+}
+
void intel_color_load_luts(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -156,39 +375,61 @@ void intel_color_load_luts(struct drm_crtc *crtc)
dev_priv->display.load_luts(crtc);
}
-void intel_color_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, uint32_t start, uint32_t size)
+int intel_color_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
{
- int end = (start + size > 256) ? 256 : start + size, i;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ size_t gamma_length, degamma_length;
- for (i = start; i < end; i++) {
- intel_crtc->lut_r[i] = red[i] >> 8;
- intel_crtc->lut_g[i] = green[i] >> 8;
- intel_crtc->lut_b[i] = blue[i] >> 8;
- }
+ degamma_length = INTEL_INFO(dev)->color.degamma_lut_size *
+ sizeof(struct drm_color_lut);
+ gamma_length = INTEL_INFO(dev)->color.gamma_lut_size *
+ sizeof(struct drm_color_lut);
+
+ /*
+ * We allow both degamma & gamma luts at the right size or
+ * NULL.
+ */
+ if ((!crtc_state->degamma_lut ||
+ crtc_state->degamma_lut->length == degamma_length) &&
+ (!crtc_state->gamma_lut ||
+ crtc_state->gamma_lut->length == gamma_length))
+ return 0;
+
+ /*
+ * We also allow no degamma lut and a gamma lut at the legacy
+ * size (256 entries).
+ */
+ if (!crtc_state->degamma_lut &&
+ crtc_state->gamma_lut &&
+ crtc_state->gamma_lut->length == LEGACY_LUT_LENGTH)
+ return 0;
- intel_color_load_luts(crtc);
+ return -EINVAL;
}
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;
drm_mode_crtc_set_gamma_size(crtc, 256);
- for (i = 0; i < 256; i++) {
- intel_crtc->lut_r[i] = i;
- intel_crtc->lut_g[i] = i;
- intel_crtc->lut_b[i] = i;
- }
- if (IS_HASWELL(dev) ||
- (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev))) {
+ if (IS_HASWELL(dev)) {
+ dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
dev_priv->display.load_luts = haswell_load_luts;
+ } else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev) ||
+ IS_BROXTON(dev) || IS_KABYLAKE(dev)) {
+ dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
+ dev_priv->display.load_luts = broadwell_load_luts;
} else {
dev_priv->display.load_luts = i9xx_load_luts;
}
+
+ /* Enable color management support when we have degamma & gamma LUTs. */
+ if (INTEL_INFO(dev)->color.degamma_lut_size != 0 &&
+ INTEL_INFO(dev)->color.gamma_lut_size != 0)
+ 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 154ac87..224ec69 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11830,6 +11830,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
return ret;
}
+ if (crtc_state->color_mgmt_changed) {
+ ret = intel_color_check(crtc, crtc_state);
+ if (ret)
+ return ret;
+ }
+
ret = 0;
if (dev_priv->display.compute_pipe_wm) {
ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
@@ -11851,7 +11857,6 @@ 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_luts,
.atomic_begin = intel_begin_crtc_commit,
.atomic_flush = intel_finish_crtc_commit,
.atomic_check = intel_crtc_atomic_check,
@@ -13386,6 +13391,18 @@ static int intel_atomic_commit(struct drm_device *dev,
dev_priv->display.crtc_enable(crtc);
}
+ 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(to_intel_crtc_state(crtc_state));
@@ -13477,8 +13494,9 @@ out:
#undef for_each_intel_crtc_masked
static const struct drm_crtc_funcs intel_crtc_funcs = {
- .gamma_set = intel_color_legacy_gamma_set,
+ .gamma_set = drm_atomic_helper_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 8c48131..baa6adb 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1626,9 +1626,8 @@ extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
/* intel_color.c */
void intel_color_init(struct drm_crtc *crtc);
+int intel_color_check(struct drm_crtc *crtc, struct drm_crtc_state *state);
void intel_color_set_csc(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);
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 97a91e6..777f98c 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -379,6 +379,7 @@ retry:
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_fb_helper_crtc *new_crtc;
+ struct intel_crtc *intel_crtc;
fb_conn = fb_helper->connector_info[i];
connector = fb_conn->connector;
@@ -420,6 +421,13 @@ retry:
num_connectors_enabled++;
+ intel_crtc = to_intel_crtc(connector->state->crtc);
+ for (j = 0; j < 256; j++) {
+ intel_crtc->lut_r[j] = j;
+ intel_crtc->lut_g[j] = j;
+ intel_crtc->lut_b[j] = j;
+ }
+
new_crtc = intel_fb_helper_crtc(fb_helper, connector->state->crtc);
/*
--
2.7.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [Intel-gfx] [PATCH 4/5] drm/i915: Implement color management on bdw/skl/bxt/kbl
2016-02-25 15:33 ` [PATCH 4/5] drm/i915: Implement color management on bdw/skl/bxt/kbl Lionel Landwerlin
@ 2016-02-26 0:03 ` Matt Roper
0 siblings, 0 replies; 16+ messages in thread
From: Matt Roper @ 2016-02-26 0:03 UTC (permalink / raw)
To: Lionel Landwerlin; +Cc: intel-gfx, kausalmalladi, dri-devel
On Thu, Feb 25, 2016 at 03:33:42PM +0000, Lionel Landwerlin wrote:
> Patch based on a previous series by Shashank Sharma.
>
> v2: Do not read GAMMA_MODE register to figure what mode we're in
>
> v3: Program PREC_PAL_GC_MAX to clamp pixel values > 1.0
>
> Add documentation on how the Broadcast RGB property is affected by CTM
>
> v4: Update contributors
>
> v5: Refactor degamma/gamma LUTs load into a single function
>
> v6: Fix missing intel_crtc variable (bisect issue)
>
> v7: Fix & simplify limited range matrix multiplication
>
> Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> Signed-off-by: Kumar, Kiran S <kiran.s.kumar@intel.com>
> Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
There are two trivial typo/style items that I call out farther down, but
aside from those, you've addressed everything I saw in earlier versions
of this patch. It's a pretty large/complicated patch overall, so there
may be things I missed, but I think it's in good enough shape to merge.
Acknowledged-by: Matt Roper <matthew.d.roper@intel.com>
> ---
> Documentation/DocBook/gpu.tmpl | 6 +-
> drivers/gpu/drm/i915/i915_drv.c | 24 ++-
> drivers/gpu/drm/i915/i915_drv.h | 6 +
> drivers/gpu/drm/i915/i915_reg.h | 22 +++
> drivers/gpu/drm/i915/intel_color.c | 341 ++++++++++++++++++++++++++++++-----
> drivers/gpu/drm/i915/intel_display.c | 22 ++-
> drivers/gpu/drm/i915/intel_drv.h | 3 +-
> drivers/gpu/drm/i915/intel_fbdev.c | 8 +
> 8 files changed, 369 insertions(+), 63 deletions(-)
>
> diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl
> index 1692c4d..430e99b 100644
> --- a/Documentation/DocBook/gpu.tmpl
> +++ b/Documentation/DocBook/gpu.tmpl
> @@ -2153,7 +2153,11 @@ void intel_crt_init(struct drm_device *dev)
> <td valign="top" >ENUM</td>
> <td valign="top" >{ "Automatic", "Full", "Limited 16:235" }</td>
> <td valign="top" >Connector</td>
> - <td valign="top" >TBD</td>
> + <td valign="top" >When this property is set to Limited 16:235
> + and CTM is set, the hardware will be programmed with the
> + result of the multiplication of CTM by the limited range
> + matrix to ensure the pixels normaly in the range 0..1.0 are
> + remapped to the range 16/255..235/255.</td>
> </tr>
> <tr>
> <td valign="top" >“audio”</td>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 20e8200..3807b73 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -66,6 +66,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,
> @@ -288,24 +291,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,
> };
> @@ -321,13 +328,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,
> @@ -345,17 +352,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 8cb4418..e71dc9a 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -663,6 +663,7 @@ struct drm_i915_display_funcs {
> /* display clock increase/decrease */
> /* pll clock increase/decrease */
>
> + void (*load_csc_matrix)(struct drm_crtc *crtc);
> void (*load_luts)(struct drm_crtc *crtc);
> };
>
> @@ -812,6 +813,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 f76cbf3..76a9e49 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -7651,6 +7651,28 @@ enum skl_disp_power_wells {
> #define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
> #define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_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_PIPE(pipe, _PAL_PREC_INDEX_A, _PAL_PREC_INDEX_B)
> +#define PREC_PAL_DATA(pipe) _MMIO_PIPE(pipe, _PAL_PREC_DATA_A, _PAL_PREC_DATA_B)
> +#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4)
> +#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (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 16657eb..a6dc2af 100644
> --- a/drivers/gpu/drm/i915/intel_color.c
> +++ b/drivers/gpu/drm/i915/intel_color.c
> @@ -24,39 +24,155 @@
>
> #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))
> +
> +#define LEGACY_LUT_LENGTH (sizeof(struct drm_color_lut) * 256)
> +
> /*
> - * Set up the pipe CSC unit.
> + * 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.
> *
> - * Currently only full range RGB to limited range RGB conversion
> - * is supported, but eventually this should handle various
> - * RGB<->YCbCr scenarios as well.
> + * 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))
> +
> +static bool crtc_state_is_legacy(struct drm_crtc_state *state)
> +{
> + return !state->degamma_lut &&
> + !state->ctm &&
> + state->gamma_lut &&
> + state->gamma_lut->length == LEGACY_LUT_LENGTH;
> +}
> +
> +/*
> + * 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_mult_by_limited(uint64_t *result, int64_t *input)
> +{
> + int i;
> +
> + for (i = 0; i < 9; i++)
> + result[i] = 0;
> +
> + for (i = 0; i < 3; i++) {
> + int64_t user_coeff = input[i * 3 + i];
> + uint64_t limited_coeff = CTM_COEFF_LIMITED_RANGE >> 2;
> + uint64_t abs_coeff = clamp_val(CTM_COEFF_ABS(user_coeff),
> + 0,
> + CTM_COEFF_4_0 - 1) >> 2;
> +
> + result[i * 3 + i] = (limited_coeff * abs_coeff) >> 27;
> + if (CTM_COEFF_NEGATIVE(user_coeff))
> + result[i * 3 + i] |= CTM_COEFF_SIGN;
> + }
> +}
> +
> +/* Set up the pipe CSC unit. */
> 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) {
> + struct drm_color_ctm *ctm =
> + (struct drm_color_ctm *)crtc_state->ctm->data;
> + uint64_t input[9] = { 0, };
>
> - if (intel_crtc->config->limited_color_range)
> - coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
> + if (intel_crtc->config->limited_color_range)
> + ctm_mult_by_limited(input, ctm->matrix);
> + else {
This minor coding style issue still needs to be fixed (all branches of
if/else must use braces if any of them need it).
> + for (i = 0; i < ARRAY_SIZE(input); i++)
> + input[i] = ctm->matrix[i];
> + }
> +
> + /*
> + * 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.
Typo:
s/identify/identity/
> + *
> + * 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;
> + }
> + }
>
> - 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);
> @@ -85,13 +201,18 @@ static void i9xx_load_csc_matrix(struct drm_crtc *crtc)
>
> void intel_color_set_csc(struct drm_crtc *crtc)
> {
> - i9xx_load_csc_matrix(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);
> }
>
> -/* Loads the palette/gamma unit for the CRTC with the prepared values. */
> +/* Loads the legacy palette/gamma unit for the CRTC. */
> static void i9xx_load_luts(struct drm_crtc *crtc)
> {
> struct drm_device *dev = crtc->dev;
> + struct drm_crtc_state *state = crtc->state;
> struct drm_i915_private *dev_priv = dev->dev_private;
> struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> enum pipe pipe = intel_crtc->pipe;
> @@ -104,18 +225,33 @@ static void i9xx_load_luts(struct drm_crtc *crtc)
> assert_pll_enabled(dev_priv, pipe);
> }
>
> - 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 (state->gamma_lut) {
> + struct drm_color_lut *lut =
> + (struct drm_color_lut *) state->gamma_lut->data;
> + for (i = 0; i < 256; i++) {
> + uint32_t word =
> + (drm_color_lut_extract(lut[i].red, 8) << 16) |
> + (drm_color_lut_extract(lut[i].green, 8) << 8) |
> + drm_color_lut_extract(lut[i].blue, 8);
> +
> + if (HAS_GMCH_DISPLAY(dev))
> + I915_WRITE(PALETTE(pipe, i), word);
> + else
> + I915_WRITE(LGC_PALETTE(pipe, i), word);
> + }
> + } else {
> + for (i = 0; i < 256; i++) {
> + uint32_t word = (i << 16) | (i << 8) | i;
> +
> + if (HAS_GMCH_DISPLAY(dev))
> + I915_WRITE(PALETTE(pipe, i), word);
> + else
> + I915_WRITE(LGC_PALETTE(pipe, i), word);
> + }
> }
> }
>
> -/* Loads the legacy palette/gamma unit for the CRTC on Haswell+. */
> +/* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
> static void haswell_load_luts(struct drm_crtc *crtc)
> {
> struct drm_device *dev = crtc->dev;
> @@ -144,6 +280,89 @@ static void haswell_load_luts(struct drm_crtc *crtc)
> hsw_enable_ips(intel_crtc);
> }
>
> +/* Loads the palette/gamma unit for the CRTC on Broadwell+. */
> +static void broadwell_load_luts(struct drm_crtc *crtc)
> +{
> + struct drm_device *dev = crtc->dev;
> + struct drm_crtc_state *state = crtc->state;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + 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;
> +
> + if (crtc_state_is_legacy(state)) {
> + haswell_load_luts(crtc);
> + return;
> + }
> +
> + 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_extract(lut[i].red, 10) << 20 |
> + drm_color_lut_extract(lut[i].green, 10) << 10 |
> + drm_color_lut_extract(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);
> + }
> + }
> +
> + 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_extract(lut[i].red, 10) << 20) |
> + (drm_color_lut_extract(lut[i].green, 10) << 10) |
> + drm_color_lut_extract(lut[i].blue, 10);
> +
> + I915_WRITE(PREC_PAL_DATA(pipe), word);
> + }
> +
> + /* Program the max register to clamp values > 1.0. */
> + I915_WRITE(PREC_PAL_GC_MAX(pipe, 0),
> + drm_color_lut_extract(lut[i].red, 16));
> + I915_WRITE(PREC_PAL_GC_MAX(pipe, 1),
> + drm_color_lut_extract(lut[i].green, 16));
> + I915_WRITE(PREC_PAL_GC_MAX(pipe, 2),
> + drm_color_lut_extract(lut[i].blue, 16));
> + } 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);
> + }
> +
> + I915_WRITE(PREC_PAL_GC_MAX(pipe, 0), (1 << 16) - 1);
> + I915_WRITE(PREC_PAL_GC_MAX(pipe, 1), (1 << 16) - 1);
> + I915_WRITE(PREC_PAL_GC_MAX(pipe, 2), (1 << 16) - 1);
> + }
> +
> + 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);
> +}
> +
> void intel_color_load_luts(struct drm_crtc *crtc)
> {
> struct drm_device *dev = crtc->dev;
> @@ -156,39 +375,61 @@ void intel_color_load_luts(struct drm_crtc *crtc)
> dev_priv->display.load_luts(crtc);
> }
>
> -void intel_color_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
> - u16 *blue, uint32_t start, uint32_t size)
> +int intel_color_check(struct drm_crtc *crtc,
> + struct drm_crtc_state *crtc_state)
> {
> - int end = (start + size > 256) ? 256 : start + size, i;
> - struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> + struct drm_device *dev = crtc->dev;
> + size_t gamma_length, degamma_length;
>
> - for (i = start; i < end; i++) {
> - intel_crtc->lut_r[i] = red[i] >> 8;
> - intel_crtc->lut_g[i] = green[i] >> 8;
> - intel_crtc->lut_b[i] = blue[i] >> 8;
> - }
> + degamma_length = INTEL_INFO(dev)->color.degamma_lut_size *
> + sizeof(struct drm_color_lut);
> + gamma_length = INTEL_INFO(dev)->color.gamma_lut_size *
> + sizeof(struct drm_color_lut);
> +
> + /*
> + * We allow both degamma & gamma luts at the right size or
> + * NULL.
> + */
> + if ((!crtc_state->degamma_lut ||
> + crtc_state->degamma_lut->length == degamma_length) &&
> + (!crtc_state->gamma_lut ||
> + crtc_state->gamma_lut->length == gamma_length))
> + return 0;
> +
> + /*
> + * We also allow no degamma lut and a gamma lut at the legacy
> + * size (256 entries).
> + */
> + if (!crtc_state->degamma_lut &&
> + crtc_state->gamma_lut &&
> + crtc_state->gamma_lut->length == LEGACY_LUT_LENGTH)
> + return 0;
>
> - intel_color_load_luts(crtc);
> + return -EINVAL;
> }
>
> 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;
>
> drm_mode_crtc_set_gamma_size(crtc, 256);
> - for (i = 0; i < 256; i++) {
> - intel_crtc->lut_r[i] = i;
> - intel_crtc->lut_g[i] = i;
> - intel_crtc->lut_b[i] = i;
> - }
>
> - if (IS_HASWELL(dev) ||
> - (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev))) {
> + if (IS_HASWELL(dev)) {
> + dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
> dev_priv->display.load_luts = haswell_load_luts;
> + } else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev) ||
> + IS_BROXTON(dev) || IS_KABYLAKE(dev)) {
> + dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
> + dev_priv->display.load_luts = broadwell_load_luts;
> } else {
> dev_priv->display.load_luts = i9xx_load_luts;
> }
> +
> + /* Enable color management support when we have degamma & gamma LUTs. */
> + if (INTEL_INFO(dev)->color.degamma_lut_size != 0 &&
> + INTEL_INFO(dev)->color.gamma_lut_size != 0)
> + 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 154ac87..224ec69 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -11830,6 +11830,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
> return ret;
> }
>
> + if (crtc_state->color_mgmt_changed) {
> + ret = intel_color_check(crtc, crtc_state);
> + if (ret)
> + return ret;
> + }
> +
> ret = 0;
> if (dev_priv->display.compute_pipe_wm) {
> ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
> @@ -11851,7 +11857,6 @@ 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_luts,
> .atomic_begin = intel_begin_crtc_commit,
> .atomic_flush = intel_finish_crtc_commit,
> .atomic_check = intel_crtc_atomic_check,
> @@ -13386,6 +13391,18 @@ static int intel_atomic_commit(struct drm_device *dev,
> dev_priv->display.crtc_enable(crtc);
> }
>
> + 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(to_intel_crtc_state(crtc_state));
>
> @@ -13477,8 +13494,9 @@ out:
> #undef for_each_intel_crtc_masked
>
> static const struct drm_crtc_funcs intel_crtc_funcs = {
> - .gamma_set = intel_color_legacy_gamma_set,
> + .gamma_set = drm_atomic_helper_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 8c48131..baa6adb 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1626,9 +1626,8 @@ extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
>
> /* intel_color.c */
> void intel_color_init(struct drm_crtc *crtc);
> +int intel_color_check(struct drm_crtc *crtc, struct drm_crtc_state *state);
> void intel_color_set_csc(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);
>
> #endif /* __INTEL_DRV_H__ */
> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> index 97a91e6..777f98c 100644
> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> @@ -379,6 +379,7 @@ retry:
> struct drm_connector *connector;
> struct drm_encoder *encoder;
> struct drm_fb_helper_crtc *new_crtc;
> + struct intel_crtc *intel_crtc;
>
> fb_conn = fb_helper->connector_info[i];
> connector = fb_conn->connector;
> @@ -420,6 +421,13 @@ retry:
>
> num_connectors_enabled++;
>
> + intel_crtc = to_intel_crtc(connector->state->crtc);
> + for (j = 0; j < 256; j++) {
> + intel_crtc->lut_r[j] = j;
> + intel_crtc->lut_g[j] = j;
> + intel_crtc->lut_b[j] = j;
> + }
> +
> new_crtc = intel_fb_helper_crtc(fb_helper, connector->state->crtc);
>
> /*
> --
> 2.7.0
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 5/5] drm/i915: Implement color management on chv
2016-02-25 15:33 [PATCH 0/5] Pipe level color management V9 Lionel Landwerlin
` (3 preceding siblings ...)
2016-02-25 15:33 ` [PATCH 4/5] drm/i915: Implement color management on bdw/skl/bxt/kbl Lionel Landwerlin
@ 2016-02-25 15:33 ` Lionel Landwerlin
2016-02-26 0:53 ` Matt Roper
2016-02-25 16:32 ` ✗ Fi.CI.BAT: failure for Pipe level color management (rev9) Patchwork
5 siblings, 1 reply; 16+ messages in thread
From: Lionel Landwerlin @ 2016-02-25 15:33 UTC (permalink / raw)
To: intel-gfx, dri-devel; +Cc: Kumar, kausalmalladi, kiran.s.kumar
Patch based on a previous series by Shashank Sharma.
v2: Update contributors
v3: Refactor degamma/gamma LUTs load into a single function
v4: Remove unused variable
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Signed-off-by: Kumar, Kiran S <kiran.s.kumar@intel.com>
Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
---
drivers/gpu/drm/i915/i915_drv.c | 3 +
drivers/gpu/drm/i915/i915_reg.h | 31 +++++++++
drivers/gpu/drm/i915/intel_color.c | 133 +++++++++++++++++++++++++++++++++++--
3 files changed, 161 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 3807b73..8a2aaa7 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -68,6 +68,8 @@ static struct drm_driver driver;
#define BDW_COLORS \
.color = { .degamma_lut_size = 512, .gamma_lut_size = 512 }
+#define CHV_COLORS \
+ .color = { .degamma_lut_size = 65, .gamma_lut_size = 257 }
static const struct intel_device_info intel_i830_info = {
.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
@@ -325,6 +327,7 @@ static const struct intel_device_info intel_cherryview_info = {
.display_mmio_offset = VLV_DISPLAY_BASE,
GEN_CHV_PIPEOFFSETS,
CURSOR_OFFSETS,
+ CHV_COLORS,
};
static const struct intel_device_info intel_skylake_info = {
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 76a9e49..ea599a9 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7673,6 +7673,37 @@ enum skl_disp_power_wells {
#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4)
#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (i) * 4)
+/* pipe CSC & degamma/gamma LUTs on CHV */
+#define _CGM_PIPE_A_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x67900)
+#define _CGM_PIPE_A_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x67904)
+#define _CGM_PIPE_A_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x67908)
+#define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C)
+#define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910)
+#define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000)
+#define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000)
+#define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00)
+#define CGM_PIPE_MODE_GAMMA (1 << 2)
+#define CGM_PIPE_MODE_CSC (1 << 1)
+#define CGM_PIPE_MODE_DEGAMMA (1 << 0)
+
+#define _CGM_PIPE_B_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x69900)
+#define _CGM_PIPE_B_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x69904)
+#define _CGM_PIPE_B_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x69908)
+#define _CGM_PIPE_B_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6990C)
+#define _CGM_PIPE_B_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x69910)
+#define _CGM_PIPE_B_DEGAMMA (VLV_DISPLAY_BASE + 0x68000)
+#define _CGM_PIPE_B_GAMMA (VLV_DISPLAY_BASE + 0x69000)
+#define _CGM_PIPE_B_MODE (VLV_DISPLAY_BASE + 0x69A00)
+
+#define CGM_PIPE_CSC_COEFF01(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF01, _CGM_PIPE_B_CSC_COEFF01)
+#define CGM_PIPE_CSC_COEFF23(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF23, _CGM_PIPE_B_CSC_COEFF23)
+#define CGM_PIPE_CSC_COEFF45(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF45, _CGM_PIPE_B_CSC_COEFF45)
+#define CGM_PIPE_CSC_COEFF67(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF67, _CGM_PIPE_B_CSC_COEFF67)
+#define CGM_PIPE_CSC_COEFF8(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF8, _CGM_PIPE_B_CSC_COEFF8)
+#define CGM_PIPE_DEGAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_DEGAMMA, _CGM_PIPE_B_DEGAMMA) + (i) * 8 + (w) * 4)
+#define CGM_PIPE_GAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_GAMMA, _CGM_PIPE_B_GAMMA) + (i) * 8 + (w) * 4)
+#define CGM_PIPE_MODE(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_MODE, _CGM_PIPE_B_MODE)
+
/* 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 a6dc2af..9ad37e5 100644
--- a/drivers/gpu/drm/i915/intel_color.c
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -29,6 +29,7 @@
#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_8_0 (CTM_COEFF_4_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)
@@ -199,6 +200,58 @@ static void i9xx_load_csc_matrix(struct drm_crtc *crtc)
}
}
+/*
+ * Set up the pipe CSC unit on CherryView.
+ */
+static void cherryview_load_csc_matrix(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc_state *state = crtc->state;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = to_intel_crtc(crtc)->pipe;
+ uint32_t mode;
+
+ if (state->ctm) {
+ struct drm_color_ctm *ctm =
+ (struct drm_color_ctm *) state->ctm->data;
+ uint16_t coeffs[9] = { 0, };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeffs); i++) {
+ uint64_t abs_coeff =
+ ((1ULL << 63) - 1) & ctm->matrix[i];
+
+ /* Round coefficient. */
+ abs_coeff += 1 << (32 - 13);
+ /* Clamp to hardware limits. */
+ abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_8_0 - 1);
+
+ /* Write coefficients in S3.12 format. */
+ if (ctm->matrix[i] & (1ULL << 63))
+ coeffs[i] = 1 << 15;
+ coeffs[i] |= ((abs_coeff >> 32) & 7) << 12;
+ coeffs[i] |= (abs_coeff >> 20) & 0xfff;
+ }
+
+ I915_WRITE(CGM_PIPE_CSC_COEFF01(pipe),
+ coeffs[1] << 16 | coeffs[0]);
+ I915_WRITE(CGM_PIPE_CSC_COEFF23(pipe),
+ coeffs[3] << 16 | coeffs[2]);
+ I915_WRITE(CGM_PIPE_CSC_COEFF45(pipe),
+ coeffs[5] << 16 | coeffs[4]);
+ I915_WRITE(CGM_PIPE_CSC_COEFF67(pipe),
+ coeffs[7] << 16 | coeffs[6]);
+ I915_WRITE(CGM_PIPE_CSC_COEFF8(pipe), coeffs[8]);
+ }
+
+ mode = (state->ctm ? CGM_PIPE_MODE_CSC : 0);
+ if (!crtc_state_is_legacy(state)) {
+ mode |= (state->degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) |
+ (state->gamma_lut ? CGM_PIPE_MODE_GAMMA : 0);
+ }
+ I915_WRITE(CGM_PIPE_MODE(pipe), mode);
+}
+
void intel_color_set_csc(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -209,10 +262,10 @@ void intel_color_set_csc(struct drm_crtc *crtc)
}
/* Loads the legacy palette/gamma unit for the CRTC. */
-static void i9xx_load_luts(struct drm_crtc *crtc)
+static void i9xx_load_luts_internal(struct drm_crtc *crtc,
+ struct drm_property_blob *blob)
{
struct drm_device *dev = crtc->dev;
- struct drm_crtc_state *state = crtc->state;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum pipe pipe = intel_crtc->pipe;
@@ -225,9 +278,8 @@ static void i9xx_load_luts(struct drm_crtc *crtc)
assert_pll_enabled(dev_priv, pipe);
}
- if (state->gamma_lut) {
- struct drm_color_lut *lut =
- (struct drm_color_lut *) state->gamma_lut->data;
+ if (blob) {
+ struct drm_color_lut *lut = (struct drm_color_lut *) blob->data;
for (i = 0; i < 256; i++) {
uint32_t word =
(drm_color_lut_extract(lut[i].red, 8) << 16) |
@@ -251,6 +303,11 @@ static void i9xx_load_luts(struct drm_crtc *crtc)
}
}
+static void i9xx_load_luts(struct drm_crtc *crtc)
+{
+ i9xx_load_luts_internal(crtc, crtc->state->gamma_lut);
+}
+
/* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
static void haswell_load_luts(struct drm_crtc *crtc)
{
@@ -363,6 +420,67 @@ static void broadwell_load_luts(struct drm_crtc *crtc)
I915_WRITE(PREC_PAL_INDEX(pipe), 0);
}
+/* Loads the palette/gamma unit for the CRTC on CherryView. */
+static void cherryview_load_luts(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;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ struct drm_color_lut *lut;
+ uint32_t i, lut_size;
+ uint32_t word0, word1;
+
+ if (crtc_state_is_legacy(state)) {
+ /* Turn off degamma/gamma on CGM block. */
+ I915_WRITE(CGM_PIPE_MODE(pipe),
+ (state->ctm ? CGM_PIPE_MODE_CSC : 0));
+ i9xx_load_luts_internal(crtc, state->gamma_lut);
+ return;
+ }
+
+ if (state->degamma_lut) {
+ lut = (struct drm_color_lut *) state->degamma_lut->data;
+ lut_size = INTEL_INFO(dev)->color.degamma_lut_size;
+ for (i = 0; i < lut_size; i++) {
+ /* Write LUT in U0.14 format. */
+ word0 =
+ (drm_color_lut_extract(lut[i].green, 14) << 16) |
+ drm_color_lut_extract(lut[i].blue, 14);
+ word1 = drm_color_lut_extract(lut[i].red, 14);
+
+ I915_WRITE(CGM_PIPE_DEGAMMA(pipe, i, 0), word0);
+ I915_WRITE(CGM_PIPE_DEGAMMA(pipe, i, 1), word1);
+ }
+ }
+
+ if (state->gamma_lut) {
+ lut = (struct drm_color_lut *) state->gamma_lut->data;
+ lut_size = INTEL_INFO(dev)->color.gamma_lut_size;
+ for (i = 0; i < lut_size; i++) {
+ /* Write LUT in U0.10 format. */
+ word0 =
+ (drm_color_lut_extract(lut[i].green, 10) << 16) |
+ drm_color_lut_extract(lut[i].blue, 10);
+ word1 = drm_color_lut_extract(lut[i].red, 10);
+
+ I915_WRITE(CGM_PIPE_GAMMA(pipe, i, 0), word0);
+ I915_WRITE(CGM_PIPE_GAMMA(pipe, i, 1), word1);
+ }
+ }
+
+ I915_WRITE(CGM_PIPE_MODE(pipe),
+ (state->ctm ? CGM_PIPE_MODE_CSC : 0) |
+ (state->degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) |
+ (state->gamma_lut ? CGM_PIPE_MODE_GAMMA : 0));
+
+ /*
+ * Also program a linear LUT in the legacy block (behind the
+ * CGM block).
+ */
+ i9xx_load_luts_internal(crtc, NULL);
+}
+
void intel_color_load_luts(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -415,7 +533,10 @@ void intel_color_init(struct drm_crtc *crtc)
drm_mode_crtc_set_gamma_size(crtc, 256);
- if (IS_HASWELL(dev)) {
+ if (IS_CHERRYVIEW(dev)) {
+ dev_priv->display.load_csc_matrix = cherryview_load_csc_matrix;
+ dev_priv->display.load_luts = cherryview_load_luts;
+ } else if (IS_HASWELL(dev)) {
dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
dev_priv->display.load_luts = haswell_load_luts;
} else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev) ||
--
2.7.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 5/5] drm/i915: Implement color management on chv
2016-02-25 15:33 ` [PATCH 5/5] drm/i915: Implement color management on chv Lionel Landwerlin
@ 2016-02-26 0:53 ` Matt Roper
0 siblings, 0 replies; 16+ messages in thread
From: Matt Roper @ 2016-02-26 0:53 UTC (permalink / raw)
To: Lionel Landwerlin; +Cc: intel-gfx, kausalmalladi, dri-devel
On Thu, Feb 25, 2016 at 03:33:43PM +0000, Lionel Landwerlin wrote:
> Patch based on a previous series by Shashank Sharma.
>
> v2: Update contributors
>
> v3: Refactor degamma/gamma LUTs load into a single function
>
> v4: Remove unused variable
>
> Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> Signed-off-by: Kumar, Kiran S <kiran.s.kumar@intel.com>
> Signed-off-by: Kausal Malladi <kausalmalladi@gmail.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.c | 3 +
> drivers/gpu/drm/i915/i915_reg.h | 31 +++++++++
> drivers/gpu/drm/i915/intel_color.c | 133 +++++++++++++++++++++++++++++++++++--
> 3 files changed, 161 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 3807b73..8a2aaa7 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -68,6 +68,8 @@ static struct drm_driver driver;
>
> #define BDW_COLORS \
> .color = { .degamma_lut_size = 512, .gamma_lut_size = 512 }
> +#define CHV_COLORS \
> + .color = { .degamma_lut_size = 65, .gamma_lut_size = 257 }
>
> static const struct intel_device_info intel_i830_info = {
> .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
> @@ -325,6 +327,7 @@ static const struct intel_device_info intel_cherryview_info = {
> .display_mmio_offset = VLV_DISPLAY_BASE,
> GEN_CHV_PIPEOFFSETS,
> CURSOR_OFFSETS,
> + CHV_COLORS,
> };
>
> static const struct intel_device_info intel_skylake_info = {
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 76a9e49..ea599a9 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -7673,6 +7673,37 @@ enum skl_disp_power_wells {
> #define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4)
> #define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (i) * 4)
>
> +/* pipe CSC & degamma/gamma LUTs on CHV */
> +#define _CGM_PIPE_A_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x67900)
> +#define _CGM_PIPE_A_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x67904)
> +#define _CGM_PIPE_A_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x67908)
> +#define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C)
> +#define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910)
> +#define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000)
> +#define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000)
> +#define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00)
> +#define CGM_PIPE_MODE_GAMMA (1 << 2)
> +#define CGM_PIPE_MODE_CSC (1 << 1)
> +#define CGM_PIPE_MODE_DEGAMMA (1 << 0)
> +
> +#define _CGM_PIPE_B_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x69900)
> +#define _CGM_PIPE_B_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x69904)
> +#define _CGM_PIPE_B_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x69908)
> +#define _CGM_PIPE_B_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6990C)
> +#define _CGM_PIPE_B_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x69910)
> +#define _CGM_PIPE_B_DEGAMMA (VLV_DISPLAY_BASE + 0x68000)
> +#define _CGM_PIPE_B_GAMMA (VLV_DISPLAY_BASE + 0x69000)
> +#define _CGM_PIPE_B_MODE (VLV_DISPLAY_BASE + 0x69A00)
> +
> +#define CGM_PIPE_CSC_COEFF01(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF01, _CGM_PIPE_B_CSC_COEFF01)
> +#define CGM_PIPE_CSC_COEFF23(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF23, _CGM_PIPE_B_CSC_COEFF23)
> +#define CGM_PIPE_CSC_COEFF45(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF45, _CGM_PIPE_B_CSC_COEFF45)
> +#define CGM_PIPE_CSC_COEFF67(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF67, _CGM_PIPE_B_CSC_COEFF67)
> +#define CGM_PIPE_CSC_COEFF8(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF8, _CGM_PIPE_B_CSC_COEFF8)
> +#define CGM_PIPE_DEGAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_DEGAMMA, _CGM_PIPE_B_DEGAMMA) + (i) * 8 + (w) * 4)
> +#define CGM_PIPE_GAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_GAMMA, _CGM_PIPE_B_GAMMA) + (i) * 8 + (w) * 4)
> +#define CGM_PIPE_MODE(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_MODE, _CGM_PIPE_B_MODE)
> +
> /* 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 a6dc2af..9ad37e5 100644
> --- a/drivers/gpu/drm/i915/intel_color.c
> +++ b/drivers/gpu/drm/i915/intel_color.c
> @@ -29,6 +29,7 @@
> #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_8_0 (CTM_COEFF_4_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)
> @@ -199,6 +200,58 @@ static void i9xx_load_csc_matrix(struct drm_crtc *crtc)
> }
> }
>
> +/*
> + * Set up the pipe CSC unit on CherryView.
> + */
> +static void cherryview_load_csc_matrix(struct drm_crtc *crtc)
> +{
> + struct drm_device *dev = crtc->dev;
> + struct drm_crtc_state *state = crtc->state;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + int pipe = to_intel_crtc(crtc)->pipe;
> + uint32_t mode;
> +
> + if (state->ctm) {
> + struct drm_color_ctm *ctm =
> + (struct drm_color_ctm *) state->ctm->data;
> + uint16_t coeffs[9] = { 0, };
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(coeffs); i++) {
> + uint64_t abs_coeff =
> + ((1ULL << 63) - 1) & ctm->matrix[i];
> +
> + /* Round coefficient. */
> + abs_coeff += 1 << (32 - 13);
> + /* Clamp to hardware limits. */
> + abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_8_0 - 1);
> +
> + /* Write coefficients in S3.12 format. */
> + if (ctm->matrix[i] & (1ULL << 63))
> + coeffs[i] = 1 << 15;
> + coeffs[i] |= ((abs_coeff >> 32) & 7) << 12;
> + coeffs[i] |= (abs_coeff >> 20) & 0xfff;
> + }
> +
> + I915_WRITE(CGM_PIPE_CSC_COEFF01(pipe),
> + coeffs[1] << 16 | coeffs[0]);
> + I915_WRITE(CGM_PIPE_CSC_COEFF23(pipe),
> + coeffs[3] << 16 | coeffs[2]);
> + I915_WRITE(CGM_PIPE_CSC_COEFF45(pipe),
> + coeffs[5] << 16 | coeffs[4]);
> + I915_WRITE(CGM_PIPE_CSC_COEFF67(pipe),
> + coeffs[7] << 16 | coeffs[6]);
> + I915_WRITE(CGM_PIPE_CSC_COEFF8(pipe), coeffs[8]);
> + }
> +
> + mode = (state->ctm ? CGM_PIPE_MODE_CSC : 0);
> + if (!crtc_state_is_legacy(state)) {
> + mode |= (state->degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) |
> + (state->gamma_lut ? CGM_PIPE_MODE_GAMMA : 0);
> + }
> + I915_WRITE(CGM_PIPE_MODE(pipe), mode);
> +}
> +
> void intel_color_set_csc(struct drm_crtc *crtc)
> {
> struct drm_device *dev = crtc->dev;
> @@ -209,10 +262,10 @@ void intel_color_set_csc(struct drm_crtc *crtc)
> }
>
> /* Loads the legacy palette/gamma unit for the CRTC. */
> -static void i9xx_load_luts(struct drm_crtc *crtc)
> +static void i9xx_load_luts_internal(struct drm_crtc *crtc,
> + struct drm_property_blob *blob)
> {
> struct drm_device *dev = crtc->dev;
> - struct drm_crtc_state *state = crtc->state;
> struct drm_i915_private *dev_priv = dev->dev_private;
> struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> enum pipe pipe = intel_crtc->pipe;
> @@ -225,9 +278,8 @@ static void i9xx_load_luts(struct drm_crtc *crtc)
> assert_pll_enabled(dev_priv, pipe);
> }
>
> - if (state->gamma_lut) {
> - struct drm_color_lut *lut =
> - (struct drm_color_lut *) state->gamma_lut->data;
> + if (blob) {
> + struct drm_color_lut *lut = (struct drm_color_lut *) blob->data;
> for (i = 0; i < 256; i++) {
> uint32_t word =
> (drm_color_lut_extract(lut[i].red, 8) << 16) |
> @@ -251,6 +303,11 @@ static void i9xx_load_luts(struct drm_crtc *crtc)
> }
> }
>
> +static void i9xx_load_luts(struct drm_crtc *crtc)
> +{
> + i9xx_load_luts_internal(crtc, crtc->state->gamma_lut);
> +}
> +
> /* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
> static void haswell_load_luts(struct drm_crtc *crtc)
> {
> @@ -363,6 +420,67 @@ static void broadwell_load_luts(struct drm_crtc *crtc)
> I915_WRITE(PREC_PAL_INDEX(pipe), 0);
> }
>
> +/* Loads the palette/gamma unit for the CRTC on CherryView. */
> +static void cherryview_load_luts(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;
> + enum pipe pipe = to_intel_crtc(crtc)->pipe;
> + struct drm_color_lut *lut;
> + uint32_t i, lut_size;
> + uint32_t word0, word1;
> +
> + if (crtc_state_is_legacy(state)) {
> + /* Turn off degamma/gamma on CGM block. */
> + I915_WRITE(CGM_PIPE_MODE(pipe),
> + (state->ctm ? CGM_PIPE_MODE_CSC : 0));
> + i9xx_load_luts_internal(crtc, state->gamma_lut);
> + return;
> + }
> +
> + if (state->degamma_lut) {
> + lut = (struct drm_color_lut *) state->degamma_lut->data;
> + lut_size = INTEL_INFO(dev)->color.degamma_lut_size;
> + for (i = 0; i < lut_size; i++) {
> + /* Write LUT in U0.14 format. */
> + word0 =
> + (drm_color_lut_extract(lut[i].green, 14) << 16) |
> + drm_color_lut_extract(lut[i].blue, 14);
> + word1 = drm_color_lut_extract(lut[i].red, 14);
> +
> + I915_WRITE(CGM_PIPE_DEGAMMA(pipe, i, 0), word0);
> + I915_WRITE(CGM_PIPE_DEGAMMA(pipe, i, 1), word1);
> + }
> + }
> +
> + if (state->gamma_lut) {
> + lut = (struct drm_color_lut *) state->gamma_lut->data;
> + lut_size = INTEL_INFO(dev)->color.gamma_lut_size;
> + for (i = 0; i < lut_size; i++) {
> + /* Write LUT in U0.10 format. */
> + word0 =
> + (drm_color_lut_extract(lut[i].green, 10) << 16) |
> + drm_color_lut_extract(lut[i].blue, 10);
> + word1 = drm_color_lut_extract(lut[i].red, 10);
> +
> + I915_WRITE(CGM_PIPE_GAMMA(pipe, i, 0), word0);
> + I915_WRITE(CGM_PIPE_GAMMA(pipe, i, 1), word1);
> + }
> + }
> +
> + I915_WRITE(CGM_PIPE_MODE(pipe),
> + (state->ctm ? CGM_PIPE_MODE_CSC : 0) |
> + (state->degamma_lut ? CGM_PIPE_MODE_DEGAMMA : 0) |
> + (state->gamma_lut ? CGM_PIPE_MODE_GAMMA : 0));
> +
> + /*
> + * Also program a linear LUT in the legacy block (behind the
> + * CGM block).
> + */
> + i9xx_load_luts_internal(crtc, NULL);
> +}
> +
> void intel_color_load_luts(struct drm_crtc *crtc)
> {
> struct drm_device *dev = crtc->dev;
> @@ -415,7 +533,10 @@ void intel_color_init(struct drm_crtc *crtc)
>
> drm_mode_crtc_set_gamma_size(crtc, 256);
>
> - if (IS_HASWELL(dev)) {
> + if (IS_CHERRYVIEW(dev)) {
> + dev_priv->display.load_csc_matrix = cherryview_load_csc_matrix;
> + dev_priv->display.load_luts = cherryview_load_luts;
> + } else if (IS_HASWELL(dev)) {
> dev_priv->display.load_csc_matrix = i9xx_load_csc_matrix;
> dev_priv->display.load_luts = haswell_load_luts;
> } else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev) ||
> --
> 2.7.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread
* ✗ Fi.CI.BAT: failure for Pipe level color management (rev9)
2016-02-25 15:33 [PATCH 0/5] Pipe level color management V9 Lionel Landwerlin
` (4 preceding siblings ...)
2016-02-25 15:33 ` [PATCH 5/5] drm/i915: Implement color management on chv Lionel Landwerlin
@ 2016-02-25 16:32 ` Patchwork
5 siblings, 0 replies; 16+ messages in thread
From: Patchwork @ 2016-02-25 16:32 UTC (permalink / raw)
To: Lionel Landwerlin; +Cc: intel-gfx
== Series Details ==
Series: Pipe level color management (rev9)
URL : https://patchwork.freedesktop.org/series/2720/
State : failure
== Summary ==
Series 2720v9 Pipe level color management
http://patchwork.freedesktop.org/api/1.0/series/2720/revisions/9/mbox/
Test kms_flip:
Subgroup basic-flip-vs-modeset:
pass -> DMESG-WARN (ilk-hp8440p) UNSTABLE
Test kms_force_connector_basic:
Subgroup force-load-detect:
dmesg-fail -> FAIL (hsw-gt2)
dmesg-fail -> FAIL (ilk-hp8440p)
Test kms_pipe_crc_basic:
Subgroup suspend-read-crc-pipe-b:
pass -> DMESG-WARN (skl-i7k-2) UNSTABLE
Subgroup suspend-read-crc-pipe-c:
pass -> DMESG-WARN (bsw-nuc-2)
dmesg-warn -> PASS (skl-i7k-2) UNSTABLE
Test pm_rpm:
Subgroup basic-pci-d3-state:
pass -> FAIL (bdw-ultra)
dmesg-warn -> PASS (byt-nuc)
Subgroup basic-rte:
fail -> PASS (bdw-ultra)
bdw-ultra total:168 pass:153 dwarn:0 dfail:0 fail:1 skip:14
bsw-nuc-2 total:168 pass:136 dwarn:1 dfail:0 fail:1 skip:30
byt-nuc total:168 pass:143 dwarn:0 dfail:0 fail:0 skip:25
hsw-brixbox total:168 pass:154 dwarn:0 dfail:0 fail:0 skip:14
hsw-gt2 total:168 pass:157 dwarn:0 dfail:0 fail:1 skip:10
ilk-hp8440p total:168 pass:117 dwarn:1 dfail:0 fail:1 skip:49
ivb-t430s total:168 pass:153 dwarn:0 dfail:0 fail:1 skip:14
skl-i7k-2 total:168 pass:151 dwarn:1 dfail:0 fail:0 skip:16
snb-dellxps total:168 pass:145 dwarn:0 dfail:0 fail:1 skip:22
snb-x220t total:168 pass:145 dwarn:0 dfail:0 fail:2 skip:21
Results at /archive/results/CI_IGT_test/Patchwork_1476/
38f0cd5314ecb02d15d019631e388d3642275600 drm-intel-nightly: 2016y-02m-25d-15h-33m-53s UTC integration manifest
798167372b5f100f1f925da0c662d8ec38383ba1 drm/i915: Implement color management on chv
9ed2b832f837247690d3dd9c2d0dd75d8842ea5b drm/i915: Implement color management on bdw/skl/bxt/kbl
767405c0e581b9a54521c46b9df8d482bacaeff7 drm: introduce pipe color correction properties
1b9f0482150dd9e66956b8e649a91177779b3f16 drm/i915: Do not read GAMMA_MODE register
a0b95e87badb761305105bc87c520546da504a50 drm/i915: Extract out gamma table and CSC to their own file
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 16+ messages in thread