Hardware cannot switch directly between a fast-loaded and a host-loaded 3D LUT in a single commit. Require userspace to disable or bypass the LUT in an intermediate commit before enabling the other loading mode.
Compare the old and new DC plane color state in the atomic plane check and reject a loading mode change when both states have the LUT enabled. Using the derived DC flags covers both colorop pipelines and the legacy host-loaded LUT properties, without rejecting pipeline changes that leave the LUT disabled or keep the same loading mode. Add parameterized KUnit coverage for disabled, host-loaded and DMA LUT transitions, including disabled LUTs with the DMA flag still set. Signed-off-by: Harry Wentland <[email protected]> --- .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 14 ++++ .../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 65 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index aad146d9c6a7..e04e9a0cef73 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1550,9 +1550,11 @@ STATIC_IFN_KUNIT int amdgpu_dm_plane_atomic_check(struct drm_plane *plane, { struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct amdgpu_device *adev = drm_to_adev(plane->dev); struct dc *dc = adev->dm.dc; struct dm_plane_state *dm_plane_state; + const struct dc_plane_state *old_dc_state; struct dc_scaling_info scaling_info; struct drm_crtc_state *new_crtc_state; int ret; @@ -1574,6 +1576,18 @@ STATIC_IFN_KUNIT int amdgpu_dm_plane_atomic_check(struct drm_plane *plane, if (!dm_plane_state->dc_state) return 0; + old_dc_state = old_plane_state ? to_dm_plane_state(old_plane_state)->dc_state : NULL; + /* Switching loading modes requires an intermediate commit with the LUT disabled. */ + if (old_dc_state && old_dc_state->cm.flags.bits.lut3d_enable && + dm_plane_state->dc_state->cm.flags.bits.lut3d_enable && + old_dc_state->cm.flags.bits.lut3d_dma_enable != + dm_plane_state->dc_state->cm.flags.bits.lut3d_dma_enable) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] Cannot switch between host-loaded and DMA 3D LUTs in one commit\n", + plane->base.id, plane->name); + return -EINVAL; + } + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c index 7422e8ba9564..2925b2803a38 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -3019,6 +3019,69 @@ static void dm_test_atomic_check_success(struct kunit *test) KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), 0); } +struct dm_test_lut3d_transition { + const char *name; + bool old_enable; + bool old_dma; + bool new_enable; + bool new_dma; + int expected; +}; + +static const struct dm_test_lut3d_transition dm_test_lut3d_transitions[] = { + { "disabled_to_disabled", false, false, false, false, 0 }, + { "disabled_to_host", false, false, true, false, 0 }, + { "disabled_to_dma", false, false, true, true, 0 }, + { "host_to_disabled", true, false, false, false, 0 }, + { "host_to_host", true, false, true, false, 0 }, + { "host_to_dma", true, false, true, true, -EINVAL }, + { "dma_to_disabled", true, true, false, false, 0 }, + { "dma_to_host", true, true, true, false, -EINVAL }, + { "dma_to_dma", true, true, true, true, 0 }, + { "disabled_dma_to_host", false, true, true, false, 0 }, + { "host_to_disabled_dma", true, false, false, true, 0 }, +}; + +KUNIT_ARRAY_PARAM_DESC(dm_test_lut3d_transition, dm_test_lut3d_transitions, name); + +static void dm_test_atomic_check_lut3d_transition(struct kunit *test) +{ + const struct dm_test_lut3d_transition *param = test->param_value; + struct dm_plane_state *dm_plane_state, *old_plane_state; + struct drm_crtc_state *new_crtc_state; + struct drm_atomic_commit *state; + struct resource_pool *res_pool; + struct amdgpu_device *adev; + struct drm_framebuffer *fb; + struct drm_plane *plane; + + adev = dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state, + &new_crtc_state, &fb); + res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res_pool); + res_pool->funcs = kunit_kzalloc(test, sizeof(*res_pool->funcs), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res_pool->funcs); + adev->dm.dc->res_pool = res_pool; + + old_plane_state = kunit_kzalloc(test, sizeof(*old_plane_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, old_plane_state); + old_plane_state->dc_state = kunit_kzalloc(test, sizeof(*old_plane_state->dc_state), + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, old_plane_state->dc_state); + state->planes[0].old_state = &old_plane_state->base; + + old_plane_state->dc_state->cm.flags.bits.lut3d_enable = param->old_enable; + old_plane_state->dc_state->cm.flags.bits.lut3d_dma_enable = param->old_dma; + dm_plane_state->dc_state->cm.flags.bits.lut3d_enable = param->new_enable; + dm_plane_state->dc_state->cm.flags.bits.lut3d_dma_enable = param->new_dma; + dm_plane_state->dc_state->src_rect.width = 100; + dm_plane_state->dc_state->src_rect.height = 100; + dm_plane_state->dc_state->dst_rect.width = 100; + dm_plane_state->dc_state->dst_rect.height = 100; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), param->expected); +} + struct dm_test_cursor_ctx { struct amdgpu_device *adev; struct amdgpu_crtc *acrtc; @@ -3304,6 +3367,8 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = { KUNIT_CASE(dm_test_atomic_check_missing_crtc_state), KUNIT_CASE(dm_test_atomic_check_rejects), KUNIT_CASE(dm_test_atomic_check_success), + KUNIT_CASE_PARAM(dm_test_atomic_check_lut3d_transition, + dm_test_lut3d_transition_gen_params), /* amdgpu_dm_plane_panic_flush() */ KUNIT_CASE(dm_test_panic_flush_no_dc_state), KUNIT_CASE(dm_test_panic_flush_disables_dcc), -- 2.56.0
