diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5dcaf145f22ff..f68240d1d9ecf 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -513,6 +513,7 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
 
 	DRM_DEBUG_ATOMIC("Added [PLANE:%d:%s] %p state to %p\n",
 			 plane->base.id, plane->name, plane_state, state);
+	drm_trace(plane, add, plane_state);
 
 	if (plane_state->crtc) {
 		struct drm_crtc_state *crtc_state;
@@ -570,22 +571,27 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
 	if (crtc && !fb) {
 		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] CRTC set but no FB\n",
 				 plane->base.id, plane->name);
+		drm_trace_err(plane, check_fail_crtc_no_fb, new_plane_state);
 		return -EINVAL;
 	} else if (fb && !crtc) {
 		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] FB set but no CRTC\n",
 				 plane->base.id, plane->name);
+		drm_trace_err(plane, check_fail_fb_no_crtc, new_plane_state);
 		return -EINVAL;
 	}
 
 	/* if disabled, we don't care about the rest of the state: */
-	if (!crtc)
+	if (!crtc) {
+		drm_trace(plane, check_passed, new_plane_state);
 		return 0;
+	}
 
 	/* Check whether this plane is usable on this CRTC */
 	if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
 		DRM_DEBUG_ATOMIC("Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n",
 				 crtc->base.id, crtc->name,
 				 plane->base.id, plane->name);
+		drm_trace_err(plane, check_fail_crtc_impossible, new_plane_state);
 		return -EINVAL;
 	}
 
@@ -599,6 +605,7 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
 				 drm_get_format_name(fb->format->format,
 						     &format_name),
 				 fb->modifier);
+		drm_trace_err(plane, check_fail_format, new_plane_state);
 		return ret;
 	}
 
@@ -611,6 +618,7 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
 				 plane->base.id, plane->name,
 				 new_plane_state->crtc_w, new_plane_state->crtc_h,
 				 new_plane_state->crtc_x, new_plane_state->crtc_y);
+		drm_trace_err(plane, check_fail_crtc_coords, new_plane_state);
 		return -ERANGE;
 	}
 
@@ -634,6 +642,7 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
 				 new_plane_state->src_y >> 16,
 				 ((new_plane_state->src_y & 0xffff) * 15625) >> 10,
 				 fb->width, fb->height);
+		drm_trace_err(plane, check_fail_src_coords, new_plane_state);
 		return -ENOSPC;
 	}
 
@@ -651,6 +660,7 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
 			DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid damage clip %d %d %d %d\n",
 					 plane->base.id, plane->name, clips->x1,
 					 clips->y1, clips->x2, clips->y2);
+			drm_trace_err(plane, check_fail_damage_clip, new_plane_state);
 			return -EINVAL;
 		}
 		clips++;
@@ -660,9 +670,12 @@ static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state,
 	if (plane_switching_crtc(old_plane_state, new_plane_state)) {
 		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n",
 				 plane->base.id, plane->name);
+		drm_trace_err(plane, check_fail_switch_old, old_plane_state);
+		drm_trace_err(plane, check_fail_switch_new, new_plane_state);
 		return -EINVAL;
 	}
 
+	drm_trace(plane, check_passed, new_plane_state);
 	return 0;
 }
 
@@ -1176,6 +1189,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 		if (ret) {
 			DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic core check failed\n",
 					 plane->base.id, plane->name);
+			drm_trace_err(plane, check_failed, new_plane_state);
 			return ret;
 		}
 	}
diff --git a/drivers/gpu/drm/drm_trace.h b/drivers/gpu/drm/drm_trace.h
index c610e8d8c71ce..7708810bbd660 100644
--- a/drivers/gpu/drm/drm_trace.h
+++ b/drivers/gpu/drm/drm_trace.h
@@ -6,6 +6,9 @@
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_encoder.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_rect.h>
 
 #include <linux/kref.h>
 #include <linux/stringify.h>
