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.atanas...@arm.com>
---

Link to v1: https://lkml.org/lkml/2017/2/1/254

Changes since v1:
 - Rebased and fixed conflicts
 - Improved clarity of overflow check (+comment)
 - Moved call to malidp_atomic_commit_update_coloradj in the existing crtc
 for-each loop

This patch depends on "[PATCH v3 2/2] drm: mali-dp: enable gamma support", sent
out on 7 Feb (https://lkml.org/lkml/2017/2/7/547).

 drivers/gpu/drm/arm/malidp_crtc.c | 58 +++++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/arm/malidp_drv.c  | 36 +++++++++++++++++++++++-
 drivers/gpu/drm/arm/malidp_drv.h  |  1 +
 drivers/gpu/drm/arm/malidp_regs.h |  2 ++
 4 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_crtc.c 
b/drivers/gpu/drm/arm/malidp_crtc.c
index 6a46520..7414540 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -192,6 +192,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)
 {
@@ -269,6 +321,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
        }
 
        ret = malidp_crtc_atomic_check_gamma(crtc, state);
+       ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state);
 
        return ret;
 }
@@ -288,6 +341,7 @@ 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, cs->gamma_coeffs, 
sizeof(state->gamma_coeffs));
+       memcpy(state->coloradj_coeffs, cs->coloradj_coeffs, 
sizeof(state->coloradj_coeffs));
 
        return &state->base;
 }
@@ -358,8 +412,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;
 
 crtc_cleanup_planes:
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index ce741c3..15f0f91 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -77,6 +77,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
  */
@@ -139,10 +170,13 @@ 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_modeset_enables(drm, state);
+
        drm_atomic_helper_commit_planes(drm, state, 0);
 
        malidp_atomic_commit_hw_done(state);
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index fbf6187..3bd4c76 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -50,6 +50,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_regs.h 
b/drivers/gpu/drm/arm/malidp_regs.h
index eeba027..8c3f3ff 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 */
@@ -99,6 +100,7 @@
 
 #define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16)
 
+#define MALIDP_COLORADJ_NUM_COEFFS     12
 #define MALIDP_COEFFTAB_NUM_COEFFS     64
 /* register offsets relative to MALIDP5x0_COEFFS_BASE */
 #define MALIDP_COLOR_ADJ_COEF          0x00000
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to