summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorJames Lin <pinglei.lin@amd.com>2026-08-28 10:13:33 +0800
committerAlex Deucher <alexander.deucher@amd.com>2026-09-17 11:38:26 -0400
commit123f78c8fa9c16d58c19c6f74152026addfc021b (patch)
treeac762230132e7789e4880fe0f82358817b61616b /drivers/gpu/drm
parente3fe350998e2a4dc35f5af9df83baac46124e6ba (diff)
downloadlinux-next-123f78c8fa9c16d58c19c6f74152026addfc021b.tar.gz
linux-next-123f78c8fa9c16d58c19c6f74152026addfc021b.zip
drm/amd/display: Attach only plane updates that actually changed
[Why & How] Cache the last programmed dc_flip_addrs/dc_plane_info/dc_scaling_info in dm_plane_state and carry them across atomic_duplicate_state. In amdgpu_dm_commit_planes() attach each flip_addr/plane_info/scaling_info surface update only when it differs from the cache (memcmp), so an address-only flip sends no plane_info/scaling_info update and stays on the FAMS2 offload path. Reviewed-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: James Lin <pinglei.lin@amd.com> Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c43
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h14
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c32
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c21
4 files changed, 101 insertions, 9 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 4e5718947cef..3f601a3d2d7d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3924,6 +3924,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bool plane_needs_flip;
struct dc_plane_state *dc_plane;
struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
+ struct dm_plane_state *dm_old_plane_state = to_dm_plane_state(old_plane_state);
/* Cursor plane is handled after stream updates */
if (plane->type == DRM_PLANE_TYPE_CURSOR &&
@@ -3958,11 +3959,22 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bundle->surface_updates[planes_count].cm = &dc_plane->cm;
}
- amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
- &bundle->scaling_infos[planes_count]);
+ if (amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
+ &bundle->scaling_infos[planes_count])) {
+ planes_count += 1;
+ continue;
+ }
- bundle->surface_updates[planes_count].scaling_info =
- &bundle->scaling_infos[planes_count];
+ /* Cache the newly computed scaling_info in the plane state */
+ *dm_new_plane_state->scaling_info =
+ bundle->scaling_infos[planes_count];
+
+ /* Only send a scaling_info update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->scaling_info,
+ dm_new_plane_state->scaling_info,
+ sizeof(struct dc_scaling_info)))
+ bundle->surface_updates[planes_count].scaling_info =
+ &bundle->scaling_infos[planes_count];
plane_needs_flip = old_plane_state->fb && new_plane_state->fb;
@@ -3985,8 +3997,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
new_plane_state->plane->index,
bundle->plane_infos[planes_count].dcc.enable);
- bundle->surface_updates[planes_count].plane_info =
- &bundle->plane_infos[planes_count];
+ /* Cache the newly computed plane_info in the plane state */
+ *dm_new_plane_state->plane_info =
+ bundle->plane_infos[planes_count];
+
+ /* Only send a plane_info update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->plane_info,
+ dm_new_plane_state->plane_info,
+ sizeof(struct dc_plane_info)))
+ bundle->surface_updates[planes_count].plane_info =
+ &bundle->plane_infos[planes_count];
if (acrtc_state->stream->link->psr_settings.psr_feature_enabled ||
acrtc_state->stream->link->replay_settings.replay_feature_enabled) {
@@ -4041,7 +4061,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
timestamp_ns = ktime_get_ns();
bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
- bundle->surface_updates[planes_count].flip_addr = &bundle->flip_addrs[planes_count];
+ /* Cache the newly computed flip_addr in the plane state */
+ *dm_new_plane_state->flip_addr =
+ bundle->flip_addrs[planes_count];
+
+ /* Only send a flip_addr update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->flip_addr,
+ dm_new_plane_state->flip_addr,
+ sizeof(struct dc_flip_addrs)))
+ bundle->surface_updates[planes_count].flip_addr =
+ &bundle->flip_addrs[planes_count];
bundle->surface_updates[planes_count].surface = dc_plane;
if (!bundle->surface_updates[planes_count].surface) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 52efebb2886d..b0ad73106a6b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -937,6 +937,10 @@ enum amdgpu_transfer_function {
AMDGPU_TRANSFER_FUNCTION_COUNT
};
+struct dc_flip_addrs;
+struct dc_scaling_info;
+struct dc_plane_info;
+
struct dm_plane_state {
struct drm_plane_state base;
struct dc_plane_state *dc_state;
@@ -1006,6 +1010,16 @@ struct dm_plane_state {
* applying blend LUT.
*/
enum amdgpu_transfer_function blend_tf;
+
+ /* Cached per-plane surface descriptors kept in the DRM plane state.
+ * The DRM atomic old/new state swap lets us compare the previous
+ * commit's values (old) against the newly computed ones to detect a
+ * real plane change (vs an address-only flip) so DC only gets a
+ * scaling_info/plane_info surface update when it actually changed.
+ */
+ struct dc_flip_addrs *flip_addr;
+ struct dc_scaling_info *scaling_info;
+ struct dc_plane_info *plane_info;
};
enum amdgpu_dm_cursor_mode {
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 4c13c7e86091..ab674a32279f 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
@@ -33,6 +33,7 @@
#include <drm/drm_fourcc.h>
#include "amdgpu.h"
+#include "dc.h"
#include "dal_asic_id.h"
#include "amdgpu_display.h"
#include "amdgpu_dm_trace.h"
@@ -1806,6 +1807,18 @@ STATIC_IFN_KUNIT void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane)
if (!amdgpu_state)
return;
+ amdgpu_state->flip_addr = kzalloc_obj(*amdgpu_state->flip_addr);
+ amdgpu_state->scaling_info = kzalloc_obj(*amdgpu_state->scaling_info);
+ amdgpu_state->plane_info = kzalloc_obj(*amdgpu_state->plane_info);
+ if (!amdgpu_state->flip_addr || !amdgpu_state->scaling_info ||
+ !amdgpu_state->plane_info) {
+ kfree(amdgpu_state->flip_addr);
+ kfree(amdgpu_state->scaling_info);
+ kfree(amdgpu_state->plane_info);
+ kfree(amdgpu_state);
+ return;
+ }
+
if (plane->state)
plane->funcs->atomic_destroy_state(plane, plane->state);
@@ -1827,6 +1840,21 @@ amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane)
if (!dm_plane_state)
return NULL;
+ dm_plane_state->flip_addr = kmemdup(old_dm_plane_state->flip_addr,
+ sizeof(*old_dm_plane_state->flip_addr), GFP_KERNEL);
+ dm_plane_state->scaling_info = kmemdup(old_dm_plane_state->scaling_info,
+ sizeof(*old_dm_plane_state->scaling_info), GFP_KERNEL);
+ dm_plane_state->plane_info = kmemdup(old_dm_plane_state->plane_info,
+ sizeof(*old_dm_plane_state->plane_info), GFP_KERNEL);
+ if (!dm_plane_state->flip_addr || !dm_plane_state->scaling_info ||
+ !dm_plane_state->plane_info) {
+ kfree(dm_plane_state->flip_addr);
+ kfree(dm_plane_state->scaling_info);
+ kfree(dm_plane_state->plane_info);
+ kfree(dm_plane_state);
+ return NULL;
+ }
+
__drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
if (old_dm_plane_state->dc_state) {
@@ -1946,6 +1974,10 @@ STATIC_IFN_KUNIT void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *
if (dm_plane_state->blend_lut)
drm_property_blob_put(dm_plane_state->blend_lut);
+ kfree(dm_plane_state->flip_addr);
+ kfree(dm_plane_state->scaling_info);
+ kfree(dm_plane_state->plane_info);
+
if (dm_plane_state->dc_state)
dc_plane_state_release(dm_plane_state->dc_state);
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 2d2397e9135c..1001cbc334b0 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
@@ -2977,7 +2977,7 @@ static void dm_test_plane_reset_initializes_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, new_state->shaper_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT);
KUNIT_EXPECT_EQ(test, new_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT);
- kfree(new_state);
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, &new_state->base);
}
/**
@@ -3000,6 +3000,14 @@ static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, plane);
KUNIT_ASSERT_NOT_NULL(test, old_state);
+ /* duplicate_state kmemdup()s these, so the source state must own them. */
+ old_state->flip_addr = kunit_kzalloc(test, sizeof(*old_state->flip_addr), GFP_KERNEL);
+ old_state->scaling_info = kunit_kzalloc(test, sizeof(*old_state->scaling_info), GFP_KERNEL);
+ old_state->plane_info = kunit_kzalloc(test, sizeof(*old_state->plane_info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
old_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_PQ_EOTF;
old_state->hdr_mult = 0x123456789ULL;
old_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_IDENTITY;
@@ -3016,7 +3024,7 @@ static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
KUNIT_EXPECT_EQ(test, dup_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF);
KUNIT_EXPECT_NULL(test, dup_state->dc_state);
- kfree(dup_state);
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, dup_base);
}
/*
@@ -3067,6 +3075,15 @@ static void dm_test_plane_duplicate_state_copies_resources(struct kunit *test)
kref_init(&dc_plane_state->refcount);
old_state->dc_state = dc_plane_state;
dm_test_attach_color_blobs(test, &adev->ddev, old_state);
+
+ /* duplicate_state kmemdup()s these, so the source state must own them. */
+ old_state->flip_addr = kunit_kzalloc(test, sizeof(*old_state->flip_addr), GFP_KERNEL);
+ old_state->scaling_info = kunit_kzalloc(test, sizeof(*old_state->scaling_info), GFP_KERNEL);
+ old_state->plane_info = kunit_kzalloc(test, sizeof(*old_state->plane_info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
plane->state = &old_state->base;
dup_base = amdgpu_dm_plane_drm_plane_duplicate_state(plane);