Re: [PATCH 17/49] drm/amd/display: add cursor module
Timur Kristóf <[email protected]> Mon, 03 Aug 2026 14:48:12 +0200
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
On Thursday, July 23, 2026 10:13:25=E2=80=AFPM Central European Summer Time= Fangzhi=20 Zuo wrote: > From: Alex Hung <[email protected]> >=20 > [WHAT] > Group the cursor policy and validation helpers from amdgpu_dm.c > into a dedicated amdgpu_dm_cursor.c and amdgpu_dm_cursor.h. > The moved functions are: >=20 > dm_check_cursor_fb, dm_check_native_cursor_state, > dm_should_update_native_cursor, dm_get_oriented_plane_size, > dm_get_plane_scale, dm_plane_color_pipeline_active, > dm_crtc_get_cursor_mode. >=20 > The cursor helpers exposed by amdgpu_dm_cursor.h are called from > amdgpu_dm.c, so give the three that lacked a namespace prefix the > standard amdgpu_dm_ prefix: amdgpu_dm_check_native_cursor_state, > amdgpu_dm_should_update_native_cursor and > amdgpu_dm_crtc_get_cursor_mode. >=20 > The descending-zpos plane iterator shared by these functions and > amdgpu_dm_atomic_check (the for_each_oldnew_plane_in_descending_zpos > macro and its __get_next_zpos helper) moves to amdgpu_dm.h, with > the helper renamed amdgpu_dm_get_next_zpos and made non-static. >=20 > Relocate the corresponding KUnit tests into amdgpu_dm_cursor_test.c. >=20 > No functional change. Hi, This commit regresses a recent bug fix from commit "Set native cursor mode = for=20 disabled CRTCs". The amdgpu_dm_crtc_get_cursor_mode() function that was add= ed=20 to amdgpu_dm_cursor.c is not the same as was removed from amdgpu_dm.c I've submitted a fix here: https://lists.freedesktop.org/archives/amd-gfx/2026-August/149759.html Please review. Thanks & best regards, Timur >=20 > Reviewed-by: Bhawanpreet Lakha <[email protected]> > Signed-off-by: Alex Hung <[email protected]> > Signed-off-by: Fangzhi Zuo <[email protected]> > Tested-by: Dan Wheeler <[email protected]> > --- > .../gpu/drm/amd/display/amdgpu_dm/Makefile | 3 +- > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 436 +---------------- > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 24 +- > .../amd/display/amdgpu_dm/amdgpu_dm_cursor.c | 443 ++++++++++++++++++ > .../amd/display/amdgpu_dm/amdgpu_dm_cursor.h | 52 ++ > .../drm/amd/display/amdgpu_dm/tests/Makefile | 1 + > .../amdgpu_dm/tests/amdgpu_dm_cursor_test.c | 268 +++++++++++ > .../display/amdgpu_dm/tests/amdgpu_dm_test.c | 232 --------- > 8 files changed, 796 insertions(+), 663 deletions(-) > create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_curso= r.c > create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor= =2Eh > create mode 100644 > drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c >=20 > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile > b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index > 5cb8c143e72f..d1faf2d8370f 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile > @@ -46,7 +46,8 @@ AMDGPUDM =3D \ > amdgpu_dm_audio.o \ > amdgpu_dm_dmub.o \ > amdgpu_dm_connector.o \ > - amdgpu_dm_freesync.o > + amdgpu_dm_freesync.o \ > + amdgpu_dm_cursor.o >=20 > ifdef CONFIG_DRM_AMD_DC_FP > AMDGPUDM +=3D dc_fpu.o > 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 > c36eb8a1d2d1..217ec822e93e 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > @@ -72,6 +72,7 @@ > #include "amdgpu_dm_connector.h" > #include "amdgpu_dm_pp_smu.h" > #include "amdgpu_dm_freesync.h" > +#include "amdgpu_dm_cursor.h" >=20 > #include "ivsrcid/ivsrcid_vislands30.h" >=20 > @@ -5760,133 +5761,6 @@ static bool should_reset_plane(struct > drm_atomic_commit *state, return false; > } >=20 > -static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, > - struct drm_plane_state=20 *new_plane_state, > - struct drm_framebuffer *fb) > -{ > - struct amdgpu_device *adev =3D drm_to_adev(new_acrtc->base.dev); > - struct amdgpu_framebuffer *afb =3D to_amdgpu_framebuffer(fb); > - unsigned int pitch; > - bool linear; > - > - if (fb->width > new_acrtc->max_cursor_width || > - fb->height > new_acrtc->max_cursor_height) { > - drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB size=20 %dx%d\n", > - new_plane_state->fb->width, > - new_plane_state->fb->height); > - return -EINVAL; > - } > - if (new_plane_state->src_w !=3D fb->width << 16 || > - new_plane_state->src_h !=3D fb->height << 16) { > - drm_dbg_atomic(adev_to_drm(adev), "Cropping not=20 supported for cursor > plane\n"); - return -EINVAL; > - } > - > - /* Pitch in pixels */ > - pitch =3D fb->pitches[0] / fb->format->cpp[0]; > - > - if (fb->width !=3D pitch) { > - drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d=20 doesn't match pitch > %d", - fb->width, pitch); > - return -EINVAL; > - } > - > - switch (pitch) { > - case 64: > - case 128: > - case 256: > - /* FB pitch is supported by cursor plane */ > - break; > - default: > - drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB pitch=20 %d px\n", pitch); > - return -EINVAL; > - } > - > - /* Core DRM takes care of checking FB modifiers, so we only need to > - * check tiling flags when the FB doesn't have a modifier. > - */ > - if (!(fb->flags & DRM_MODE_FB_MODIFIERS)) { > - if (adev->family =3D=3D AMDGPU_FAMILY_GC_12_0_0) { > - linear =3D AMDGPU_TILING_GET(afb->tiling_flags,=20 GFX12_SWIZZLE_MODE) =3D=3D 0; > - } else if (adev->family >=3D AMDGPU_FAMILY_AI) { > - linear =3D AMDGPU_TILING_GET(afb->tiling_flags,=20 SWIZZLE_MODE) =3D=3D 0; > - } else { > - linear =3D AMDGPU_TILING_GET(afb->tiling_flags,=20 ARRAY_MODE) !=3D > DC_ARRAY_2D_TILED_THIN1 && - =20 AMDGPU_TILING_GET(afb->tiling_flags, > ARRAY_MODE) !=3D DC_ARRAY_1D_TILED_THIN1 && - =09 > AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) =3D=3D 0; > - } > - if (!linear) { > - drm_dbg_atomic(adev_to_drm(adev), "Cursor FB=20 not linear"); > - return -EINVAL; > - } > - } > - > - return 0; > -} > - > -/* > - * Helper function for checking the cursor in native mode > - */ > -static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc, > - struct drm_plane=20 *plane, > - struct drm_plane_state=20 *new_plane_state, > - bool enable) > -{ > - > - struct amdgpu_crtc *new_acrtc; > - int ret; > - > - if (!enable || !new_plane_crtc || > - drm_atomic_plane_disabling(plane->state, new_plane_state)) > - return 0; > - > - new_acrtc =3D to_amdgpu_crtc(new_plane_crtc); > - > - if (new_plane_state->src_x !=3D 0 || new_plane_state->src_y !=3D 0) { > - drm_dbg_atomic(new_plane_crtc->dev, "Cropping not=20 supported for cursor > plane\n"); - return -EINVAL; > - } > - > - if (new_plane_state->fb) { > - ret =3D dm_check_cursor_fb(new_acrtc, new_plane_state, > - =09 new_plane_state->fb); > - if (ret) > - return ret; > - } > - > - return 0; > -} > - > -STATIC_IFN_KUNIT bool dm_should_update_native_cursor(struct > drm_atomic_commit *state, - =09 struct drm_crtc *old_plane_crtc, > - struct=20 drm_crtc *new_plane_crtc, > - bool=20 enable) > -{ > - struct drm_crtc_state *old_crtc_state, *new_crtc_state; > - struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; > - > - if (!enable) { > - if (old_plane_crtc =3D=3D NULL) > - return true; > - > - old_crtc_state =3D drm_atomic_get_old_crtc_state( > - state, old_plane_crtc); > - dm_old_crtc_state =3D to_dm_crtc_state(old_crtc_state); > - > - return dm_old_crtc_state->cursor_mode =3D=3D=20 DM_CURSOR_NATIVE_MODE; > - } else { > - if (new_plane_crtc =3D=3D NULL) > - return true; > - > - new_crtc_state =3D drm_atomic_get_new_crtc_state( > - state, new_plane_crtc); > - dm_new_crtc_state =3D to_dm_crtc_state(new_crtc_state); > - > - return dm_new_crtc_state->cursor_mode =3D=3D=20 DM_CURSOR_NATIVE_MODE; > - } > -} > -EXPORT_IF_KUNIT(dm_should_update_native_cursor); > - > static int dm_update_plane_state(struct dc *dc, > struct drm_atomic_commit *state, > struct drm_plane *plane, > @@ -5911,14 +5785,14 @@ static int dm_update_plane_state(struct dc *dc, > dm_new_plane_state =3D to_dm_plane_state(new_plane_state); > dm_old_plane_state =3D to_dm_plane_state(old_plane_state); >=20 > - update_native_cursor =3D dm_should_update_native_cursor(state, > - =20 old_plane_crtc, > - =20 new_plane_crtc, > - =20 enable); > + update_native_cursor =3D amdgpu_dm_should_update_native_cursor(state, > + =09 old_plane_crtc, > + =09 new_plane_crtc, > + =09 enable); >=20 > if (plane->type =3D=3D DRM_PLANE_TYPE_CURSOR && update_native_cursor)=20 { > - ret =3D dm_check_native_cursor_state(new_plane_crtc,=20 plane, > - =20 new_plane_state, enable); > + ret =3D=20 amdgpu_dm_check_native_cursor_state(new_plane_crtc, plane, > + =20 new_plane_state, enable); > if (ret) > return ret; >=20 > @@ -6048,8 +5922,8 @@ static int dm_update_plane_state(struct dc *dc, > out: > /* If enabling cursor overlay failed, attempt fallback to native=20 mode */ > if (enable && ret =3D=3D -EINVAL && plane->type =3D=3D=20 DRM_PLANE_TYPE_CURSOR) { > - ret =3D dm_check_native_cursor_state(new_plane_crtc,=20 plane, > - =20 new_plane_state, enable); > + ret =3D=20 amdgpu_dm_check_native_cursor_state(new_plane_crtc, plane, > + =20 new_plane_state, enable); > if (ret) > return ret; >=20 > @@ -6059,37 +5933,6 @@ static int dm_update_plane_state(struct dc *dc, > return ret; > } >=20 > -STATIC_IFN_KUNIT void dm_get_oriented_plane_size(struct drm_plane_state > *plane_state, - int=20 *src_w, int *src_h) > -{ > - switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) { > - case DRM_MODE_ROTATE_90: > - case DRM_MODE_ROTATE_270: > - *src_w =3D plane_state->src_h >> 16; > - *src_h =3D plane_state->src_w >> 16; > - break; > - case DRM_MODE_ROTATE_0: > - case DRM_MODE_ROTATE_180: > - default: > - *src_w =3D plane_state->src_w >> 16; > - *src_h =3D plane_state->src_h >> 16; > - break; > - } > -} > -EXPORT_IF_KUNIT(dm_get_oriented_plane_size); > - > -STATIC_IFN_KUNIT void > -dm_get_plane_scale(struct drm_plane_state *plane_state, > - int *out_plane_scale_w, int *out_plane_scale_h) > -{ > - int plane_src_w, plane_src_h; > - > - dm_get_oriented_plane_size(plane_state, &plane_src_w,=20 &plane_src_h); > - *out_plane_scale_w =3D plane_src_w ? plane_state->crtc_w * 1000 / > plane_src_w : 0; - *out_plane_scale_h =3D plane_src_h ? plane_state- >crtc_h * > 1000 / plane_src_h : 0; -} > -EXPORT_IF_KUNIT(dm_get_plane_scale); > - > /* > * The normalized_zpos value cannot be used by this iterator directly. I= t's > only * calculated for enabled planes, potentially causing normalized_zpos > collisions @@ -6097,7 +5940,7 @@ EXPORT_IF_KUNIT(dm_get_plane_scale); > * so that the iterator will not generate the same object twice, or loop > * indefinitely. > */ > -static inline struct __drm_planes_state *__get_next_zpos( > +struct __drm_planes_state *amdgpu_dm_get_next_zpos( > struct drm_atomic_commit *state, > struct __drm_planes_state *prev) > { > @@ -6135,19 +5978,6 @@ static inline struct __drm_planes_state > *__get_next_zpos( return &state->planes[highest_i]; > } >=20 > -/* > - * Use the uniqueness of the plane's (zpos, drm obj ID) combination to > iterate - * by descending zpos, as read from the new plane state. This is > the same - * ordering as defined by drm_atomic_normalize_zpos(). > - */ > -#define for_each_oldnew_plane_in_descending_zpos(__state, plane, > old_plane_state, new_plane_state) \ - for (struct __drm_planes_state *__i= =3D > __get_next_zpos((__state), NULL); \ - __i !=3D NULL; __i =3D > __get_next_zpos((__state), __i)) \ > - for_each_if(((plane) =3D __i->ptr, =09 \ > - (void)(plane) /* Only to avoid unused- but-set-variable warning */, > \ - (old_plane_state) =3D __i->old_state, =09 \ > - (new_plane_state) =3D __i->new_state, 1)) > - > static int add_affected_mst_dsc_crtcs(struct drm_atomic_commit *state, > struct drm_crtc *crtc) { > struct drm_connector *connector; > @@ -6178,244 +6008,6 @@ static int add_affected_mst_dsc_crtcs(struct > drm_atomic_commit *state, struct dr return > drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_root->mst_mgr);= } >=20 > -/** > - * DOC: Cursor Modes - Native vs Overlay > - * > - * In native mode, the cursor uses a integrated cursor pipe within each = DCN > hw - * plane. It does not require a dedicated hw plane to enable, but it = is > - * subjected to the same z-order and scaling as the hw plane. It also has > format - * restrictions, a RGB cursor in native mode cannot be enabled > within a non-RGB - * hw plane. > - * > - * In overlay mode, the cursor uses a separate DCN hw plane, and thus has > its - * own scaling and z-pos. It also has no blending restrictions. It > lends to a - * cursor behavior more akin to a DRM client's expectations. > However, it does - * occupy an extra DCN plane, and therefore will only be > used if a DCN plane is - * available. > - */ > - > -/** > - * dm_plane_color_pipeline_active() - Check if a plane's color pipeline > active. - * @state: DRM atomic state > - * @plane: DRM plane to check > - * @use_old: if true, inspect the old colorop states; otherwise the new > ones - * > - * A color pipeline may be selected (color_pipeline !=3D NULL) but still= is > - * inactive if every colorop in the chain is bypassed. Only return > - * true when at least one colorop has bypass =3D=3D false, meaning the c= ursor > - * would be subjected to the transformation in native mode. > - * > - * Return: true if the pipeline modifies pixels, false otherwise. > - */ > -static bool dm_plane_color_pipeline_active(struct drm_atomic_commit *sta= te, > - struct drm_plane=20 *plane, > - bool use_old) > -{ > - struct drm_colorop *colorop; > - struct drm_colorop_state *old_colorop_state, *new_colorop_state; > - int i; > - > - for_each_oldnew_colorop_in_state(state, colorop,=20 old_colorop_state, > new_colorop_state, i) { - struct drm_colorop_state *cstate =3D=20 use_old ? > old_colorop_state : new_colorop_state; - > - if (cstate->colorop->plane !=3D plane) > - continue; > - if (!cstate->bypass) > - return true; > - } > - return false; > -} > - > -/** > - * dm_crtc_get_cursor_mode() - Determine the required cursor mode on crtc > - * @adev: amdgpu device > - * @state: DRM atomic state > - * @dm_crtc_state: amdgpu state for the CRTC containing the cursor > - * @cursor_mode: Returns the required cursor mode on dm_crtc_state > - * > - * Get whether the cursor should be enabled in native mode, or overlay > mode, on - * the dm_crtc_state. > - * > - * The cursor should be enabled in overlay mode if there exists an > underlying - * plane - on which the cursor may be blended - that is either > YUV formatted, - * scaled differently from the cursor, or has a color > pipeline active. - * > - * Since zpos info is required, drm_atomic_normalize_zpos must be called > before - * calling this function. > - * > - * Return: 0 on success, or an error code if getting the cursor plane st= ate > - * failed. > - */ > -static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev, > - struct drm_atomic_commit=20 *state, > - struct dm_crtc_state=20 *dm_crtc_state, > - enum amdgpu_dm_cursor_mode=20 *cursor_mode) > -{ > - struct drm_plane_state *old_plane_state, *plane_state,=20 *cursor_state; > - struct drm_crtc_state *crtc_state =3D &dm_crtc_state->base; > - struct drm_plane *plane; > - bool consider_mode_change =3D false; > - bool entire_crtc_covered =3D false; > - bool cursor_changed =3D false; > - int underlying_scale_w, underlying_scale_h; > - int cursor_scale_w, cursor_scale_h; > - int i; > - > - /* Overlay cursor not supported on HW before DCN > - * DCN401/420 does not have the cursor-on-scaled-plane or > cursor-on-yuv-plane restrictions - * as previous DCN generations, so > enable native mode on DCN401/420 - * > - * Always set native cursor mode when the CRTC is disabled, > - * to make sure it doesn't cause atomic commits to fail when > - * they are trying to disable the CRTC. > - */ > - if (amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(4, 0, 1) || > - amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(4, 2, 0) || > - amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(4, 2, 1) || > - !dm_crtc_state->base.enable) { > - *cursor_mode =3D DM_CURSOR_NATIVE_MODE; > - return 0; > - } > - > - /* Init cursor_mode to be the same as current */ > - *cursor_mode =3D dm_crtc_state->cursor_mode; > - > - /* > - * Cursor mode can change if a plane's format changes, scale=20 changes, is > - * enabled/disabled, z-order changes, or color management=20 properties > change. - */ > - for_each_oldnew_plane_in_state(state, plane, old_plane_state,=20 plane_state, > i) { - int new_scale_w, new_scale_h, old_scale_w,=20 old_scale_h; > - > - /* Only care about planes on this CRTC */ > - if ((drm_plane_mask(plane) & crtc_state->plane_mask) =3D=3D=20 0) > - continue; > - > - if (plane->type =3D=3D DRM_PLANE_TYPE_CURSOR) > - cursor_changed =3D true; > - > - if (drm_atomic_plane_enabling(old_plane_state,=20 plane_state) || > - drm_atomic_plane_disabling(old_plane_state,=20 plane_state) || > - old_plane_state->fb->format !=3D plane_state->fb- >format) { > - consider_mode_change =3D true; > - break; > - } > - > - dm_get_plane_scale(plane_state, &new_scale_w,=20 &new_scale_h); > - dm_get_plane_scale(old_plane_state, &old_scale_w,=20 &old_scale_h); > - if (new_scale_w !=3D old_scale_w || new_scale_h !=3D=20 old_scale_h) { > - consider_mode_change =3D true; > - break; > - } > - > - /* > - * A non-cursor plane moving or resizing (without a=20 scale change) > - * changes how much of the CRTC it covers. This can=20 create or > - * remove a hole under the cursor and thus flip the=20 required > - * cursor mode (native vs overlay), so its destination=20 rect must > - * be re-evaluated too. > - * > - * The cursor plane itself is deliberately excluded:=20 the cursor > - * mode depends on the underlying planes' coverage, not=20 on the > - * cursor's position (see the entire_crtc_covered logic=20 below). > - * Triggering on cursor movement would force every=20 legacy cursor > - * update off its fast path, and in a cursor-only commit=20 =2D where > - * the underlying planes are not part of the state -=20 the coverage > - * loop would see no covering plane and misevaluate the=20 mode as > - * overlay, regressing flip-vs-cursor-legacy. > - */ > - if (plane->type !=3D DRM_PLANE_TYPE_CURSOR && > - (old_plane_state->crtc_x !=3D plane_state->crtc_x || > - old_plane_state->crtc_y !=3D plane_state->crtc_y || > - old_plane_state->crtc_w !=3D plane_state->crtc_w || > - old_plane_state->crtc_h !=3D plane_state->crtc_h)) { > - consider_mode_change =3D true; > - break; > - } > - > - if (dm_plane_color_pipeline_active(state, plane, true)=20 !=3D > - dm_plane_color_pipeline_active(state, plane,=20 false)) { > - consider_mode_change =3D true; > - break; > - } > - } > - > - if (!consider_mode_change && !crtc_state->zpos_changed) > - return 0; > - > - /* > - * If no cursor change on this CRTC, and not enabled on this CRTC,=20 then > - * no need to set cursor mode. This avoids needlessly locking the=20 cursor > - * state. > - */ > - if (!cursor_changed && > - !(drm_plane_mask(crtc_state->crtc->cursor) & crtc_state- >plane_mask)) > { - return 0; > - } > - > - cursor_state =3D drm_atomic_get_plane_state(state, > - =20 crtc_state->crtc->cursor); > - if (IS_ERR(cursor_state)) > - return PTR_ERR(cursor_state); > - > - /* Cursor is disabled */ > - if (!cursor_state->fb) > - return 0; > - > - /* For all planes in descending z-order (all of which are below=20 cursor > - * as per zpos definitions), check their scaling and format > - */ > - for_each_oldnew_plane_in_descending_zpos(state, plane,=20 old_plane_state, > plane_state) { - > - /* Only care about non-cursor planes on this CRTC */ > - if ((drm_plane_mask(plane) & crtc_state->plane_mask) =3D=3D=20 0 || > - plane->type =3D=3D DRM_PLANE_TYPE_CURSOR) > - continue; > - > - /* Underlying plane is YUV format - use overlay cursor=20 */ > - if (amdgpu_dm_plane_is_video_format(plane_state->fb- >format->format)) { > - *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > - return 0; > - } > - > - /* Underlying plane has an active color pipeline -=20 cursor would be > transformed */ - if (dm_plane_color_pipeline_active(state,=20 plane, false)) > { > - *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > - return 0; > - } > - > - dm_get_plane_scale(plane_state, > - &underlying_scale_w,=20 &underlying_scale_h); > - dm_get_plane_scale(cursor_state, > - &cursor_scale_w,=20 &cursor_scale_h); > - > - /* Underlying plane has different scale - use overlay=20 cursor */ > - if (cursor_scale_w !=3D underlying_scale_w && > - cursor_scale_h !=3D underlying_scale_h) { > - *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > - return 0; > - } > - > - /* If this plane covers the whole CRTC, no need to=20 check planes > underneath */ - if (plane_state->crtc_x <=3D 0 &&=20 plane_state->crtc_y <=3D 0 > && > - plane_state->crtc_x + plane_state->crtc_w >=3D > crtc_state->mode.hdisplay && - plane_state->crtc_y + > plane_state->crtc_h >=3D crtc_state->mode.vdisplay) { - =09 entire_crtc_covered > =3D true; > - break; > - } > - } > - > - /* If planes do not cover the entire CRTC, use overlay mode to=20 enable > - * cursor over holes > - */ > - if (entire_crtc_covered) > - *cursor_mode =3D DM_CURSOR_NATIVE_MODE; > - else > - *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > - > - return 0; > -} > - > static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev, > struct=20 drm_atomic_commit *state, > struct=20 drm_crtc_state *crtc_state) > @@ -6619,8 +6211,8 @@ static int amdgpu_dm_atomic_check(struct drm_device > *dev, for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { > dm_new_crtc_state =3D to_dm_crtc_state(new_crtc_state); >=20 > - ret =3D dm_crtc_get_cursor_mode(adev, state,=20 dm_new_crtc_state, > - =20 &dm_new_crtc_state->cursor_mode); > + ret =3D amdgpu_dm_crtc_get_cursor_mode(adev, state,=20 dm_new_crtc_state, > + =20 &dm_new_crtc_state->cursor_mode); > if (ret) { > drm_dbg(dev, "Failed to determine cursor=20 mode: %pe\n", ERR_PTR(ret)); > goto fail; > @@ -6754,8 +6346,8 @@ static int amdgpu_dm_atomic_check(struct drm_device > *dev, } >=20 > /* If HW can only do native cursor, check restrictions=20 again */ > - ret =3D dm_crtc_get_cursor_mode(adev, state,=20 dm_new_crtc_state, > - =20 &required_cursor_mode); > + ret =3D amdgpu_dm_crtc_get_cursor_mode(adev, state,=20 dm_new_crtc_state, > + =20 &required_cursor_mode); > if (ret) { > drm_dbg_driver(crtc->dev, > "[CRTC:%d:%s] Checking=20 cursor mode failed\n", > 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 > 1ef92a28e3e9..1ddf5bc88a03 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > @@ -1141,6 +1141,22 @@ void amdgpu_dm_emulated_link_detect(struct dc_link > *link); void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_devi= ce > *adev, struct dc_sink *sink); >=20 > +struct __drm_planes_state *amdgpu_dm_get_next_zpos(struct drm_atomic_com= mit > *state, + struct=20 __drm_planes_state *prev); > + > +/* > + * Use the uniqueness of the plane's (zpos, drm obj ID) combination to > iterate + * by descending zpos, as read from the new plane state. This is > the same + * ordering as defined by drm_atomic_normalize_zpos(). > + */ > +#define for_each_oldnew_plane_in_descending_zpos(__state, plane, > old_plane_state, new_plane_state) \ + for (struct __drm_planes_state *__i= =3D > amdgpu_dm_get_next_zpos((__state), NULL); \ + __i !=3D NULL; __i =3D > amdgpu_dm_get_next_zpos((__state), __i)) \ + =09 for_each_if(((plane) =3D > __i->ptr, \ > + (void)(plane) /* Only to avoid unused- but-set-variable warning */, > \ + (old_plane_state) =3D __i->old_state, =09 \ > + (new_plane_state) =3D __i->new_state, 1)) > + > #if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) > struct amdgpu_ip_block; > bool dm_is_idle(struct amdgpu_ip_block *ip_block); > @@ -1157,19 +1173,11 @@ int dm_crtc_get_scanoutpos(struct amdgpu_device > *adev, int crtc, struct dm_atomic_state *dm_atomic_get_new_state(struct > drm_atomic_commit *state); void dm_atomic_destroy_state(struct > drm_private_obj *obj, > struct drm_private_state *state); > -bool dm_should_update_native_cursor(struct drm_atomic_commit *state, > - struct drm_crtc=20 *old_plane_crtc, > - struct drm_crtc=20 *new_plane_crtc, > - bool enable); > int dm_plane_layer_index_cmp(const void *a, const void *b); > int fill_plane_color_attributes(const struct drm_plane_state *plane_stat= e, > const enum surface_pixel_format=20 format, > enum dc_color_space=20 *color_space); > bool modereset_required(struct drm_crtc_state *crtc_state); > -void dm_get_oriented_plane_size(struct drm_plane_state *plane_state, > - int *src_w, int *src_h); > -void dm_get_plane_scale(struct drm_plane_state *plane_state, > - int *out_plane_scale_w, int=20 *out_plane_scale_h); > bool is_scaling_state_different(const struct dm_connector_state *dm_stat= e, > const struct dm_connector_state=20 *old_dm_state); > void set_multisync_trigger_params(struct dc_stream_state *stream); > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor.c > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor.c new file mode > 100644 > index 000000000000..ab50d58896ab > --- /dev/null > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor.c > @@ -0,0 +1,443 @@ > +// SPDX-License-Identifier: MIT > +/* > + * Copyright 2026 Advanced Micro Devices, Inc. > + * > + * Permission is hereby granted, free of charge, to any person obtaining= a > + * copy of this software and associated documentation files (the > "Software"), + * to deal in the Software without restriction, including > without limitation + * the rights to use, copy, modify, merge, publish, > distribute, sublicense, + * and/or sell copies of the Software, and to > permit persons to whom the + * Software is furnished to do so, subject to > the following conditions: + * > + * The above copyright notice and this permission notice shall be includ= ed > in + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE= SS > OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT= =2E=20 > IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR > ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF > CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WI= TH > THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. > + * > + * Authors: AMD > + * > + */ > + > +#include <drm/drm_atomic.h> > +#include <drm/drm_atomic_helper.h> > +#include <drm/drm_blend.h> > +#include <drm/drm_fourcc.h> > +#include <drm/drm_framebuffer.h> > +#include <drm/drm_plane.h> > +#include <drm/drm_colorop.h> > + > +#include "dc.h" > +#include "dal_asic_id.h" > +#include "amdgpu.h" > +#include "amdgpu_display.h" > +#include "amdgpu_dm.h" > +#include "amdgpu_dm_plane.h" > +#include "amdgpu_dm_cursor.h" > +#include "dm_helpers.h" > + > +static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, > + struct drm_plane_state=20 *new_plane_state, > + struct drm_framebuffer *fb) > +{ > + struct amdgpu_device *adev =3D drm_to_adev(new_acrtc->base.dev); > + struct amdgpu_framebuffer *afb =3D to_amdgpu_framebuffer(fb); > + unsigned int pitch; > + bool linear; > + > + if (fb->width > new_acrtc->max_cursor_width || > + fb->height > new_acrtc->max_cursor_height) { > + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB size=20 %dx%d\n", > + new_plane_state->fb->width, > + new_plane_state->fb->height); > + return -EINVAL; > + } > + if (new_plane_state->src_w !=3D fb->width << 16 || > + new_plane_state->src_h !=3D fb->height << 16) { > + drm_dbg_atomic(adev_to_drm(adev), "Cropping not=20 supported for cursor > plane\n"); + return -EINVAL; > + } > + > + /* Pitch in pixels */ > + pitch =3D fb->pitches[0] / fb->format->cpp[0]; > + > + if (fb->width !=3D pitch) { > + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d=20 doesn't match pitch > %d", + fb->width, pitch); > + return -EINVAL; > + } > + > + switch (pitch) { > + case 64: > + case 128: > + case 256: > + /* FB pitch is supported by cursor plane */ > + break; > + default: > + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB pitch=20 %d px\n", pitch); > + return -EINVAL; > + } > + > + /* Core DRM takes care of checking FB modifiers, so we only need to > + * check tiling flags when the FB doesn't have a modifier. > + */ > + if (!(fb->flags & DRM_MODE_FB_MODIFIERS)) { > +#if defined(CONFIG_DRM_AMD_DC_DCN6_0) || defined(CONFIG_DRM_AMD_DC_DCN5_= 0) > + if (adev->family =3D=3D AMDGPU_FAMILY_GC_12_0_0 > + || adev->family =3D=3D AMDGPU_FAMILY_GC_13_0_1) { > +#else > + if (adev->family =3D=3D AMDGPU_FAMILY_GC_12_0_0) { > +#endif > + linear =3D AMDGPU_TILING_GET(afb->tiling_flags,=20 GFX12_SWIZZLE_MODE) =3D=3D 0; > + } else if (adev->family >=3D AMDGPU_FAMILY_AI) { > + linear =3D AMDGPU_TILING_GET(afb->tiling_flags,=20 SWIZZLE_MODE) =3D=3D 0; > + } else { > + linear =3D AMDGPU_TILING_GET(afb->tiling_flags,=20 ARRAY_MODE) !=3D > DC_ARRAY_2D_TILED_THIN1 && + =20 AMDGPU_TILING_GET(afb->tiling_flags, > ARRAY_MODE) !=3D DC_ARRAY_1D_TILED_THIN1 && + =09 > AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) =3D=3D 0; > + } > + if (!linear) { > + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB=20 not linear"); > + return -EINVAL; > + } > + } > + > + return 0; > +} > + > +/* > + * Helper function for checking the cursor in native mode > + */ > +int amdgpu_dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc, > + struct drm_plane=20 *plane, > + struct drm_plane_state=20 *new_plane_state, > + bool enable) > +{ > + > + struct amdgpu_crtc *new_acrtc; > + int ret; > + > + if (!enable || !new_plane_crtc || > + drm_atomic_plane_disabling(plane->state, new_plane_state)) > + return 0; > + > + new_acrtc =3D to_amdgpu_crtc(new_plane_crtc); > + > + if (new_plane_state->src_x !=3D 0 || new_plane_state->src_y !=3D 0) { > + drm_dbg_atomic(new_plane_crtc->dev, "Cropping not=20 supported for cursor > plane\n"); + return -EINVAL; > + } > + > + if (new_plane_state->fb) { > + ret =3D dm_check_cursor_fb(new_acrtc, new_plane_state, > + =09 new_plane_state->fb); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > +bool amdgpu_dm_should_update_native_cursor(struct drm_atomic_commit *sta= te, > + struct drm_crtc=20 *old_plane_crtc, > + struct drm_crtc=20 *new_plane_crtc, > + bool enable) > +{ > + struct drm_crtc_state *old_crtc_state, *new_crtc_state; > + struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; > + > + if (!enable) { > + if (old_plane_crtc =3D=3D NULL) > + return true; > + > + old_crtc_state =3D drm_atomic_get_old_crtc_state( > + state, old_plane_crtc); > + dm_old_crtc_state =3D to_dm_crtc_state(old_crtc_state); > + > + return dm_old_crtc_state->cursor_mode =3D=3D=20 DM_CURSOR_NATIVE_MODE; > + } > + > + if (new_plane_crtc =3D=3D NULL) > + return true; > + > + new_crtc_state =3D drm_atomic_get_new_crtc_state( > + state, new_plane_crtc); > + dm_new_crtc_state =3D to_dm_crtc_state(new_crtc_state); > + > + return dm_new_crtc_state->cursor_mode =3D=3D DM_CURSOR_NATIVE_MODE; > +} > +EXPORT_IF_KUNIT(amdgpu_dm_should_update_native_cursor); > + > +STATIC_IFN_KUNIT void dm_get_oriented_plane_size(struct drm_plane_state > *plane_state, + int=20 *src_w, int *src_h) > +{ > + switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) { > + case DRM_MODE_ROTATE_90: > + case DRM_MODE_ROTATE_270: > + *src_w =3D plane_state->src_h >> 16; > + *src_h =3D plane_state->src_w >> 16; > + break; > + case DRM_MODE_ROTATE_0: > + case DRM_MODE_ROTATE_180: > + default: > + *src_w =3D plane_state->src_w >> 16; > + *src_h =3D plane_state->src_h >> 16; > + break; > + } > +} > +EXPORT_IF_KUNIT(dm_get_oriented_plane_size); > + > +STATIC_IFN_KUNIT void > +dm_get_plane_scale(struct drm_plane_state *plane_state, > + int *out_plane_scale_w, int *out_plane_scale_h) > +{ > + int plane_src_w, plane_src_h; > + > + dm_get_oriented_plane_size(plane_state, &plane_src_w,=20 &plane_src_h); > + *out_plane_scale_w =3D plane_src_w ? plane_state->crtc_w * 1000 / > plane_src_w : 0; + *out_plane_scale_h =3D plane_src_h ? plane_state- >crtc_h * > 1000 / plane_src_h : 0; +} > +EXPORT_IF_KUNIT(dm_get_plane_scale); > + > +/** > + * DOC: Cursor Modes - Native vs Overlay > + * > + * In native mode, the cursor uses a integrated cursor pipe within each = DCN > hw + * plane. It does not require a dedicated hw plane to enable, but it = is > + * subjected to the same z-order and scaling as the hw plane. It also has > format + * restrictions, a RGB cursor in native mode cannot be enabled > within a non-RGB + * hw plane. > + * > + * In overlay mode, the cursor uses a separate DCN hw plane, and thus has > its + * own scaling and z-pos. It also has no blending restrictions. It > lends to a + * cursor behavior more akin to a DRM client's expectations. > However, it does + * occupy an extra DCN plane, and therefore will only be > used if a DCN plane is + * available. > + */ > + > +/** > + * dm_plane_color_pipeline_active() - Check if a plane's color pipeline > active. + * @state: DRM atomic state > + * @plane: DRM plane to check > + * @use_old: if true, inspect the old colorop states; otherwise the new > ones + * > + * A color pipeline may be selected (color_pipeline !=3D NULL) but still= is > + * inactive if every colorop in the chain is bypassed. Only return > + * true when at least one colorop has bypass =3D=3D false, meaning the c= ursor > + * would be subjected to the transformation in native mode. > + * > + * Return: true if the pipeline modifies pixels, false otherwise. > + */ > +static bool dm_plane_color_pipeline_active(struct drm_atomic_commit *sta= te, > + struct drm_plane=20 *plane, > + bool use_old) > +{ > + struct drm_colorop *colorop; > + struct drm_colorop_state *old_colorop_state, *new_colorop_state; > + int i; > + > + for_each_oldnew_colorop_in_state(state, colorop, old_colorop_state, > new_colorop_state, i) { + struct drm_colorop_state *cstate =3D=20 use_old ? > old_colorop_state : new_colorop_state; + > + if (cstate->colorop->plane !=3D plane) > + continue; > + if (!cstate->bypass) > + return true; > + } > + return false; > +} > + > +/** > + * amdgpu_dm_crtc_get_cursor_mode() - Determine the required cursor mode= on > crtc + * @adev: amdgpu device > + * @state: DRM atomic state > + * @dm_crtc_state: amdgpu state for the CRTC containing the cursor > + * @cursor_mode: Returns the required cursor mode on dm_crtc_state > + * > + * Get whether the cursor should be enabled in native mode, or overlay > mode, on + * the dm_crtc_state. > + * > + * The cursor should be enabled in overlay mode if there exists an > underlying + * plane - on which the cursor may be blended - that is either > YUV formatted, + * scaled differently from the cursor, or has a color > pipeline active. + * > + * Since zpos info is required, drm_atomic_normalize_zpos must be called > before + * calling this function. > + * > + * Return: 0 on success, or an error code if getting the cursor plane st= ate > + * failed. > + */ > +int amdgpu_dm_crtc_get_cursor_mode(struct amdgpu_device *adev, > + struct drm_atomic_commit=20 *state, > + struct dm_crtc_state=20 *dm_crtc_state, > + enum amdgpu_dm_cursor_mode=20 *cursor_mode) > +{ > + struct drm_plane_state *old_plane_state, *plane_state,=20 *cursor_state; > + struct drm_crtc_state *crtc_state =3D &dm_crtc_state->base; > + struct drm_plane *plane; > + bool consider_mode_change =3D false; > + bool entire_crtc_covered =3D false; > + bool cursor_changed =3D false; > + int underlying_scale_w, underlying_scale_h; > + int cursor_scale_w, cursor_scale_h; > + int i; > + > + /* Overlay cursor not supported on HW before DCN > + * DCN401/420 does not have the cursor-on-scaled-plane or > cursor-on-yuv-plane restrictions + * as previous DCN generations, so > enable native mode on DCN401/420 + */ > + if (amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(4, 0, 1) || > + amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(4, 2, 0) || > +#if defined(CONFIG_DRM_AMD_DC_DCN6_0) > + amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(4, 2, 1) || > + amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(6, 0, 0)) { > +#else > + amdgpu_ip_version(adev, DCE_HWIP, 0) =3D=3D IP_VERSION(4, 2, 1)) { > +#endif > + *cursor_mode =3D DM_CURSOR_NATIVE_MODE; > + return 0; > + } > + > + /* Init cursor_mode to be the same as current */ > + *cursor_mode =3D dm_crtc_state->cursor_mode; > + > + /* > + * Cursor mode can change if a plane's format changes, scale=20 changes, is > + * enabled/disabled, z-order changes, or color management=20 properties > change. + */ > + for_each_oldnew_plane_in_state(state, plane, old_plane_state,=20 plane_state, > i) { + int new_scale_w, new_scale_h, old_scale_w,=20 old_scale_h; > + > + /* Only care about planes on this CRTC */ > + if ((drm_plane_mask(plane) & crtc_state->plane_mask) =3D=3D=20 0) > + continue; > + > + if (plane->type =3D=3D DRM_PLANE_TYPE_CURSOR) > + cursor_changed =3D true; > + > + if (drm_atomic_plane_enabling(old_plane_state,=20 plane_state) || > + drm_atomic_plane_disabling(old_plane_state,=20 plane_state) || > + old_plane_state->fb->format !=3D plane_state->fb- >format) { > + consider_mode_change =3D true; > + break; > + } > + > + dm_get_plane_scale(plane_state, &new_scale_w,=20 &new_scale_h); > + dm_get_plane_scale(old_plane_state, &old_scale_w,=20 &old_scale_h); > + if (new_scale_w !=3D old_scale_w || new_scale_h !=3D=20 old_scale_h) { > + consider_mode_change =3D true; > + break; > + } > + > + /* > + * A non-cursor plane moving or resizing (without a=20 scale change) > + * changes how much of the CRTC it covers. This can=20 create or > + * remove a hole under the cursor and thus flip the=20 required > + * cursor mode (native vs overlay), so its destination=20 rect must > + * be re-evaluated too. > + * > + * The cursor plane itself is deliberately excluded: the=20 cursor > + * mode depends on the underlying planes' coverage, not=20 on the > + * cursor's position (see the entire_crtc_covered logic=20 below). > + * Triggering on cursor movement would force every=20 legacy cursor > + * update off its fast path, and in a cursor-only commit=20 =2D where > + * the underlying planes are not part of the state - the=20 coverage > + * loop would see no covering plane and misevaluate the=20 mode as > + * overlay, regressing flip-vs-cursor-legacy. > + */ > + if (plane->type !=3D DRM_PLANE_TYPE_CURSOR && > + (old_plane_state->crtc_x !=3D plane_state->crtc_x || > + old_plane_state->crtc_y !=3D plane_state->crtc_y || > + old_plane_state->crtc_w !=3D plane_state->crtc_w || > + old_plane_state->crtc_h !=3D plane_state->crtc_h)) { > + consider_mode_change =3D true; > + break; > + } > + > + if (dm_plane_color_pipeline_active(state, plane, true) ! =3D > + dm_plane_color_pipeline_active(state, plane, false))=20 { > + consider_mode_change =3D true; > + break; > + } > + } > + > + if (!consider_mode_change && !crtc_state->zpos_changed) > + return 0; > + > + /* > + * If no cursor change on this CRTC, and not enabled on this CRTC,=20 then > + * no need to set cursor mode. This avoids needlessly locking the=20 cursor > + * state. > + */ > + if (!cursor_changed && > + !(drm_plane_mask(crtc_state->crtc->cursor) & crtc_state- >plane_mask)) > { + return 0; > + } > + > + cursor_state =3D drm_atomic_get_plane_state(state, > + =20 crtc_state->crtc->cursor); > + if (IS_ERR(cursor_state)) > + return PTR_ERR(cursor_state); > + > + /* Cursor is disabled */ > + if (!cursor_state->fb) > + return 0; > + > + /* For all planes in descending z-order (all of which are below=20 cursor > + * as per zpos definitions), check their scaling and format > + */ > + for_each_oldnew_plane_in_descending_zpos(state, plane,=20 old_plane_state, > plane_state) { + > + /* Only care about non-cursor planes on this CRTC */ > + if ((drm_plane_mask(plane) & crtc_state->plane_mask) =3D=3D=20 0 || > + plane->type =3D=3D DRM_PLANE_TYPE_CURSOR) > + continue; > + > + /* Underlying plane is YUV format - use overlay cursor=20 */ > + if (amdgpu_dm_plane_is_video_format(plane_state->fb- >format->format)) { > + *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > + return 0; > + } > + > + /* Underlying plane has an active color pipeline -=20 cursor would be > transformed */ + if (dm_plane_color_pipeline_active(state,=20 plane, false)) > { > + *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > + return 0; > + } > + > + dm_get_plane_scale(plane_state, > + &underlying_scale_w,=20 &underlying_scale_h); > + dm_get_plane_scale(cursor_state, > + &cursor_scale_w,=20 &cursor_scale_h); > + > + /* Underlying plane has different scale - use overlay=20 cursor */ > + if (cursor_scale_w !=3D underlying_scale_w && > + cursor_scale_h !=3D underlying_scale_h) { > + *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > + return 0; > + } > + > + /* If this plane covers the whole CRTC, no need to check=20 planes > underneath */ + if (plane_state->crtc_x <=3D 0 &&=20 plane_state->crtc_y <=3D 0 > && > + plane_state->crtc_x + plane_state->crtc_w >=3D > crtc_state->mode.hdisplay && + plane_state->crtc_y + > plane_state->crtc_h >=3D crtc_state->mode.vdisplay) { + =09 entire_crtc_covered > =3D true; > + break; > + } > + } > + > + /* If planes do not cover the entire CRTC, use overlay mode to=20 enable > + * cursor over holes > + */ > + if (entire_crtc_covered) > + *cursor_mode =3D DM_CURSOR_NATIVE_MODE; > + else > + *cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > + > + return 0; > +} > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor.h > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor.h new file mode > 100644 > index 000000000000..5f619e4474aa > --- /dev/null > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor.h > @@ -0,0 +1,52 @@ > +/* SPDX-License-Identifier: MIT */ > +/* > + * Copyright 2026 Advanced Micro Devices, Inc. > + * > + * Permission is hereby granted, free of charge, to any person obtaining= a > + * copy of this software and associated documentation files (the > "Software"), + * to deal in the Software without restriction, including > without limitation + * the rights to use, copy, modify, merge, publish, > distribute, sublicense, + * and/or sell copies of the Software, and to > permit persons to whom the + * Software is furnished to do so, subject to > the following conditions: + * > + * The above copyright notice and this permission notice shall be includ= ed > in + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE= SS > OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT= =2E=20 > IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR > ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF > CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WI= TH > THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. > + * > + * Authors: AMD > + * > + */ > + > +#ifndef __AMDGPU_DM_CURSOR_H__ > +#define __AMDGPU_DM_CURSOR_H__ > + > +int amdgpu_dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc, > + struct drm_plane=20 *plane, > + struct drm_plane_state=20 *new_plane_state, > + bool enable); > + > +bool amdgpu_dm_should_update_native_cursor(struct drm_atomic_commit *sta= te, > + struct drm_crtc=20 *old_plane_crtc, > + struct drm_crtc=20 *new_plane_crtc, > + bool enable); > + > +int amdgpu_dm_crtc_get_cursor_mode(struct amdgpu_device *adev, > + struct drm_atomic_commit=20 *state, > + struct dm_crtc_state=20 *dm_crtc_state, > + enum amdgpu_dm_cursor_mode=20 *cursor_mode); > + > +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) > +void dm_get_oriented_plane_size(struct drm_plane_state *plane_state, > + int *src_w, int *src_h); > +void dm_get_plane_scale(struct drm_plane_state *plane_state, > + int *out_plane_scale_w, int=20 *out_plane_scale_h); > +#endif /* CONFIG_DRM_AMD_DC_KUNIT_TEST */ > + > +#endif /* __AMDGPU_DM_CURSOR_H__ */ > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile > b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile index > e58ffc4dcd84..3a51fccc2a5e 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile > @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D > amdgpu_dm_mst_types_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D > amdgpu_dm_pp_smu_test.o > obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D amdgpu_dm_test.o > obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D amdgpu_dm_freesync_test.o > +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D amdgpu_dm_cursor_test.o > obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D amdgpu_dm_crtc_test.o > obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D amdgpu_dm_services_test.o > obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=3D amdgpu_dm_helpers_test.o > diff --git > a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c > b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c new > file mode 100644 > index 000000000000..3da76794ece9 > --- /dev/null > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c > @@ -0,0 +1,268 @@ > +// SPDX-License-Identifier: GPL-2.0 OR MIT > +/* > + * KUnit tests for amdgpu_dm_cursor.c > + * > + * Copyright 2026 Advanced Micro Devices, Inc. > + */ > + > +#include <kunit/test.h> > +#include <drm/drm_atomic.h> > +#include <drm/drm_blend.h> > +#include <drm/drm_crtc.h> > +#include <drm/drm_plane.h> > + > +#include "dc.h" > +#include "amdgpu.h" > +#include "amdgpu_mode.h" > +#include "amdgpu_dm.h" > +#include "amdgpu_dm_cursor.h" > + > +/* Tests for amdgpu_dm_should_update_native_cursor() */ > + > +/** > + * dm_test_should_update_native_cursor_without_crtc - Test NULL crtc cas= es > update native cursor + * @test: The KUnit test context > + */ > +static void dm_test_should_update_native_cursor_without_crtc(struct kunit > *test) +{ > + KUNIT_EXPECT_TRUE(test, amdgpu_dm_should_update_native_cursor(NULL,=20 NULL, > NULL, false)); + KUNIT_EXPECT_TRUE(test, > amdgpu_dm_should_update_native_cursor(NULL, NULL, NULL, true)); +} > + > +/** > + * dm_test_should_update_native_cursor_disable_native - Test disable path > reads old crtc cursor mode + * @test: The KUnit test context > + */ > +static void dm_test_should_update_native_cursor_disable_native(struct ku= nit > *test) +{ > + struct dm_crtc_state *dm_crtc_state; > + struct drm_atomic_commit *state; > + struct drm_crtc *crtc; > + > + state =3D kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, state); > + > + crtc =3D kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, crtc); > + > + dm_crtc_state =3D kunit_kzalloc(test, sizeof(*dm_crtc_state),=20 GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); > + > + state->crtcs =3D kunit_kzalloc(test, sizeof(*state->crtcs),=20 GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); > + > + crtc->index =3D 0; > + dm_crtc_state->cursor_mode =3D DM_CURSOR_NATIVE_MODE; > + state->crtcs[0].old_state =3D &dm_crtc_state->base; > + > + KUNIT_EXPECT_TRUE(test, > + =20 amdgpu_dm_should_update_native_cursor(state, crtc, NULL, false)); > +} > + > +/** > + * dm_test_should_update_native_cursor_enable_overlay - Test enable path > reads new crtc cursor mode + * @test: The KUnit test context > + */ > +static void dm_test_should_update_native_cursor_enable_overlay(struct ku= nit > *test) +{ > + struct dm_crtc_state *dm_crtc_state; > + struct drm_atomic_commit *state; > + struct drm_crtc *crtc; > + > + state =3D kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, state); > + > + crtc =3D kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, crtc); > + > + dm_crtc_state =3D kunit_kzalloc(test, sizeof(*dm_crtc_state),=20 GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); > + > + state->crtcs =3D kunit_kzalloc(test, sizeof(*state->crtcs),=20 GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); > + > + crtc->index =3D 0; > + dm_crtc_state->cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > + state->crtcs[0].new_state =3D &dm_crtc_state->base; > + > + KUNIT_EXPECT_FALSE(test, > + =20 amdgpu_dm_should_update_native_cursor(state, NULL, crtc, true)); > +} > + > +/* Tests for dm_get_oriented_plane_size() */ > + > +/** > + * dm_test_oriented_plane_size_rotate_0 - Test Oriented plane size rotat= e 0 > + * @test: The KUnit test context > + */ > +static void dm_test_oriented_plane_size_rotate_0(struct kunit *test) > +{ > + struct drm_plane_state plane_state =3D { 0 }; > + int src_w =3D 0; > + int src_h =3D 0; > + > + plane_state.rotation =3D DRM_MODE_ROTATE_0; > + plane_state.src_w =3D 1920 << 16; > + plane_state.src_h =3D 1080 << 16; > + > + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > + > + KUNIT_EXPECT_EQ(test, src_w, 1920); > + KUNIT_EXPECT_EQ(test, src_h, 1080); > +} > + > +/** > + * dm_test_oriented_plane_size_rotate_90 - Test Oriented plane size rota= te > 90 + * @test: The KUnit test context > + */ > +static void dm_test_oriented_plane_size_rotate_90(struct kunit *test) > +{ > + struct drm_plane_state plane_state =3D { 0 }; > + int src_w =3D 0; > + int src_h =3D 0; > + > + plane_state.rotation =3D DRM_MODE_ROTATE_90; > + plane_state.src_w =3D 1920 << 16; > + plane_state.src_h =3D 1080 << 16; > + > + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > + > + KUNIT_EXPECT_EQ(test, src_w, 1080); > + KUNIT_EXPECT_EQ(test, src_h, 1920); > +} > + > +/** > + * dm_test_oriented_plane_size_rotate_180 - Test Oriented plane size rot= ate > 180 + * @test: The KUnit test context > + */ > +static void dm_test_oriented_plane_size_rotate_180(struct kunit *test) > +{ > + struct drm_plane_state plane_state =3D { 0 }; > + int src_w =3D 0; > + int src_h =3D 0; > + > + plane_state.rotation =3D DRM_MODE_ROTATE_180; > + plane_state.src_w =3D 1920 << 16; > + plane_state.src_h =3D 1080 << 16; > + > + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > + > + KUNIT_EXPECT_EQ(test, src_w, 1920); > + KUNIT_EXPECT_EQ(test, src_h, 1080); > +} > + > +/** > + * dm_test_oriented_plane_size_rotate_270 - Test Oriented plane size rot= ate > 270 + * @test: The KUnit test context > + */ > +static void dm_test_oriented_plane_size_rotate_270(struct kunit *test) > +{ > + struct drm_plane_state plane_state =3D { 0 }; > + int src_w =3D 0; > + int src_h =3D 0; > + > + plane_state.rotation =3D DRM_MODE_ROTATE_270; > + plane_state.src_w =3D 1920 << 16; > + plane_state.src_h =3D 1080 << 16; > + > + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > + > + KUNIT_EXPECT_EQ(test, src_w, 1080); > + KUNIT_EXPECT_EQ(test, src_h, 1920); > +} > + > +/* Tests for dm_get_plane_scale() */ > + > +/** > + * dm_test_get_plane_scale_identity - Test Get plane scale identity > + * @test: The KUnit test context > + */ > +static void dm_test_get_plane_scale_identity(struct kunit *test) > +{ > + struct drm_plane_state plane_state =3D { 0 }; > + int scale_w =3D 0; > + int scale_h =3D 0; > + > + plane_state.rotation =3D DRM_MODE_ROTATE_0; > + plane_state.src_w =3D 1920 << 16; > + plane_state.src_h =3D 1080 << 16; > + plane_state.crtc_w =3D 1920; > + plane_state.crtc_h =3D 1080; > + > + dm_get_plane_scale(&plane_state, &scale_w, &scale_h); > + > + KUNIT_EXPECT_EQ(test, scale_w, 1000); > + KUNIT_EXPECT_EQ(test, scale_h, 1000); > +} > + > +/** > + * dm_test_get_plane_scale_rotate_90_identity - Test Get plane scale rot= ate > 90 identity + * @test: The KUnit test context > + */ > +static void dm_test_get_plane_scale_rotate_90_identity(struct kunit *tes= t) > +{ > + struct drm_plane_state plane_state =3D { 0 }; > + int scale_w =3D 0; > + int scale_h =3D 0; > + > + plane_state.rotation =3D DRM_MODE_ROTATE_90; > + plane_state.src_w =3D 1920 << 16; > + plane_state.src_h =3D 1080 << 16; > + plane_state.crtc_w =3D 1080; > + plane_state.crtc_h =3D 1920; > + > + dm_get_plane_scale(&plane_state, &scale_w, &scale_h); > + > + KUNIT_EXPECT_EQ(test, scale_w, 1000); > + KUNIT_EXPECT_EQ(test, scale_h, 1000); > +} > + > +/** > + * dm_test_get_plane_scale_zero_src_width - Test Get plane scale zero src > width + * @test: The KUnit test context > + */ > +static void dm_test_get_plane_scale_zero_src_width(struct kunit *test) > +{ > + struct drm_plane_state plane_state =3D { 0 }; > + int scale_w =3D 0; > + int scale_h =3D 0; > + > + plane_state.rotation =3D DRM_MODE_ROTATE_0; > + plane_state.src_w =3D 0; > + plane_state.src_h =3D 1080 << 16; > + plane_state.crtc_w =3D 100; > + plane_state.crtc_h =3D 200; > + > + dm_get_plane_scale(&plane_state, &scale_w, &scale_h); > + > + KUNIT_EXPECT_EQ(test, scale_w, 0); > + KUNIT_EXPECT_EQ(test, scale_h, 185); > +} > + > +static struct kunit_case amdgpu_dm_cursor_tests[] =3D { > + /* amdgpu_dm_should_update_native_cursor */ > + KUNIT_CASE(dm_test_should_update_native_cursor_without_crtc), > + KUNIT_CASE(dm_test_should_update_native_cursor_disable_native), > + KUNIT_CASE(dm_test_should_update_native_cursor_enable_overlay), > + /* dm_get_oriented_plane_size */ > + KUNIT_CASE(dm_test_oriented_plane_size_rotate_0), > + KUNIT_CASE(dm_test_oriented_plane_size_rotate_90), > + KUNIT_CASE(dm_test_oriented_plane_size_rotate_180), > + KUNIT_CASE(dm_test_oriented_plane_size_rotate_270), > + /* dm_get_plane_scale */ > + KUNIT_CASE(dm_test_get_plane_scale_identity), > + KUNIT_CASE(dm_test_get_plane_scale_rotate_90_identity), > + KUNIT_CASE(dm_test_get_plane_scale_zero_src_width), > + {} > +}; > + > +static struct kunit_suite amdgpu_dm_cursor_test_suite =3D { > + .name =3D "amdgpu_dm_cursor", > + .test_cases =3D amdgpu_dm_cursor_tests, > +}; > + > +kunit_test_suite(amdgpu_dm_cursor_test_suite); > + > +MODULE_AUTHOR("AMD"); > +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_cursor"); > +MODULE_LICENSE("Dual MIT/GPL"); > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c > b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c index > 428d24259198..3c10eec9b1e0 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c > @@ -227,76 +227,6 @@ static void dm_test_atomic_get_new_state_match(struct > kunit *test) KUNIT_EXPECT_PTR_EQ(test, dm_atomic_get_new_state(state), > dm_state); } >=20 > -/** > - * dm_test_should_update_native_cursor_without_crtc - Test NULL crtc cas= es > update native cursor - * @test: The KUnit test context > - */ > -static void dm_test_should_update_native_cursor_without_crtc(struct kunit > *test) -{ > - KUNIT_EXPECT_TRUE(test, dm_should_update_native_cursor(NULL, NULL,=20 NULL, > false)); - KUNIT_EXPECT_TRUE(test, dm_should_update_native_cursor(NULL, > NULL, NULL, true)); -} > - > -/** > - * dm_test_should_update_native_cursor_disable_native - Test disable path > reads old crtc cursor mode - * @test: The KUnit test context > - */ > -static void dm_test_should_update_native_cursor_disable_native(struct ku= nit > *test) -{ > - struct dm_crtc_state *dm_crtc_state; > - struct drm_atomic_commit *state; > - struct drm_crtc *crtc; > - > - state =3D kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, state); > - > - crtc =3D kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, crtc); > - > - dm_crtc_state =3D kunit_kzalloc(test, sizeof(*dm_crtc_state),=20 GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); > - > - state->crtcs =3D kunit_kzalloc(test, sizeof(*state->crtcs),=20 GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, state->crtcs); > - > - crtc->index =3D 0; > - dm_crtc_state->cursor_mode =3D DM_CURSOR_NATIVE_MODE; > - state->crtcs[0].old_state =3D &dm_crtc_state->base; > - > - KUNIT_EXPECT_TRUE(test, > - dm_should_update_native_cursor(state,=20 crtc, NULL, false)); > -} > - > -/** > - * dm_test_should_update_native_cursor_enable_overlay - Test enable path > reads new crtc cursor mode - * @test: The KUnit test context > - */ > -static void dm_test_should_update_native_cursor_enable_overlay(struct ku= nit > *test) -{ > - struct dm_crtc_state *dm_crtc_state; > - struct drm_atomic_commit *state; > - struct drm_crtc *crtc; > - > - state =3D kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, state); > - > - crtc =3D kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, crtc); > - > - dm_crtc_state =3D kunit_kzalloc(test, sizeof(*dm_crtc_state),=20 GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); > - > - state->crtcs =3D kunit_kzalloc(test, sizeof(*state->crtcs),=20 GFP_KERNEL); > - KUNIT_ASSERT_NOT_NULL(test, state->crtcs); > - > - crtc->index =3D 0; > - dm_crtc_state->cursor_mode =3D DM_CURSOR_OVERLAY_MODE; > - state->crtcs[0].new_state =3D &dm_crtc_state->base; > - > - KUNIT_EXPECT_FALSE(test, > - dm_should_update_native_cursor(state,=20 NULL, crtc, true)); > -} > - > /** > * dm_test_atomic_destroy_state_no_context - Test destroying DM atomic > state without a DC context * @test: The KUnit test context > @@ -599,156 +529,6 @@ static void > dm_test_modereset_not_required_when_inactive_without_modeset(struct > KUNIT_EXPECT_FALSE(test, modereset_required(&crtc_state)); > } >=20 > -/* Tests for dm_get_oriented_plane_size() */ > - > -/** > - * dm_test_oriented_plane_size_rotate_0 - Test Oriented plane size rotat= e 0 > - * @test: The KUnit test context > - */ > -static void dm_test_oriented_plane_size_rotate_0(struct kunit *test) > -{ > - struct drm_plane_state plane_state =3D { 0 }; > - int src_w =3D 0; > - int src_h =3D 0; > - > - plane_state.rotation =3D DRM_MODE_ROTATE_0; > - plane_state.src_w =3D 1920 << 16; > - plane_state.src_h =3D 1080 << 16; > - > - dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > - > - KUNIT_EXPECT_EQ(test, src_w, 1920); > - KUNIT_EXPECT_EQ(test, src_h, 1080); > -} > - > -/** > - * dm_test_oriented_plane_size_rotate_90 - Test Oriented plane size rota= te > 90 - * @test: The KUnit test context > - */ > -static void dm_test_oriented_plane_size_rotate_90(struct kunit *test) > -{ > - struct drm_plane_state plane_state =3D { 0 }; > - int src_w =3D 0; > - int src_h =3D 0; > - > - plane_state.rotation =3D DRM_MODE_ROTATE_90; > - plane_state.src_w =3D 1920 << 16; > - plane_state.src_h =3D 1080 << 16; > - > - dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > - > - KUNIT_EXPECT_EQ(test, src_w, 1080); > - KUNIT_EXPECT_EQ(test, src_h, 1920); > -} > - > -/** > - * dm_test_oriented_plane_size_rotate_180 - Test Oriented plane size rot= ate > 180 - * @test: The KUnit test context > - */ > -static void dm_test_oriented_plane_size_rotate_180(struct kunit *test) > -{ > - struct drm_plane_state plane_state =3D { 0 }; > - int src_w =3D 0; > - int src_h =3D 0; > - > - plane_state.rotation =3D DRM_MODE_ROTATE_180; > - plane_state.src_w =3D 1920 << 16; > - plane_state.src_h =3D 1080 << 16; > - > - dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > - > - KUNIT_EXPECT_EQ(test, src_w, 1920); > - KUNIT_EXPECT_EQ(test, src_h, 1080); > -} > - > -/** > - * dm_test_oriented_plane_size_rotate_270 - Test Oriented plane size rot= ate > 270 - * @test: The KUnit test context > - */ > -static void dm_test_oriented_plane_size_rotate_270(struct kunit *test) > -{ > - struct drm_plane_state plane_state =3D { 0 }; > - int src_w =3D 0; > - int src_h =3D 0; > - > - plane_state.rotation =3D DRM_MODE_ROTATE_270; > - plane_state.src_w =3D 1920 << 16; > - plane_state.src_h =3D 1080 << 16; > - > - dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); > - > - KUNIT_EXPECT_EQ(test, src_w, 1080); > - KUNIT_EXPECT_EQ(test, src_h, 1920); > -} > - > -/* Tests for dm_get_plane_scale() */ > - > -/** > - * dm_test_get_plane_scale_identity - Test Get plane scale identity > - * @test: The KUnit test context > - */ > -static void dm_test_get_plane_scale_identity(struct kunit *test) > -{ > - struct drm_plane_state plane_state =3D { 0 }; > - int scale_w =3D 0; > - int scale_h =3D 0; > - > - plane_state.rotation =3D DRM_MODE_ROTATE_0; > - plane_state.src_w =3D 1920 << 16; > - plane_state.src_h =3D 1080 << 16; > - plane_state.crtc_w =3D 1920; > - plane_state.crtc_h =3D 1080; > - > - dm_get_plane_scale(&plane_state, &scale_w, &scale_h); > - > - KUNIT_EXPECT_EQ(test, scale_w, 1000); > - KUNIT_EXPECT_EQ(test, scale_h, 1000); > -} > - > -/** > - * dm_test_get_plane_scale_rotate_90_identity - Test Get plane scale rot= ate > 90 identity - * @test: The KUnit test context > - */ > -static void dm_test_get_plane_scale_rotate_90_identity(struct kunit *tes= t) > -{ > - struct drm_plane_state plane_state =3D { 0 }; > - int scale_w =3D 0; > - int scale_h =3D 0; > - > - plane_state.rotation =3D DRM_MODE_ROTATE_90; > - plane_state.src_w =3D 1920 << 16; > - plane_state.src_h =3D 1080 << 16; > - plane_state.crtc_w =3D 1080; > - plane_state.crtc_h =3D 1920; > - > - dm_get_plane_scale(&plane_state, &scale_w, &scale_h); > - > - KUNIT_EXPECT_EQ(test, scale_w, 1000); > - KUNIT_EXPECT_EQ(test, scale_h, 1000); > -} > - > -/** > - * dm_test_get_plane_scale_zero_src_width - Test Get plane scale zero src > width - * @test: The KUnit test context > - */ > -static void dm_test_get_plane_scale_zero_src_width(struct kunit *test) > -{ > - struct drm_plane_state plane_state =3D { 0 }; > - int scale_w =3D 0; > - int scale_h =3D 0; > - > - plane_state.rotation =3D DRM_MODE_ROTATE_0; > - plane_state.src_w =3D 0; > - plane_state.src_h =3D 1080 << 16; > - plane_state.crtc_w =3D 100; > - plane_state.crtc_h =3D 200; > - > - dm_get_plane_scale(&plane_state, &scale_w, &scale_h); > - > - KUNIT_EXPECT_EQ(test, scale_w, 0); > - KUNIT_EXPECT_EQ(test, scale_h, 185); > -} > - > /* Tests for is_scaling_state_different() */ >=20 > /** > @@ -1386,9 +1166,6 @@ static struct kunit_case amdgpu_dm_tests[] =3D { > KUNIT_CASE(dm_test_crtc_get_scanoutpos_no_stream), > KUNIT_CASE(dm_test_atomic_get_new_state_empty), > KUNIT_CASE(dm_test_atomic_get_new_state_match), > - KUNIT_CASE(dm_test_should_update_native_cursor_without_crtc), > - KUNIT_CASE(dm_test_should_update_native_cursor_disable_native), > - KUNIT_CASE(dm_test_should_update_native_cursor_enable_overlay), > KUNIT_CASE(dm_test_atomic_destroy_state_no_context), > /* dm_plane_layer_index_cmp */ > KUNIT_CASE(dm_test_plane_layer_index_cmp_equal), > @@ -1407,15 +1184,6 @@ static struct kunit_case amdgpu_dm_tests[] =3D { > KUNIT_CASE(dm_test_modereset_required_when_inactive_and_modeset), > =09 KUNIT_CASE(dm_test_modereset_not_required_when_active_and_modeset), > =09 KUNIT_CASE(dm_test_modereset_not_required_when_inactive_without_modeset), > - /* dm_get_oriented_plane_size */ > - KUNIT_CASE(dm_test_oriented_plane_size_rotate_0), > - KUNIT_CASE(dm_test_oriented_plane_size_rotate_90), > - KUNIT_CASE(dm_test_oriented_plane_size_rotate_180), > - KUNIT_CASE(dm_test_oriented_plane_size_rotate_270), > - /* dm_get_plane_scale */ > - KUNIT_CASE(dm_test_get_plane_scale_identity), > - KUNIT_CASE(dm_test_get_plane_scale_rotate_90_identity), > - KUNIT_CASE(dm_test_get_plane_scale_zero_src_width), > /* is_scaling_state_different */ > KUNIT_CASE(dm_test_scaling_state_same), > KUNIT_CASE(dm_test_scaling_state_scaling_changed),