diff mbox series

drm/amdgpu: Add dcn30 drm_panic support

Message ID 20241004090850.460668-1-jfalempe@redhat.com (mailing list archive)
State New, archived
Headers show
Series drm/amdgpu: Add dcn30 drm_panic support | expand

Commit Message

Jocelyn Falempe Oct. 4, 2024, 9:07 a.m. UTC
Add support for the drm_panic module, which displays a pretty user
friendly message on the screen when a Linux kernel panic occurs.

It should work on all readeon using amdgpu_dm_plane.c, when the
framebuffer is linear (like when in a VT). For tiled framebuffer, it
will only work on radeon with dcn30. It should be easy to add support
for dcn20 or dcn31, but I can't test it.
I've tested it on a Radeon W6400 pro.

Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 137 +++++++++++++++++-
 .../amd/display/dc/hubp/dcn30/dcn30_hubp.c    |  17 +++
 .../amd/display/dc/hubp/dcn30/dcn30_hubp.h    |   2 +
 drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h  |   1 +
 4 files changed, 155 insertions(+), 2 deletions(-)


base-commit: a5c2320151ff7cdf9ec50630d638a417ff927e31

Comments

Alex Deucher Oct. 22, 2024, 8:10 p.m. UTC | #1
On Fri, Oct 4, 2024 at 5:09 AM Jocelyn Falempe <jfalempe@redhat.com> wrote:
>
> Add support for the drm_panic module, which displays a pretty user
> friendly message on the screen when a Linux kernel panic occurs.
>
> It should work on all readeon using amdgpu_dm_plane.c, when the

radeon

> framebuffer is linear (like when in a VT). For tiled framebuffer, it
> will only work on radeon with dcn30. It should be easy to add support
> for dcn20 or dcn31, but I can't test it.
> I've tested it on a Radeon W6400 pro.

Looks good to me.  @Wentland, Harry, @Siqueira, Rodrigo, etc, does
this look ok to you guys?  If so, can you pick it up and look at
adding the callbacks for other DCN versions?

Thanks,

Alex

