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
