On Thursday, July 23, 2026 10:13:25 PM Central European Summer Time Fangzhi 
Zuo wrote:
> From: Alex Hung <[email protected]>
> 
> [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:
> 
>   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.
> 
> 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.
> 
> 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.
> 
> Relocate the corresponding KUnit tests into amdgpu_dm_cursor_test.c.
> 
> No functional change.

Hi,

This commit regresses a recent bug fix from commit "Set native cursor mode for 
disabled CRTCs". The amdgpu_dm_crtc_get_cursor_mode() function that was added 
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


> 
> 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_cursor.c
> create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_cursor.h
> create mode 100644
> drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_cursor_test.c
> 
> 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 = \
>       amdgpu_dm_audio.o \
>       amdgpu_dm_dmub.o \
>       amdgpu_dm_connector.o \
> -     amdgpu_dm_freesync.o
> +     amdgpu_dm_freesync.o \
> +     amdgpu_dm_cursor.o
> 
>  ifdef CONFIG_DRM_AMD_DC_FP
>  AMDGPUDM += 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"
> 
>  #include "ivsrcid/ivsrcid_vislands30.h"
> 
> @@ -5760,133 +5761,6 @@ static bool should_reset_plane(struct
> drm_atomic_commit *state, return false;
>  }
> 
> -static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc,
> -                           struct drm_plane_state 
*new_plane_state,
> -                           struct drm_framebuffer *fb)
> -{
> -     struct amdgpu_device *adev = drm_to_adev(new_acrtc->base.dev);
> -     struct amdgpu_framebuffer *afb = 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 
%dx%d\n",
> -                              new_plane_state->fb->width,
> -                              new_plane_state->fb->height);
> -             return -EINVAL;
> -     }
> -     if (new_plane_state->src_w != fb->width << 16 ||
> -         new_plane_state->src_h != fb->height << 16) {
> -             drm_dbg_atomic(adev_to_drm(adev), "Cropping not 
supported for cursor
> plane\n"); -          return -EINVAL;
> -     }
> -
> -     /* Pitch in pixels */
> -     pitch = fb->pitches[0] / fb->format->cpp[0];
> -
> -     if (fb->width != pitch) {
> -             drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d 
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 
%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 == AMDGPU_FAMILY_GC_12_0_0) {
> -                     linear = AMDGPU_TILING_GET(afb->tiling_flags, 
GFX12_SWIZZLE_MODE) == 0;
> -             } else if (adev->family >= AMDGPU_FAMILY_AI) {
> -                     linear = AMDGPU_TILING_GET(afb->tiling_flags, 
SWIZZLE_MODE) == 0;
> -             } else {
> -                     linear = AMDGPU_TILING_GET(afb->tiling_flags, 
ARRAY_MODE) !=
> DC_ARRAY_2D_TILED_THIN1 && -                           
AMDGPU_TILING_GET(afb->tiling_flags,
> ARRAY_MODE) != DC_ARRAY_1D_TILED_THIN1 && -                           
> AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0;
> -             }
> -             if (!linear) {
> -                     drm_dbg_atomic(adev_to_drm(adev), "Cursor FB 
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 
*plane,
> -                                     struct drm_plane_state 
*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 = to_amdgpu_crtc(new_plane_crtc);
> -
> -     if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) {
> -             drm_dbg_atomic(new_plane_crtc->dev, "Cropping not 
supported for cursor
> plane\n"); -          return -EINVAL;
> -     }
> -
> -     if (new_plane_state->fb) {
> -             ret = dm_check_cursor_fb(new_acrtc, new_plane_state,
> -                                             
new_plane_state->fb);
> -             if (ret)
> -                     return ret;
> -     }
> -
> -     return 0;
> -}
> -
> -STATIC_IFN_KUNIT bool dm_should_update_native_cursor(struct
> drm_atomic_commit *state, -                                   
             struct drm_crtc *old_plane_crtc,
> -                                                  struct 
drm_crtc *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 == NULL)
> -                     return true;
> -
> -             old_crtc_state = drm_atomic_get_old_crtc_state(
> -                     state, old_plane_crtc);
> -             dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
> -
> -             return dm_old_crtc_state->cursor_mode == 
DM_CURSOR_NATIVE_MODE;
> -     } else {
> -             if (new_plane_crtc == NULL)
> -                     return true;
> -
> -             new_crtc_state = drm_atomic_get_new_crtc_state(
> -                     state, new_plane_crtc);
> -             dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
> -
> -             return dm_new_crtc_state->cursor_mode == 
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 = to_dm_plane_state(new_plane_state);
>       dm_old_plane_state = to_dm_plane_state(old_plane_state);
> 
> -     update_native_cursor = dm_should_update_native_cursor(state,
> -                                                           
old_plane_crtc,
> -                                                           
new_plane_crtc,
> -                                                           
enable);
> +     update_native_cursor = amdgpu_dm_should_update_native_cursor(state,
> +                                                             
     old_plane_crtc,
> +                                                             
     new_plane_crtc,
> +                                                             
     enable);
> 
>       if (plane->type == DRM_PLANE_TYPE_CURSOR && update_native_cursor) 
{
> -             ret = dm_check_native_cursor_state(new_plane_crtc, 
plane,
> -                                                 
new_plane_state, enable);
> +             ret = 
amdgpu_dm_check_native_cursor_state(new_plane_crtc, plane,
> +                                                       
new_plane_state, enable);
>               if (ret)
>                       return ret;
> 
> @@ -6048,8 +5922,8 @@ static int dm_update_plane_state(struct dc *dc,
>  out:
>       /* If enabling cursor overlay failed, attempt fallback to native 
mode */
>       if (enable && ret == -EINVAL && plane->type == 
DRM_PLANE_TYPE_CURSOR) {
> -             ret = dm_check_native_cursor_state(new_plane_crtc, 
plane,
> -                                                 
new_plane_state, enable);
> +             ret = 
amdgpu_dm_check_native_cursor_state(new_plane_crtc, plane,
> +                                                       
new_plane_state, enable);
>               if (ret)
>                       return ret;
> 
> @@ -6059,37 +5933,6 @@ static int dm_update_plane_state(struct dc *dc,
>       return ret;
>  }
> 
> -STATIC_IFN_KUNIT void dm_get_oriented_plane_size(struct drm_plane_state
> *plane_state, -                                        int 
*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 = plane_state->src_h >> 16;
> -             *src_h = plane_state->src_w >> 16;
> -             break;
> -     case DRM_MODE_ROTATE_0:
> -     case DRM_MODE_ROTATE_180:
> -     default:
> -             *src_w = plane_state->src_w >> 16;
> -             *src_h = 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, 
&plane_src_h);
> -     *out_plane_scale_w = plane_src_w ? plane_state->crtc_w * 1000 /
> plane_src_w : 0; -    *out_plane_scale_h = 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. It'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];
>  }
> 
> -/*
> - * 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 =
> __get_next_zpos((__state), NULL); \ -      __i != NULL; __i =
> __get_next_zpos((__state), __i))              \
> -             for_each_if(((plane) = __i->ptr,                        
        \
> -                          (void)(plane) /* Only to avoid unused-
but-set-variable warning */,
> \ -                        (old_plane_state) = __i->old_state,                
\
> -                          (new_plane_state) = __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); }
> 
> -/**
> - * 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 != NULL) but still is
> - * inactive if every colorop in the chain is bypassed.  Only return
> - * true when at least one colorop has bypass == false, meaning the cursor
> - * 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 *state,
> -                                        struct drm_plane 
*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 = 
use_old ?
> old_colorop_state : new_colorop_state; -
> -             if (cstate->colorop->plane != 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 state
> - * failed.
> - */
> -static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
> -                                struct drm_atomic_commit 
*state,
> -                                struct dm_crtc_state 
*dm_crtc_state,
> -                                enum amdgpu_dm_cursor_mode 
*cursor_mode)
> -{
> -     struct drm_plane_state *old_plane_state, *plane_state, 
*cursor_state;
> -     struct drm_crtc_state *crtc_state = &dm_crtc_state->base;
> -     struct drm_plane *plane;
> -     bool consider_mode_change = false;
> -     bool entire_crtc_covered = false;
> -     bool cursor_changed = 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) == IP_VERSION(4, 0, 1) ||
> -         amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
> -         amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
> -         !dm_crtc_state->base.enable) {
> -             *cursor_mode = DM_CURSOR_NATIVE_MODE;
> -             return 0;
> -     }
> -
> -     /* Init cursor_mode to be the same as current */
> -     *cursor_mode = dm_crtc_state->cursor_mode;
> -
> -     /*
> -      * Cursor mode can change if a plane's format changes, scale 
changes, is
> -      * enabled/disabled, z-order changes, or color management 
properties
> change. -      */
> -     for_each_oldnew_plane_in_state(state, plane, old_plane_state, 
plane_state,
> i) { -                int new_scale_w, new_scale_h, old_scale_w, 
old_scale_h;
> -
> -             /* Only care about planes on this CRTC */
> -             if ((drm_plane_mask(plane) & crtc_state->plane_mask) == 
0)
> -                     continue;
> -
> -             if (plane->type == DRM_PLANE_TYPE_CURSOR)
> -                     cursor_changed = true;
> -
> -             if (drm_atomic_plane_enabling(old_plane_state, 
plane_state) ||
> -                 drm_atomic_plane_disabling(old_plane_state, 
plane_state) ||
> -                 old_plane_state->fb->format != plane_state->fb-
>format) {
> -                     consider_mode_change = true;
> -                     break;
> -             }
> -
> -             dm_get_plane_scale(plane_state, &new_scale_w, 
&new_scale_h);
> -             dm_get_plane_scale(old_plane_state, &old_scale_w, 
&old_scale_h);
> -             if (new_scale_w != old_scale_w || new_scale_h != 
old_scale_h) {
> -                     consider_mode_change = true;
> -                     break;
> -             }
> -
> -             /*
> -              * A non-cursor plane moving or resizing (without a 
scale change)
> -              * changes how much of the CRTC it covers. This can 
create or
> -              * remove a hole under the cursor and thus flip the 
required
> -              * cursor mode (native vs overlay), so its destination 
rect must
> -              * be re-evaluated too.
> -              *
> -              * The cursor plane itself is deliberately excluded: 
the cursor
> -              * mode depends on the underlying planes' coverage, not 
on the
> -              * cursor's position (see the entire_crtc_covered logic 
below).
> -              * Triggering on cursor movement would force every 
legacy cursor
> -              * update off its fast path, and in a cursor-only commit 
- where
> -              * the underlying planes are not part of the state - 
the coverage
> -              * loop would see no covering plane and misevaluate the 
mode as
> -              * overlay, regressing flip-vs-cursor-legacy.
> -              */
> -             if (plane->type != DRM_PLANE_TYPE_CURSOR &&
> -                 (old_plane_state->crtc_x != plane_state->crtc_x ||
> -                  old_plane_state->crtc_y != plane_state->crtc_y ||
> -                  old_plane_state->crtc_w != plane_state->crtc_w ||
> -                  old_plane_state->crtc_h != plane_state->crtc_h)) {
> -                     consider_mode_change = true;
> -                     break;
> -             }
> -
> -             if (dm_plane_color_pipeline_active(state, plane, true) 
!=
> -                 dm_plane_color_pipeline_active(state, plane, 
false)) {
> -                     consider_mode_change = 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, 
then
> -      * no need to set cursor mode. This avoids needlessly locking the 
cursor
> -      * state.
> -      */
> -     if (!cursor_changed &&
> -         !(drm_plane_mask(crtc_state->crtc->cursor) & crtc_state-
>plane_mask))
> { -           return 0;
> -     }
> -
> -     cursor_state = drm_atomic_get_plane_state(state,
> -                                               
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 
cursor
> -      * as per zpos definitions), check their scaling and format
> -      */
> -     for_each_oldnew_plane_in_descending_zpos(state, plane, 
old_plane_state,
> plane_state) { -
> -             /* Only care about non-cursor planes on this CRTC */
> -             if ((drm_plane_mask(plane) & crtc_state->plane_mask) == 
0 ||
> -                 plane->type == DRM_PLANE_TYPE_CURSOR)
> -                     continue;
> -
> -             /* Underlying plane is YUV format - use overlay cursor 
*/
> -             if (amdgpu_dm_plane_is_video_format(plane_state->fb-
>format->format)) {
> -                     *cursor_mode = DM_CURSOR_OVERLAY_MODE;
> -                     return 0;
> -             }
> -
> -             /* Underlying plane has an active color pipeline - 
cursor would be
> transformed */ -              if (dm_plane_color_pipeline_active(state, 
plane, false))
> {
> -                     *cursor_mode = DM_CURSOR_OVERLAY_MODE;
> -                     return 0;
> -             }
> -
> -             dm_get_plane_scale(plane_state,
> -                                &underlying_scale_w, 
&underlying_scale_h);
> -             dm_get_plane_scale(cursor_state,
> -                                &cursor_scale_w, 
&cursor_scale_h);
> -
> -             /* Underlying plane has different scale - use overlay 
cursor */
> -             if (cursor_scale_w != underlying_scale_w &&
> -                 cursor_scale_h != underlying_scale_h) {
> -                     *cursor_mode = DM_CURSOR_OVERLAY_MODE;
> -                     return 0;
> -             }
> -
> -             /* If this plane covers the whole CRTC, no need to 
check planes
> underneath */ -               if (plane_state->crtc_x <= 0 && 
plane_state->crtc_y <= 0
> &&
> -                 plane_state->crtc_x + plane_state->crtc_w >=
> crtc_state->mode.hdisplay && -                    plane_state->crtc_y +
> plane_state->crtc_h >= crtc_state->mode.vdisplay) { -                 
entire_crtc_covered
> = true;
> -                     break;
> -             }
> -     }
> -
> -     /* If planes do not cover the entire CRTC, use overlay mode to 
enable
> -      * cursor over holes
> -      */
> -     if (entire_crtc_covered)
> -             *cursor_mode = DM_CURSOR_NATIVE_MODE;
> -     else
> -             *cursor_mode = DM_CURSOR_OVERLAY_MODE;
> -
> -     return 0;
> -}
> -
>  static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
>                                           struct 
drm_atomic_commit *state,
>                                           struct 
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 = to_dm_crtc_state(new_crtc_state);
> 
> -             ret = dm_crtc_get_cursor_mode(adev, state, 
dm_new_crtc_state,
> -                                           
&dm_new_crtc_state->cursor_mode);
> +             ret = amdgpu_dm_crtc_get_cursor_mode(adev, state, 
dm_new_crtc_state,
> +                                                  
&dm_new_crtc_state->cursor_mode);
>               if (ret) {
>                       drm_dbg(dev, "Failed to determine cursor 
mode: %pe\n", ERR_PTR(ret));
>                       goto fail;
> @@ -6754,8 +6346,8 @@ static int amdgpu_dm_atomic_check(struct drm_device
> *dev, }
> 
>               /* If HW can only do native cursor, check restrictions 
again */
> -             ret = dm_crtc_get_cursor_mode(adev, state, 
dm_new_crtc_state,
> -                                           
&required_cursor_mode);
> +             ret = amdgpu_dm_crtc_get_cursor_mode(adev, state, 
dm_new_crtc_state,
> +                                                  
&required_cursor_mode);
>               if (ret) {
>                       drm_dbg_driver(crtc->dev,
>                                      "[CRTC:%d:%s] Checking 
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_device
> *adev, struct dc_sink *sink);
> 
> +struct __drm_planes_state *amdgpu_dm_get_next_zpos(struct drm_atomic_commit
> *state, +                                                struct 
__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 =
> amdgpu_dm_get_next_zpos((__state), NULL); \ +      __i != NULL; __i =
> amdgpu_dm_get_next_zpos((__state), __i))              \ +             
for_each_if(((plane) =
> __i->ptr,                             \
> +                          (void)(plane) /* Only to avoid unused-
but-set-variable warning */,
> \ +                        (old_plane_state) = __i->old_state,                
\
> +                          (new_plane_state) = __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 
*old_plane_crtc,
> -                                 struct drm_crtc 
*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_state,
>                               const enum surface_pixel_format 
format,
>                               enum dc_color_space 
*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 
*out_plane_scale_h);
>  bool is_scaling_state_different(const struct dm_connector_state *dm_state,
>                               const struct dm_connector_state 
*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 included
> in + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
> 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 WITH
> 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 
*new_plane_state,
> +                           struct drm_framebuffer *fb)
> +{
> +     struct amdgpu_device *adev = drm_to_adev(new_acrtc->base.dev);
> +     struct amdgpu_framebuffer *afb = 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 
%dx%d\n",
> +                              new_plane_state->fb->width,
> +                              new_plane_state->fb->height);
> +             return -EINVAL;
> +     }
> +     if (new_plane_state->src_w != fb->width << 16 ||
> +         new_plane_state->src_h != fb->height << 16) {
> +             drm_dbg_atomic(adev_to_drm(adev), "Cropping not 
supported for cursor
> plane\n"); +          return -EINVAL;
> +     }
> +
> +     /* Pitch in pixels */
> +     pitch = fb->pitches[0] / fb->format->cpp[0];
> +
> +     if (fb->width != pitch) {
> +             drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d 
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 
%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 == AMDGPU_FAMILY_GC_12_0_0
> +                 || adev->family == AMDGPU_FAMILY_GC_13_0_1) {
> +#else
> +             if (adev->family == AMDGPU_FAMILY_GC_12_0_0) {
> +#endif
> +                     linear = AMDGPU_TILING_GET(afb->tiling_flags, 
GFX12_SWIZZLE_MODE) == 0;
> +             } else if (adev->family >= AMDGPU_FAMILY_AI) {
> +                     linear = AMDGPU_TILING_GET(afb->tiling_flags, 
SWIZZLE_MODE) == 0;
> +             } else {
> +                     linear = AMDGPU_TILING_GET(afb->tiling_flags, 
ARRAY_MODE) !=
> DC_ARRAY_2D_TILED_THIN1 && +                           
AMDGPU_TILING_GET(afb->tiling_flags,
> ARRAY_MODE) != DC_ARRAY_1D_TILED_THIN1 && +                           
> AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0;
> +             }
> +             if (!linear) {
> +                     drm_dbg_atomic(adev_to_drm(adev), "Cursor FB 
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 
*plane,
> +                                     struct drm_plane_state 
*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 = to_amdgpu_crtc(new_plane_crtc);
> +
> +     if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) {
> +             drm_dbg_atomic(new_plane_crtc->dev, "Cropping not 
supported for cursor
> plane\n"); +          return -EINVAL;
> +     }
> +
> +     if (new_plane_state->fb) {
> +             ret = dm_check_cursor_fb(new_acrtc, new_plane_state,
> +                                             
new_plane_state->fb);
> +             if (ret)
> +                     return ret;
> +     }
> +
> +     return 0;
> +}
> +
> +bool amdgpu_dm_should_update_native_cursor(struct drm_atomic_commit *state,
> +                                        struct drm_crtc 
*old_plane_crtc,
> +                                        struct drm_crtc 
*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 == NULL)
> +                     return true;
> +
> +             old_crtc_state = drm_atomic_get_old_crtc_state(
> +                     state, old_plane_crtc);
> +             dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
> +
> +             return dm_old_crtc_state->cursor_mode == 
DM_CURSOR_NATIVE_MODE;
> +     }
> +
> +     if (new_plane_crtc == NULL)
> +             return true;
> +
> +     new_crtc_state = drm_atomic_get_new_crtc_state(
> +             state, new_plane_crtc);
> +     dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
> +
> +     return dm_new_crtc_state->cursor_mode == 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 
*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 = plane_state->src_h >> 16;
> +             *src_h = plane_state->src_w >> 16;
> +             break;
> +     case DRM_MODE_ROTATE_0:
> +     case DRM_MODE_ROTATE_180:
> +     default:
> +             *src_w = plane_state->src_w >> 16;
> +             *src_h = 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, 
&plane_src_h);
> +     *out_plane_scale_w = plane_src_w ? plane_state->crtc_w * 1000 /
> plane_src_w : 0; +    *out_plane_scale_h = 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 != NULL) but still is
> + * inactive if every colorop in the chain is bypassed.  Only return
> + * true when at least one colorop has bypass == false, meaning the cursor
> + * 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 *state,
> +                                        struct drm_plane 
*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 = 
use_old ?
> old_colorop_state : new_colorop_state; +
> +             if (cstate->colorop->plane != 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 state
> + * failed.
> + */
> +int amdgpu_dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
> +                                struct drm_atomic_commit 
*state,
> +                                struct dm_crtc_state 
*dm_crtc_state,
> +                                enum amdgpu_dm_cursor_mode 
*cursor_mode)
> +{
> +     struct drm_plane_state *old_plane_state, *plane_state, 
*cursor_state;
> +     struct drm_crtc_state *crtc_state = &dm_crtc_state->base;
> +     struct drm_plane *plane;
> +     bool consider_mode_change = false;
> +     bool entire_crtc_covered = false;
> +     bool cursor_changed = 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) == IP_VERSION(4, 0, 1) ||
> +         amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
> +#if defined(CONFIG_DRM_AMD_DC_DCN6_0)
> +         amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
> +         amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(6, 0, 0)) {
> +#else
> +         amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1)) {
> +#endif
> +             *cursor_mode = DM_CURSOR_NATIVE_MODE;
> +             return 0;
> +     }
> +
> +     /* Init cursor_mode to be the same as current */
> +     *cursor_mode = dm_crtc_state->cursor_mode;
> +
> +     /*
> +      * Cursor mode can change if a plane's format changes, scale 
changes, is
> +      * enabled/disabled, z-order changes, or color management 
properties
> change. +      */
> +     for_each_oldnew_plane_in_state(state, plane, old_plane_state, 
plane_state,
> i) { +                int new_scale_w, new_scale_h, old_scale_w, 
old_scale_h;
> +
> +             /* Only care about planes on this CRTC */
> +             if ((drm_plane_mask(plane) & crtc_state->plane_mask) == 
0)
> +                     continue;
> +
> +             if (plane->type == DRM_PLANE_TYPE_CURSOR)
> +                     cursor_changed = true;
> +
> +             if (drm_atomic_plane_enabling(old_plane_state, 
plane_state) ||
> +                 drm_atomic_plane_disabling(old_plane_state, 
plane_state) ||
> +                 old_plane_state->fb->format != plane_state->fb-
>format) {
> +                     consider_mode_change = true;
> +                     break;
> +             }
> +
> +             dm_get_plane_scale(plane_state, &new_scale_w, 
&new_scale_h);
> +             dm_get_plane_scale(old_plane_state, &old_scale_w, 
&old_scale_h);
> +             if (new_scale_w != old_scale_w || new_scale_h != 
old_scale_h) {
> +                     consider_mode_change = true;
> +                     break;
> +             }
> +
> +             /*
> +              * A non-cursor plane moving or resizing (without a 
scale change)
> +              * changes how much of the CRTC it covers. This can 
create or
> +              * remove a hole under the cursor and thus flip the 
required
> +              * cursor mode (native vs overlay), so its destination 
rect must
> +              * be re-evaluated too.
> +              *
> +              * The cursor plane itself is deliberately excluded: the 
cursor
> +              * mode depends on the underlying planes' coverage, not 
on the
> +              * cursor's position (see the entire_crtc_covered logic 
below).
> +              * Triggering on cursor movement would force every 
legacy cursor
> +              * update off its fast path, and in a cursor-only commit 
- where
> +              * the underlying planes are not part of the state - the 
coverage
> +              * loop would see no covering plane and misevaluate the 
mode as
> +              * overlay, regressing flip-vs-cursor-legacy.
> +              */
> +             if (plane->type != DRM_PLANE_TYPE_CURSOR &&
> +                 (old_plane_state->crtc_x != plane_state->crtc_x ||
> +                  old_plane_state->crtc_y != plane_state->crtc_y ||
> +                  old_plane_state->crtc_w != plane_state->crtc_w ||
> +                  old_plane_state->crtc_h != plane_state->crtc_h)) {
> +                     consider_mode_change = true;
> +                     break;
> +             }
> +
> +             if (dm_plane_color_pipeline_active(state, plane, true) !
=
> +                 dm_plane_color_pipeline_active(state, plane, false)) 
{
> +                     consider_mode_change = 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, 
then
> +      * no need to set cursor mode. This avoids needlessly locking the 
cursor
> +      * state.
> +      */
> +     if (!cursor_changed &&
> +         !(drm_plane_mask(crtc_state->crtc->cursor) & crtc_state-
>plane_mask))
> { +           return 0;
> +     }
> +
> +     cursor_state = drm_atomic_get_plane_state(state,
> +                                               
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 
cursor
> +      * as per zpos definitions), check their scaling and format
> +      */
> +     for_each_oldnew_plane_in_descending_zpos(state, plane, 
old_plane_state,
> plane_state) { +
> +             /* Only care about non-cursor planes on this CRTC */
> +             if ((drm_plane_mask(plane) & crtc_state->plane_mask) == 
0 ||
> +                 plane->type == DRM_PLANE_TYPE_CURSOR)
> +                     continue;
> +
> +             /* Underlying plane is YUV format - use overlay cursor 
*/
> +             if (amdgpu_dm_plane_is_video_format(plane_state->fb-
>format->format)) {
> +                     *cursor_mode = DM_CURSOR_OVERLAY_MODE;
> +                     return 0;
> +             }
> +
> +             /* Underlying plane has an active color pipeline - 
cursor would be
> transformed */ +              if (dm_plane_color_pipeline_active(state, 
plane, false))
> {
> +                     *cursor_mode = DM_CURSOR_OVERLAY_MODE;
> +                     return 0;
> +             }
> +
> +             dm_get_plane_scale(plane_state,
> +                                &underlying_scale_w, 
&underlying_scale_h);
> +             dm_get_plane_scale(cursor_state,
> +                                &cursor_scale_w, 
&cursor_scale_h);
> +
> +             /* Underlying plane has different scale - use overlay 
cursor */
> +             if (cursor_scale_w != underlying_scale_w &&
> +                 cursor_scale_h != underlying_scale_h) {
> +                     *cursor_mode = DM_CURSOR_OVERLAY_MODE;
> +                     return 0;
> +             }
> +
> +             /* If this plane covers the whole CRTC, no need to check 
planes
> underneath */ +               if (plane_state->crtc_x <= 0 && 
plane_state->crtc_y <= 0
> &&
> +                 plane_state->crtc_x + plane_state->crtc_w >=
> crtc_state->mode.hdisplay && +                    plane_state->crtc_y +
> plane_state->crtc_h >= crtc_state->mode.vdisplay) { +                 
entire_crtc_covered
> = true;
> +                     break;
> +             }
> +     }
> +
> +     /* If planes do not cover the entire CRTC, use overlay mode to 
enable
> +      * cursor over holes
> +      */
> +     if (entire_crtc_covered)
> +             *cursor_mode = DM_CURSOR_NATIVE_MODE;
> +     else
> +             *cursor_mode = 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 included
> in + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
> 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 WITH
> 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 
*plane,
> +                                     struct drm_plane_state 
*new_plane_state,
> +                                     bool enable);
> +
> +bool amdgpu_dm_should_update_native_cursor(struct drm_atomic_commit *state,
> +                                        struct drm_crtc 
*old_plane_crtc,
> +                                        struct drm_crtc 
*new_plane_crtc,
> +                                        bool enable);
> +
> +int amdgpu_dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
> +                                struct drm_atomic_commit 
*state,
> +                                struct dm_crtc_state 
*dm_crtc_state,
> +                                enum amdgpu_dm_cursor_mode 
*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 
*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) +=
> amdgpu_dm_mst_types_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) +=
> amdgpu_dm_pp_smu_test.o
>  obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_test.o
>  obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_freesync_test.o
> +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_cursor_test.o
>  obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crtc_test.o
>  obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_services_test.o
>  obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += 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 cases
> 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, 
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 kunit
> *test) +{
> +     struct dm_crtc_state *dm_crtc_state;
> +     struct drm_atomic_commit *state;
> +     struct drm_crtc *crtc;
> +
> +     state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, state);
> +
> +     crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, crtc);
> +
> +     dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), 
GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
> +
> +     state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), 
GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
> +
> +     crtc->index = 0;
> +     dm_crtc_state->cursor_mode = DM_CURSOR_NATIVE_MODE;
> +     state->crtcs[0].old_state = &dm_crtc_state->base;
> +
> +     KUNIT_EXPECT_TRUE(test,
> +                       
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 kunit
> *test) +{
> +     struct dm_crtc_state *dm_crtc_state;
> +     struct drm_atomic_commit *state;
> +     struct drm_crtc *crtc;
> +
> +     state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, state);
> +
> +     crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, crtc);
> +
> +     dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), 
GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
> +
> +     state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), 
GFP_KERNEL);
> +     KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
> +
> +     crtc->index = 0;
> +     dm_crtc_state->cursor_mode = DM_CURSOR_OVERLAY_MODE;
> +     state->crtcs[0].new_state = &dm_crtc_state->base;
> +
> +     KUNIT_EXPECT_FALSE(test,
> +                        
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 rotate 0
> + * @test: The KUnit test context
> + */
> +static void dm_test_oriented_plane_size_rotate_0(struct kunit *test)
> +{
> +     struct drm_plane_state plane_state = { 0 };
> +     int src_w = 0;
> +     int src_h = 0;
> +
> +     plane_state.rotation = DRM_MODE_ROTATE_0;
> +     plane_state.src_w = 1920 << 16;
> +     plane_state.src_h = 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 rotate
> 90 + * @test: The KUnit test context
> + */
> +static void dm_test_oriented_plane_size_rotate_90(struct kunit *test)
> +{
> +     struct drm_plane_state plane_state = { 0 };
> +     int src_w = 0;
> +     int src_h = 0;
> +
> +     plane_state.rotation = DRM_MODE_ROTATE_90;
> +     plane_state.src_w = 1920 << 16;
> +     plane_state.src_h = 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 rotate
> 180 + * @test: The KUnit test context
> + */
> +static void dm_test_oriented_plane_size_rotate_180(struct kunit *test)
> +{
> +     struct drm_plane_state plane_state = { 0 };
> +     int src_w = 0;
> +     int src_h = 0;
> +
> +     plane_state.rotation = DRM_MODE_ROTATE_180;
> +     plane_state.src_w = 1920 << 16;
> +     plane_state.src_h = 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 rotate
> 270 + * @test: The KUnit test context
> + */
> +static void dm_test_oriented_plane_size_rotate_270(struct kunit *test)
> +{
> +     struct drm_plane_state plane_state = { 0 };
> +     int src_w = 0;
> +     int src_h = 0;
> +
> +     plane_state.rotation = DRM_MODE_ROTATE_270;
> +     plane_state.src_w = 1920 << 16;
> +     plane_state.src_h = 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 = { 0 };
> +     int scale_w = 0;
> +     int scale_h = 0;
> +
> +     plane_state.rotation = DRM_MODE_ROTATE_0;
> +     plane_state.src_w = 1920 << 16;
> +     plane_state.src_h = 1080 << 16;
> +     plane_state.crtc_w = 1920;
> +     plane_state.crtc_h = 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 rotate
> 90 identity + * @test: The KUnit test context
> + */
> +static void dm_test_get_plane_scale_rotate_90_identity(struct kunit *test)
> +{
> +     struct drm_plane_state plane_state = { 0 };
> +     int scale_w = 0;
> +     int scale_h = 0;
> +
> +     plane_state.rotation = DRM_MODE_ROTATE_90;
> +     plane_state.src_w = 1920 << 16;
> +     plane_state.src_h = 1080 << 16;
> +     plane_state.crtc_w = 1080;
> +     plane_state.crtc_h = 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 = { 0 };
> +     int scale_w = 0;
> +     int scale_h = 0;
> +
> +     plane_state.rotation = DRM_MODE_ROTATE_0;
> +     plane_state.src_w = 0;
> +     plane_state.src_h = 1080 << 16;
> +     plane_state.crtc_w = 100;
> +     plane_state.crtc_h = 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[] = {
> +     /* 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 = {
> +     .name = "amdgpu_dm_cursor",
> +     .test_cases = 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); }
> 
> -/**
> - * dm_test_should_update_native_cursor_without_crtc - Test NULL crtc cases
> 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, 
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 kunit
> *test) -{
> -     struct dm_crtc_state *dm_crtc_state;
> -     struct drm_atomic_commit *state;
> -     struct drm_crtc *crtc;
> -
> -     state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, state);
> -
> -     crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, crtc);
> -
> -     dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), 
GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
> -
> -     state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), 
GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
> -
> -     crtc->index = 0;
> -     dm_crtc_state->cursor_mode = DM_CURSOR_NATIVE_MODE;
> -     state->crtcs[0].old_state = &dm_crtc_state->base;
> -
> -     KUNIT_EXPECT_TRUE(test,
> -                       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 kunit
> *test) -{
> -     struct dm_crtc_state *dm_crtc_state;
> -     struct drm_atomic_commit *state;
> -     struct drm_crtc *crtc;
> -
> -     state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, state);
> -
> -     crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, crtc);
> -
> -     dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), 
GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state);
> -
> -     state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), 
GFP_KERNEL);
> -     KUNIT_ASSERT_NOT_NULL(test, state->crtcs);
> -
> -     crtc->index = 0;
> -     dm_crtc_state->cursor_mode = DM_CURSOR_OVERLAY_MODE;
> -     state->crtcs[0].new_state = &dm_crtc_state->base;
> -
> -     KUNIT_EXPECT_FALSE(test,
> -                        dm_should_update_native_cursor(state, 
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));
>  }
> 
> -/* Tests for dm_get_oriented_plane_size() */
> -
> -/**
> - * dm_test_oriented_plane_size_rotate_0 - Test Oriented plane size rotate 0
> - * @test: The KUnit test context
> - */
> -static void dm_test_oriented_plane_size_rotate_0(struct kunit *test)
> -{
> -     struct drm_plane_state plane_state = { 0 };
> -     int src_w = 0;
> -     int src_h = 0;
> -
> -     plane_state.rotation = DRM_MODE_ROTATE_0;
> -     plane_state.src_w = 1920 << 16;
> -     plane_state.src_h = 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 rotate
> 90 - * @test: The KUnit test context
> - */
> -static void dm_test_oriented_plane_size_rotate_90(struct kunit *test)
> -{
> -     struct drm_plane_state plane_state = { 0 };
> -     int src_w = 0;
> -     int src_h = 0;
> -
> -     plane_state.rotation = DRM_MODE_ROTATE_90;
> -     plane_state.src_w = 1920 << 16;
> -     plane_state.src_h = 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 rotate
> 180 - * @test: The KUnit test context
> - */
> -static void dm_test_oriented_plane_size_rotate_180(struct kunit *test)
> -{
> -     struct drm_plane_state plane_state = { 0 };
> -     int src_w = 0;
> -     int src_h = 0;
> -
> -     plane_state.rotation = DRM_MODE_ROTATE_180;
> -     plane_state.src_w = 1920 << 16;
> -     plane_state.src_h = 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 rotate
> 270 - * @test: The KUnit test context
> - */
> -static void dm_test_oriented_plane_size_rotate_270(struct kunit *test)
> -{
> -     struct drm_plane_state plane_state = { 0 };
> -     int src_w = 0;
> -     int src_h = 0;
> -
> -     plane_state.rotation = DRM_MODE_ROTATE_270;
> -     plane_state.src_w = 1920 << 16;
> -     plane_state.src_h = 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 = { 0 };
> -     int scale_w = 0;
> -     int scale_h = 0;
> -
> -     plane_state.rotation = DRM_MODE_ROTATE_0;
> -     plane_state.src_w = 1920 << 16;
> -     plane_state.src_h = 1080 << 16;
> -     plane_state.crtc_w = 1920;
> -     plane_state.crtc_h = 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 rotate
> 90 identity - * @test: The KUnit test context
> - */
> -static void dm_test_get_plane_scale_rotate_90_identity(struct kunit *test)
> -{
> -     struct drm_plane_state plane_state = { 0 };
> -     int scale_w = 0;
> -     int scale_h = 0;
> -
> -     plane_state.rotation = DRM_MODE_ROTATE_90;
> -     plane_state.src_w = 1920 << 16;
> -     plane_state.src_h = 1080 << 16;
> -     plane_state.crtc_w = 1080;
> -     plane_state.crtc_h = 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 = { 0 };
> -     int scale_w = 0;
> -     int scale_h = 0;
> -
> -     plane_state.rotation = DRM_MODE_ROTATE_0;
> -     plane_state.src_w = 0;
> -     plane_state.src_h = 1080 << 16;
> -     plane_state.crtc_w = 100;
> -     plane_state.crtc_h = 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() */
> 
>  /**
> @@ -1386,9 +1166,6 @@ static struct kunit_case amdgpu_dm_tests[] = {
>       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[] = {
>       KUNIT_CASE(dm_test_modereset_required_when_inactive_and_modeset),
>       
KUNIT_CASE(dm_test_modereset_not_required_when_active_and_modeset),
>       
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),




Reply via email to