>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 137 +++++++++++++++++-
>  .../amd/display/dc/hubp/dcn30/dcn30_hubp.c    |  17 +++
>  .../amd/display/dc/hubp/dcn30/dcn30_hubp.h    |   2 +
>  drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h  |   1 +
>  4 files changed, 155 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> index 25f63b2e7a8e2..a62b197ab6833 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> @@ -26,7 +26,9 @@
>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_blend.h>
> +#include "drm/drm_framebuffer.h"
>  #include <drm/drm_gem_atomic_helper.h>
> +#include <drm/drm_panic.h>
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_gem_framebuffer_helper.h>
>  #include <drm/drm_fourcc.h>
> @@ -36,6 +38,7 @@
>  #include "amdgpu_display.h"
>  #include "amdgpu_dm_trace.h"
>  #include "amdgpu_dm_plane.h"
> +#include "bif/bif_4_1_d.h"
>  #include "gc/gc_11_0_0_offset.h"
>  #include "gc/gc_11_0_0_sh_mask.h"
>
> @@ -1420,6 +1423,125 @@ static void amdgpu_dm_plane_atomic_async_update(struct drm_plane *plane,
>         amdgpu_dm_plane_handle_cursor_update(plane, old_state);
>  }
>
> +/* panic_bo is set in amdgpu_dm_plane_get_scanout_buffer() and only used in amdgpu_dm_set_pixel()
> + * they are called from the panic handler, and no race condition can occurs.
> + */
> +static struct amdgpu_bo *panic_abo;
> +
> +/* Use the indirect MMIO to write each pixel to the GPU VRAM,
> + * This is a simplified version of amdgpu_device_mm_access()
> + */
> +static void amdgpu_dm_set_pixel(struct drm_scanout_buffer *sb,
> +                               unsigned int x,
> +                               unsigned int y,
> +                               u32 color)
> +{
> +       struct amdgpu_res_cursor cursor;
> +       unsigned long offset;
> +       struct amdgpu_bo *abo = panic_abo;
> +       struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
> +       uint32_t tmp;
> +
> +       offset = x * 4 + y * sb->pitch[0];
> +       amdgpu_res_first(abo->tbo.resource, offset, 4, &cursor);
> +
> +       tmp = cursor.start >> 31;
> +       WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t) cursor.start) | 0x80000000);
> +       if (tmp != 0xffffffff)
> +               WREG32_NO_KIQ(mmMM_INDEX_HI, tmp);
> +       WREG32_NO_KIQ(mmMM_DATA, color);
> +}
> +
> +static int amdgpu_dm_plane_disable_tiling(struct dc_plane_state *dc_plane_state)
> +{
> +       struct dc_state *dc_state;
> +       int i;
> +
> +       if (!dc_plane_state)
> +               return -EINVAL;
> +
> +       dc_state = dc_plane_state->ctx->dc->current_state;
> +       if (!dc_state)
> +               return -EINVAL;
> +
> +       for (i = 0; i < dc_plane_state->ctx->dc->res_pool->pipe_count; i++) {
> +               struct pipe_ctx *pipe_ctx = &dc_state->res_ctx.pipe_ctx[i];
> +               struct hubp *hubp;
> +
> +               if (!pipe_ctx)
> +                       continue;
> +
> +               hubp = pipe_ctx->plane_res.hubp;
> +               if (!hubp)
> +                       continue;
> +
> +               if (!hubp->funcs->hubp_clear_tiling)
> +                       return -EINVAL;
> +
> +               hubp->funcs->hubp_clear_tiling(hubp);
> +               hubp->funcs->hubp_program_surface_flip_and_addr(hubp,
> +                                                               &dc_plane_state->address,
> +                                                               dc_plane_state->flip_immediate);
> +       }
> +       return 0;
> +}
> +
> +static int amdgpu_dm_plane_get_scanout_buffer(struct drm_plane *plane,
> +                                             struct drm_scanout_buffer *sb)
> +{
> +       struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane->state);
> +       struct amdgpu_bo *abo;
> +       struct drm_framebuffer *fb = plane->state->fb;
> +
> +       if (!fb)
> +               return -EINVAL;
> +
> +       DRM_DEBUG_KMS("Framebuffer %dx%d %p4cc\n", fb->width, fb->height, &fb->format->format);
> +
> +       abo = gem_to_amdgpu_bo(fb->obj[0]);
> +       if (!abo)
> +               return -EINVAL;
> +
> +       /* disable tiling */
> +       if (fb->modifier && amdgpu_dm_plane_disable_tiling(dm_plane_state->dc_state))
> +               return -EINVAL;
> +
> +       sb->width = fb->width;
> +       sb->height = fb->height;
> +       /* Use the generic linear format, because we just disabled tiling */
> +       sb->format = drm_format_info(fb->format->format);
> +       if (!sb->format)
> +               return -EINVAL;
> +
> +       sb->pitch[0] = fb->pitches[0];
> +
> +       if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) {
> +               if (abo->tbo.resource->mem_type != TTM_PL_VRAM) {
> +                       DRM_WARN("amdgpu panic, framebuffer not in VRAM\n");
> +                       return -EINVAL;
> +               }
> +               /* Only handle 32bits format, to simplify mmio access */
> +               if (fb->format->cpp[0] != 4) {
> +                       DRM_WARN("amdgpu panic, pixel format is not 32bits\n");
> +                       return -EINVAL;
> +               }
> +               sb->set_pixel = amdgpu_dm_set_pixel;
> +               panic_abo = abo;
> +               return 0;
> +       }
> +       if (!abo->kmap.virtual &&
> +           ttm_bo_kmap(&abo->tbo, 0, PFN_UP(abo->tbo.base.size), &abo->kmap)) {
> +               DRM_WARN("amdgpu bo map failed, panic won't be displayed\n");
> +               return -ENOMEM;
> +       }
> +       if (abo->kmap.bo_kmap_type & TTM_BO_MAP_IOMEM_MASK)
> +               iosys_map_set_vaddr_iomem(&sb->map[0], abo->kmap.virtual);
> +       else
> +               iosys_map_set_vaddr(&sb->map[0], abo->kmap.virtual);
> +
> +       return 0;
> +}
> +
>  static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
>         .prepare_fb = amdgpu_dm_plane_helper_prepare_fb,
>         .cleanup_fb = amdgpu_dm_plane_helper_cleanup_fb,
> @@ -1428,6 +1550,15 @@ static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
>         .atomic_async_update = amdgpu_dm_plane_atomic_async_update
>  };
>
> +static const struct drm_plane_helper_funcs dm_primary_plane_helper_funcs = {
> +       .prepare_fb = amdgpu_dm_plane_helper_prepare_fb,
> +       .cleanup_fb = amdgpu_dm_plane_helper_cleanup_fb,
> +       .atomic_check = amdgpu_dm_plane_atomic_check,
> +       .atomic_async_check = amdgpu_dm_plane_atomic_async_check,
> +       .atomic_async_update = amdgpu_dm_plane_atomic_async_update,
> +       .get_scanout_buffer = amdgpu_dm_plane_get_scanout_buffer,
> +};
> +
>  static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane)
>  {
>         struct dm_plane_state *amdgpu_state = NULL;
> @@ -1854,7 +1985,10 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
>             plane->type != DRM_PLANE_TYPE_CURSOR)
>                 drm_plane_enable_fb_damage_clips(plane);
>
> -       drm_plane_helper_add(plane, &dm_plane_helper_funcs);
> +       if (plane->type == DRM_PLANE_TYPE_PRIMARY)
> +               drm_plane_helper_add(plane, &dm_primary_plane_helper_funcs);
> +       else
> +               drm_plane_helper_add(plane, &dm_plane_helper_funcs);
>
>  #ifdef AMD_PRIVATE_COLOR
>         dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
> @@ -1876,4 +2010,3 @@ bool amdgpu_dm_plane_is_video_format(uint32_t format)
>
>         return false;
>  }
> -
> diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
> index 60a64d2903527..3b16c3cda2c3e 100644
> --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
> +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
> @@ -334,6 +334,22 @@ void hubp3_program_tiling(
>
>  }
>
> +void hubp3_clear_tiling(struct hubp *hubp)
> +{
> +       struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
> +
> +       REG_UPDATE(DCHUBP_REQ_SIZE_CONFIG, SWATH_HEIGHT, 0);
> +       REG_UPDATE(DCSURF_TILING_CONFIG, SW_MODE, DC_SW_LINEAR);
> +
> +       REG_UPDATE_6(DCSURF_SURFACE_CONTROL,
> +               PRIMARY_SURFACE_DCC_EN, 0,
> +               PRIMARY_SURFACE_DCC_IND_BLK, 0,
> +               PRIMARY_SURFACE_DCC_IND_BLK_C, 0,
> +               SECONDARY_SURFACE_DCC_EN, 0,
> +               SECONDARY_SURFACE_DCC_IND_BLK, 0,
> +               SECONDARY_SURFACE_DCC_IND_BLK_C, 0);
> +}
> +
>  void hubp3_dcc_control(struct hubp *hubp, bool enable,
>                 enum hubp_ind_block_size blk_size)
>  {
> @@ -512,6 +528,7 @@ static struct hubp_funcs dcn30_hubp_funcs = {
>         .hubp_in_blank = hubp1_in_blank,
>         .hubp_soft_reset = hubp1_soft_reset,
>         .hubp_set_flip_int = hubp1_set_flip_int,
> +       .hubp_clear_tiling = hubp3_clear_tiling,
>  };
>
>  bool hubp3_construct(
> diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
> index b010531a7fe88..cfb01bf340a1a 100644
> --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
> +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
> @@ -297,6 +297,8 @@ void hubp3_read_state(struct hubp *hubp);
>
>  void hubp3_init(struct hubp *hubp);
>
> +void hubp3_clear_tiling(struct hubp *hubp);
> +
>  #endif /* __DC_HUBP_DCN30_H__ */
>
>
> diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
> index 16580d6242789..d0878fc0cc948 100644
> --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
> +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
> @@ -275,6 +275,7 @@ struct hubp_funcs {
>                         enum hubp_3dlut_fl_crossbar_bit_slice bit_slice_cb_b,
>                         enum hubp_3dlut_fl_crossbar_bit_slice bit_slice_cr_r);
>         int (*hubp_get_3dlut_fl_done)(struct hubp *hubp);
> +       void (*hubp_clear_tiling)(struct hubp *hubp);
>  };
>
>  #endif
>
> base-commit: a5c2320151ff7cdf9ec50630d638a417ff927e31
> --
> 2.46.1
>
Jocelyn Falempe Oct. 22, 2024, 11:09 p.m. UTC | #2
On 22/10/2024 22:10, Alex Deucher wrote:
> On Fri, Oct 4, 2024 at 5:09 AM Jocelyn Falempe <jfalempe@redhat.com> wrote:
>>
>> Add support for the drm_panic module, which displays a pretty user
>> friendly message on the screen when a Linux kernel panic occurs.
>>
>> It should work on all readeon using amdgpu_dm_plane.c, when the
> 
> radeon
> 
>> framebuffer is linear (like when in a VT). For tiled framebuffer, it
>> will only work on radeon with dcn30. It should be easy to add support
>> for dcn20 or dcn31, but I can't test it.
>> I've tested it on a Radeon W6400 pro.
> 
> Looks good to me.  @Wentland, Harry, @Siqueira, Rodrigo, etc, does
> this look ok to you guys?  If so, can you pick it up and look at
> adding the callbacks for other DCN versions?

I've sent a v2 of this patch, and I'm preparing a v3, which adds dcn31, 
dnc32 and dnc35 support. I've tested it successfully on a 7900XTX and 
radeon RX 5700.
One thing that doesn't work yet, is on a laptop's panel.
Thomas Weißschuh tested it on a laptop with an integrated radeon 780M, 
and the screen is not updated.
It has something to do with PSR, but I didn't find a way to workaround this.
So basically calling hubp_program_surface_flip_and_addr() is not enough 
to get the new framebuffer content to the internal panel, but it works 
on an external display on his laptop.
I tried to call dc_set_psr_allow_active(dc, false), but it has no effect.

Anyway I will send the v3 tomorrow.

Best regards,
diff mbox series

Patch

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 25f63b2e7a8e2..a62b197ab6833 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -26,7 +26,9 @@ 
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_blend.h>
+#include "drm/drm_framebuffer.h"
 #include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_panic.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_fourcc.h>
@@ -36,6 +38,7 @@ 
 #include "amdgpu_display.h"
 #include "amdgpu_dm_trace.h"
 #include "amdgpu_dm_plane.h"
+#include "bif/bif_4_1_d.h"
 #include "gc/gc_11_0_0_offset.h"
 #include "gc/gc_11_0_0_sh_mask.h"
 
@@ -1420,6 +1423,125 @@  static void amdgpu_dm_plane_atomic_async_update(struct drm_plane *plane,
 	amdgpu_dm_plane_handle_cursor_update(plane, old_state);
 }
 
+/* panic_bo is set in amdgpu_dm_plane_get_scanout_buffer() and only used in amdgpu_dm_set_pixel()
+ * they are called from the panic handler, and no race condition can occurs.
+ */
+static struct amdgpu_bo *panic_abo;
+
+/* Use the indirect MMIO to write each pixel to the GPU VRAM,
+ * This is a simplified version of amdgpu_device_mm_access()
+ */
+static void amdgpu_dm_set_pixel(struct drm_scanout_buffer *sb,
+				unsigned int x,
+				unsigned int y,
+				u32 color)
+{
+	struct amdgpu_res_cursor cursor;
+	unsigned long offset;
+	struct amdgpu_bo *abo = panic_abo;
+	struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
+	uint32_t tmp;
+
+	offset = x * 4 + y * sb->pitch[0];
+	amdgpu_res_first(abo->tbo.resource, offset, 4, &cursor);
+
+	tmp = cursor.start >> 31;
+	WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t) cursor.start) | 0x80000000);
+	if (tmp != 0xffffffff)
+		WREG32_NO_KIQ(mmMM_INDEX_HI, tmp);
+	WREG32_NO_KIQ(mmMM_DATA, color);
+}
+
+static int amdgpu_dm_plane_disable_tiling(struct dc_plane_state *dc_plane_state)
+{
+	struct dc_state *dc_state;
+	int i;
+
+	if (!dc_plane_state)
+		return -EINVAL;
+
+	dc_state = dc_plane_state->ctx->dc->current_state;
+	if (!dc_state)
+		return -EINVAL;
+
+	for (i = 0; i < dc_plane_state->ctx->dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe_ctx = &dc_state->res_ctx.pipe_ctx[i];
+		struct hubp *hubp;
+
+		if (!pipe_ctx)
+			continue;
+
+		hubp = pipe_ctx->plane_res.hubp;
+		if (!hubp)
+			continue;
+
+		if (!hubp->funcs->hubp_clear_tiling)
+			return -EINVAL;
+
+		hubp->funcs->hubp_clear_tiling(hubp);
+		hubp->funcs->hubp_program_surface_flip_and_addr(hubp,
+								&dc_plane_state->address,
+								dc_plane_state->flip_immediate);
+	}
+	return 0;
+}
+
+static int amdgpu_dm_plane_get_scanout_buffer(struct drm_plane *plane,
+					      struct drm_scanout_buffer *sb)
+{
+	struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane->state);
+	struct amdgpu_bo *abo;
+	struct drm_framebuffer *fb = plane->state->fb;
+
+	if (!fb)
+		return -EINVAL;
+
+	DRM_DEBUG_KMS("Framebuffer %dx%d %p4cc\n", fb->width, fb->height, &fb->format->format);
+
+	abo = gem_to_amdgpu_bo(fb->obj[0]);
+	if (!abo)
+		return -EINVAL;
+
+	/* disable tiling */
+	if (fb->modifier && amdgpu_dm_plane_disable_tiling(dm_plane_state->dc_state))
+		return -EINVAL;
+
+	sb->width = fb->width;
+	sb->height = fb->height;
+	/* Use the generic linear format, because we just disabled tiling */
+	sb->format = drm_format_info(fb->format->format);
+	if (!sb->format)
+		return -EINVAL;
+
+	sb->pitch[0] = fb->pitches[0];
+
+	if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) {
+		if (abo->tbo.resource->mem_type != TTM_PL_VRAM) {
+			DRM_WARN("amdgpu panic, framebuffer not in VRAM\n");
+			return -EINVAL;
+		}
+		/* Only handle 32bits format, to simplify mmio access */
+		if (fb->format->cpp[0] != 4) {
+			DRM_WARN("amdgpu panic, pixel format is not 32bits\n");
+			return -EINVAL;
+		}
+		sb->set_pixel = amdgpu_dm_set_pixel;
+		panic_abo = abo;
+		return 0;
+	}
+	if (!abo->kmap.virtual &&
+	    ttm_bo_kmap(&abo->tbo, 0, PFN_UP(abo->tbo.base.size), &abo->kmap)) {
+		DRM_WARN("amdgpu bo map failed, panic won't be displayed\n");
+		return -ENOMEM;
+	}
+	if (abo->kmap.bo_kmap_type & TTM_BO_MAP_IOMEM_MASK)
+		iosys_map_set_vaddr_iomem(&sb->map[0], abo->kmap.virtual);
+	else
+		iosys_map_set_vaddr(&sb->map[0], abo->kmap.virtual);
+
+	return 0;
+}
+
 static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
 	.prepare_fb = amdgpu_dm_plane_helper_prepare_fb,
 	.cleanup_fb = amdgpu_dm_plane_helper_cleanup_fb,