@@ -83,6 +86,12 @@ enum drm_trace_event_class {
 	 * state through the atomic core and helpers.
 	 */
 	drm_trace_class_connector	= BIT(4),
+
+	/**
+	 * @drm_trace_class_plane: This class is used to track plane state
+	 * through the atomic core and helpers.
+	 */
+	drm_trace_class_plane		= BIT(5),
 };
 
 /**
@@ -444,6 +453,140 @@ DEFINE_EVENT(class_drm_connector,
 	TP_ARGS(event_class, state)
 );
 
+DECLARE_EVENT_CLASS(class_drm_plane,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state),
+	TP_STRUCT__entry(
+		__field(unsigned int, event_class)
+		__field(uint32_t, plane_id)
+		__field(const struct drm_plane_state *, plane_state)
+		__field(const struct drm_atomic_state *, state)
+		__field(const struct drm_crtc_commit *, commit)
+		__field(uint32_t, crtc_id)
+		__field(uint32_t, fb_id)
+		__field(uint32_t, fb_format)
+		__field(uint8_t, fb_planes)
+		__field(uint64_t, fb_modifier)
+		__field(const struct dma_fence *, fence)
+		__array(u8, crtc_coords, sizeof(struct drm_rect))
+		__array(u8, src_coords, sizeof(struct drm_rect))
+		__field(u32, alpha)
+		__field(uint32_t, pixel_blend_mode)
+		__field(unsigned int, rotation)
+		__field(unsigned int, zpos)
+		__field(unsigned int, normalized_zpos)
+		__field(enum drm_color_encoding, color_encoding)
+		__field(enum drm_color_range, color_range)
+		__field(bool, visible)
+		__array(u8, src, sizeof(struct drm_rect))
+		__array(u8, dst, sizeof(struct drm_rect))
+	),
+	TP_fast_assign(
+		__entry->event_class = event_class;
+		__entry->plane_id = state->plane->base.id;
+		__entry->plane_state = state;
+		__entry->state = state->state;
+		__entry->commit = state->commit;
+		__entry->crtc_id = state->crtc ? state->crtc->base.id : 0;
+		__entry->fb_id = state->fb ? state->fb->base.id : 0;
+		__entry->fb_format = state->fb ? state->fb->format->format :
+						 'E' << 24 | 'O' << 16 |
+						 'N' << 8 | 'N';
+		__entry->fb_planes = state->fb ? state->fb->format->num_planes :
+					0;
+		__entry->fb_modifier = state->fb ? state->fb->modifier : 0;
+		__entry->fence = state->fence;
+		((struct drm_rect *)__entry->crtc_coords)->x1 = state->crtc_x;
+		((struct drm_rect *)__entry->crtc_coords)->y1 = state->crtc_y;
+		((struct drm_rect *)__entry->crtc_coords)->x1 = state->crtc_w;
+		((struct drm_rect *)__entry->crtc_coords)->y2 = state->crtc_h;
+		((struct drm_rect *)__entry->src_coords)->x1 = state->src_x;
+		((struct drm_rect *)__entry->src_coords)->y1 = state->src_y;
+		((struct drm_rect *)__entry->src_coords)->x1 = state->src_w;
+		((struct drm_rect *)__entry->src_coords)->y2 = state->src_h;
+		__entry->alpha = state->alpha;
+		__entry->pixel_blend_mode = state->pixel_blend_mode;
+		__entry->rotation = state->rotation;
+		__entry->zpos = state->zpos;
+		__entry->normalized_zpos = state->normalized_zpos;
+		__entry->color_encoding = state->color_encoding;
+		__entry->color_range = state->color_range;
+		__entry->visible = state->visible;
+		memcpy(__entry->src, &state->src, sizeof(__entry->src));
+		memcpy(__entry->dst, &state->dst, sizeof(__entry->dst));
+	),
+	TP_printk("plane_id=%u plane_state=%pK state=%pK commit=%pK crtc_id=%u "
+		  "fb(id=%u fmt=%c%c%c%c planes=%u mod=%llu) fence=%pK crtc("
+		  DRM_RECT_FMT") src("DRM_RECT_FP_FMT") alpha=%u "
+		  "pixel_blend_mode=%u rotation=%u zpos=%u "
+		  "normalized_zpos=%u color_encoding=%d color_range=%d "
+		  "visible=%d src_rect("DRM_RECT_FP_FMT") dst_rect("
+		  DRM_RECT_FMT")",
+		  __entry->plane_id, __entry->plane_state, __entry->state,
+		  __entry->commit, __entry->crtc_id, __entry->fb_id,
+		  __entry->fb_format & 0xff,
+		  (__entry->fb_format >> 8) & 0xff,
+		  (__entry->fb_format >> 16) & 0xff,
+		  (__entry->fb_format >> 24) & 0x7f, __entry->fb_planes,
+		  __entry->fb_modifier, __entry->fence,
+		  DRM_RECT_ARG((const struct drm_rect *)__entry->crtc_coords),
+		  DRM_RECT_FP_ARG((const struct drm_rect *)__entry->src_coords),
+		  __entry->alpha, __entry->pixel_blend_mode, __entry->rotation,
+		  __entry->zpos, __entry->normalized_zpos,
+		  __entry->color_encoding, __entry->color_range,
+		  __entry->visible,
+		  DRM_RECT_FP_ARG((const struct drm_rect *)__entry->src),
+		  DRM_RECT_ARG((const struct drm_rect *)__entry->dst))
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_add,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_crtc_no_fb,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_fb_no_crtc,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_crtc_impossible,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_format,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_crtc_coords,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_src_coords,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_damage_clip,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_switch_old,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_fail_switch_new,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_failed,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+DEFINE_EVENT(class_drm_plane, drm_plane_check_passed,
+	TP_PROTO(unsigned int event_class, const struct drm_plane_state *state),
+	TP_ARGS(event_class, state)
+);
+
 #endif /* _DRM_TRACE_H_ */
 
 /* This part must be outside protection */
