diff mbox series

[08/12] drm: mali-dp: Add CTM support

Message ID 20170421091848.4666-9-Liviu.Dudau@arm.com
State New
Headers show
Series drm/mali-dp: Collate the pending patches in a series | expand

Commit Message

Liviu Dudau April 21, 2017, 9:18 a.m. UTC
From: Mihail Atanassov <mihail.atanassov@arm.com>

All DPs have a COLORADJ matrix which is applied prior to output gamma.
Attach that to the CTM property. Also, ensure the input CTM's coefficients
can fit in the DP registers' Q3.12 format.

Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
---
 drivers/gpu/drm/arm/malidp_crtc.c | 64 +++++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/arm/malidp_drv.c  | 35 ++++++++++++++++++++-
 drivers/gpu/drm/arm/malidp_drv.h  |  1 +
 drivers/gpu/drm/arm/malidp_hw.h   |  1 +
 drivers/gpu/drm/arm/malidp_regs.h |  1 +
 5 files changed, 98 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index 27ab09459b9d..8f2e1ae51ba0 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -195,6 +195,58 @@  static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc,
 	return 0;
 }
 
+/*
+ * Check if there is a new CTM and if it contains valid input. Valid here means
+ * that the number is inside the representable range for a Q3.12 number,
+ * excluding truncating the fractional part of the input data.
+ *
+ * The COLORADJ registers can be changed atomically.
+ */
+static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc,
+					struct drm_crtc_state *state)
+{
+	struct malidp_crtc_state *mc = to_malidp_crtc_state(state);
+	struct drm_color_ctm *ctm;
+	int i;
+
+	if (!state->color_mgmt_changed)
+		return 0;
+
+	if (!state->ctm)
+		return 0;
+
+	if (crtc->state->ctm && (crtc->state->ctm->base.id ==
+				 state->ctm->base.id))
+		return 0;
+
+	/*
+	 * The size of the ctm is checked in
+	 * drm_atomic_replace_property_blob_from_id.
+	 */
+	ctm = (struct drm_color_ctm *)state->ctm->data;
+	for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) {
+		/* Convert from S31.32 to Q3.12. */
+		s64 val = ctm->matrix[i];
+		u32 mag = ((((u64)val) & ~BIT_ULL(63)) >> 20) &
+			  GENMASK_ULL(14, 0);
+
+		/*
+		 * Convert to 2s complement and check the destination's top bit
+		 * for overflow. NB: Can't check before converting or it'd
+		 * incorrectly reject the case:
+		 * sign == 1
+		 * mag == 0x2000
+		 */
+		if (val & BIT_ULL(63))
+			mag = ~mag + 1;
+		if (!!(val & BIT_ULL(63)) != !!(mag & BIT(14)))
+			return -EINVAL;
+		mc->coloradj_coeffs[i] = mag;
+	}
+
+	return 0;
+}
+
 static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
 				    struct drm_crtc_state *state)
 {
@@ -204,6 +256,7 @@  static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
 	const struct drm_plane_state *pstate;
 	u32 rot_mem_free, rot_mem_usable;
 	int rotated_planes = 0;
+	int ret;
 
 	/*
 	 * check if there is enough rotation memory available for planes
@@ -270,7 +323,10 @@  static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
 		}
 	}
 
-	return malidp_crtc_atomic_check_gamma(crtc, state);
+	ret = malidp_crtc_atomic_check_gamma(crtc, state);
+	ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state);
+
+	return ret;
 }
 
 static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
@@ -295,6 +351,8 @@  static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc)
 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
 	memcpy(state->gamma_coeffs, old_state->gamma_coeffs,
 	       sizeof(state->gamma_coeffs));
+	memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs,
+	       sizeof(state->coloradj_coeffs));
 
 	return &state->base;
 }
@@ -392,8 +450,8 @@  int malidp_crtc_init(struct drm_device *drm)
 
 	drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs);
 	drm_mode_crtc_set_gamma_size(&malidp->crtc, MALIDP_GAMMA_LUT_SIZE);
-	/* No inverse-gamma and color adjustments yet. */
-	drm_crtc_enable_color_mgmt(&malidp->crtc, 0, false, MALIDP_GAMMA_LUT_SIZE);
+	/* No inverse-gamma: it is per-plane */
+	drm_crtc_enable_color_mgmt(&malidp->crtc, 0, true, MALIDP_GAMMA_LUT_SIZE);
 
 	return 0;
 
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 1eb6bbc5118a..eae41e26b819 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -79,6 +79,37 @@  static void malidp_atomic_commit_update_gamma(struct drm_crtc *crtc,
 	}
 }
 
+static
+void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc,
+					  struct drm_crtc_state *old_state)
+{
+	struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
+	struct malidp_hw_device *hwdev = malidp->dev;
+	int i;
+
+	if (!crtc->state->color_mgmt_changed)
+		return;
+
+	if (!crtc->state->ctm) {
+		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_CADJ,
+				    MALIDP_DE_DISPLAY_FUNC);
+	} else {
+		struct malidp_crtc_state *mc =
+			to_malidp_crtc_state(crtc->state);
+
+		if (!old_state->ctm || (crtc->state->ctm->base.id !=
+					old_state->ctm->base.id))
+			for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; ++i)
+				malidp_hw_write(hwdev,
+						mc->coloradj_coeffs[i],
+						hwdev->map.coeffs_base +
+						MALIDP_COLOR_ADJ_COEF + 4 * i);
+
+		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_CADJ,
+				  MALIDP_DE_DISPLAY_FUNC);
+	}
+}
+
 /*
  * set the "config valid" bit and wait until the hardware acts on it
  */
@@ -145,8 +176,10 @@  static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
 
 	drm_atomic_helper_commit_modeset_disables(drm, state);
 
-	for_each_crtc_in_state(state, crtc, old_crtc_state, i)
+	for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
 		malidp_atomic_commit_update_gamma(crtc, old_crtc_state);
+		malidp_atomic_commit_update_coloradj(crtc, old_crtc_state);
+	}
 
 	drm_atomic_helper_commit_planes(drm, state, 0);
 
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index f5abd8bfbd2b..e1c784dcdd92 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -51,6 +51,7 @@  struct malidp_plane_state {
 struct malidp_crtc_state {
 	struct drm_crtc_state base;
 	u32 gamma_coeffs[MALIDP_COEFFTAB_NUM_COEFFS];
+	u32 coloradj_coeffs[MALIDP_COLORADJ_NUM_COEFFS];
 };
 
 #define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base)
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index c2df6b6e7645..470fe71724a3 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -259,6 +259,7 @@  static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev,
 #define MALIDP_BGND_COLOR_G		0x000
 #define MALIDP_BGND_COLOR_B		0x000
 
+#define MALIDP_COLORADJ_NUM_COEFFS	12
 #define MALIDP_COEFFTAB_NUM_COEFFS	64
 
 #define MALIDP_GAMMA_LUT_SIZE		4096
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
index 28252c5b31b5..4bf338d4172e 100644
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -64,6 +64,7 @@ 
 /* bit masks that are common between products */
 #define   MALIDP_CFG_VALID		(1 << 0)
 #define   MALIDP_DISP_FUNC_GAMMA	(1 << 0)
+#define   MALIDP_DISP_FUNC_CADJ		(1 << 4)
 #define   MALIDP_DISP_FUNC_ILACED	(1 << 8)
 
 /* register offsets for IRQ management */