@@ -1428,6 +1550,15 @@  static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
 	.atomic_async_update = amdgpu_dm_plane_atomic_async_update
 };
 
+static const struct drm_plane_helper_funcs dm_primary_plane_helper_funcs = {
+	.prepare_fb = amdgpu_dm_plane_helper_prepare_fb,
+	.cleanup_fb = amdgpu_dm_plane_helper_cleanup_fb,
+	.atomic_check = amdgpu_dm_plane_atomic_check,
+	.atomic_async_check = amdgpu_dm_plane_atomic_async_check,
+	.atomic_async_update = amdgpu_dm_plane_atomic_async_update,
+	.get_scanout_buffer = amdgpu_dm_plane_get_scanout_buffer,
+};
+
 static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane)
 {
 	struct dm_plane_state *amdgpu_state = NULL;
@@ -1854,7 +1985,10 @@  int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
 	    plane->type != DRM_PLANE_TYPE_CURSOR)
 		drm_plane_enable_fb_damage_clips(plane);
 
-	drm_plane_helper_add(plane, &dm_plane_helper_funcs);
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+		drm_plane_helper_add(plane, &dm_primary_plane_helper_funcs);
+	else
+		drm_plane_helper_add(plane, &dm_plane_helper_funcs);
 
 #ifdef AMD_PRIVATE_COLOR
 	dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
