Add a core atomic check for DRM_COLOROP_3D_LUT_DMA colorops. When the
colorop is enabled (not bypassed), validate the selected LUT_3D_FORMAT
index and require a framebuffer whose fourcc, modifier, pitch and
dimensions match the advertised drm_mode_3dlut_mode entry: width equal to
the cube edge and height equal to lut_size^2 (due to the 2D flattening
of the cube). Driver-specific constraints are left to the driver's own
atomic_check.

Signed-off-by: Harry Wentland <[email protected]>
---
 drivers/gpu/drm/drm_atomic.c | 62 ++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 158f41eae76f..a6f1be7ce76c 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1745,6 +1745,57 @@ drm_atomic_add_affected_colorops(struct 
drm_atomic_commit *state,
 }
 EXPORT_SYMBOL(drm_atomic_add_affected_colorops);
 
+static int drm_atomic_colorop_check(struct drm_colorop *colorop,
+                                   struct drm_colorop_state *new_colorop_state)
+{
+       const struct drm_mode_3dlut_mode *modes, *mode;
+       struct drm_framebuffer *fb = new_colorop_state->fb;
+       u32 num_modes;
+
+       if (colorop->type != DRM_COLOROP_3D_LUT_DMA)
+               return 0;
+
+       /* Nothing to validate while the colorop is bypassed. */
+       if (colorop->bypass_property && new_colorop_state->bypass)
+               return 0;
+
+       if (!colorop->lut_3d_formats_blob)
+               return -EINVAL;
+
+       num_modes = colorop->lut_3d_formats_blob->length /
+                   sizeof(struct drm_mode_3dlut_mode);
+       if (new_colorop_state->lut_3d_format >= num_modes) {
+               drm_dbg_atomic(colorop->dev,
+                              "[COLOROP:%d] LUT_3D_FORMAT %u out of range 
(have %u)\n",
+                              colorop->base.id, 
new_colorop_state->lut_3d_format,
+                              num_modes);
+               return -EINVAL;
+       }
+
+       modes = colorop->lut_3d_formats_blob->data;
+       mode = &modes[new_colorop_state->lut_3d_format];
+
+       if (!fb) {
+               drm_dbg_atomic(colorop->dev,
+                              "[COLOROP:%d] enabled DMA 3D LUT without a 
framebuffer\n",
+                              colorop->base.id);
+               return -EINVAL;
+       }
+
+       if (fb->format->format != mode->format ||
+           fb->modifier != mode->modifier ||
+           fb->pitches[0] != mode->pitch ||
+           fb->width != mode->lut_size ||
+           fb->height != (u64)mode->lut_size * mode->lut_size) {
+               drm_dbg_atomic(colorop->dev,
+                              "[COLOROP:%d] framebuffer does not match 
LUT_3D_FORMAT %u\n",
+                              colorop->base.id, 
new_colorop_state->lut_3d_format);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /**
  * drm_atomic_check_only - check whether a given config would work
  * @state: atomic configuration to check
@@ -1768,6 +1819,8 @@ int drm_atomic_check_only(struct drm_atomic_commit *state)
        struct drm_crtc_state *new_crtc_state;
        struct drm_connector *conn;
        struct drm_connector_state *conn_state;
+       struct drm_colorop *colorop;
+       struct drm_colorop_state *new_colorop_state;
        unsigned int requested_crtc = 0;
        unsigned int affected_crtc = 0;
        int i, ret = 0;
@@ -1806,6 +1859,15 @@ int drm_atomic_check_only(struct drm_atomic_commit 
*state)
                }
        }
 
+       for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
+               ret = drm_atomic_colorop_check(colorop, new_colorop_state);
+               if (ret) {
+                       drm_dbg_atomic(dev, "[COLOROP:%d] atomic core check 
failed\n",
+                                      colorop->base.id);
+                       return ret;
+               }
+       }
+
        if (config->funcs->atomic_check) {
                ret = config->funcs->atomic_check(state->dev, state);
 
-- 
2.56.0

Reply via email to