@@ -1876,4 +2010,3 @@  bool amdgpu_dm_plane_is_video_format(uint32_t format)
 
 	return false;
 }
-
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
index 60a64d2903527..3b16c3cda2c3e 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
@@ -334,6 +334,22 @@  void hubp3_program_tiling(
 
 }
 
+void hubp3_clear_tiling(struct hubp *hubp)
+{
+	struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+
+	REG_UPDATE(DCHUBP_REQ_SIZE_CONFIG, SWATH_HEIGHT, 0);
+	REG_UPDATE(DCSURF_TILING_CONFIG, SW_MODE, DC_SW_LINEAR);
+
+	REG_UPDATE_6(DCSURF_SURFACE_CONTROL,
+		PRIMARY_SURFACE_DCC_EN, 0,
+		PRIMARY_SURFACE_DCC_IND_BLK, 0,
+		PRIMARY_SURFACE_DCC_IND_BLK_C, 0,
+		SECONDARY_SURFACE_DCC_EN, 0,
+		SECONDARY_SURFACE_DCC_IND_BLK, 0,
+		SECONDARY_SURFACE_DCC_IND_BLK_C, 0);
+}
+
 void hubp3_dcc_control(struct hubp *hubp, bool enable,
 		enum hubp_ind_block_size blk_size)
 {
@@ -512,6 +528,7 @@  static struct hubp_funcs dcn30_hubp_funcs = {
 	.hubp_in_blank = hubp1_in_blank,
 	.hubp_soft_reset = hubp1_soft_reset,
 	.hubp_set_flip_int = hubp1_set_flip_int,
+	.hubp_clear_tiling = hubp3_clear_tiling,
 };
 
 bool hubp3_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
index b010531a7fe88..cfb01bf340a1a 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
@@ -297,6 +297,8 @@  void hubp3_read_state(struct hubp *hubp);
 
 void hubp3_init(struct hubp *hubp);
 
+void hubp3_clear_tiling(struct hubp *hubp);
+
 #endif /* __DC_HUBP_DCN30_H__ */
 
 
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
index 16580d6242789..d0878fc0cc948 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
@@ -275,6 +275,7 @@  struct hubp_funcs {
 			enum hubp_3dlut_fl_crossbar_bit_slice bit_slice_cb_b,
 			enum hubp_3dlut_fl_crossbar_bit_slice bit_slice_cr_r);
 	int (*hubp_get_3dlut_fl_done)(struct hubp *hubp);
+	void (*hubp_clear_tiling)(struct hubp *hubp);
 };
 
 #endif