]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Add Visual Confirm Support for Testing
authorMuaaz Nisar <muanisar@amd.com>
Thu, 18 Dec 2025 21:03:44 +0000 (16:03 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 23 Feb 2026 19:39:31 +0000 (14:39 -0500)
[WHY+HOW]
Adding visual confirm to visually track changes in refresh rate.

Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Muaaz Nisar <muanisar@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h

index 76b5be1371edfc3b82c8542ee789b5dba2972935..615bf2a013894a0a9e228e502da10f3d63a13b1a 100644 (file)
@@ -442,75 +442,6 @@ static bool set_long_vtotal(struct dc *dc, struct dc_stream_state *stream, struc
        return false;
 }
 
-/**
- *  dc_stream_adjust_vmin_vmax - look up pipe context & update parts of DRR
- *  @dc:     dc reference
- *  @stream: Initial dc stream state
- *  @adjust: Updated parameters for vertical_total_min and vertical_total_max
- *
- *  Looks up the pipe context of dc_stream_state and updates the
- *  vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh
- *  Rate, which is a power-saving feature that targets reducing panel
- *  refresh rate while the screen is static
- *
- *  Return: %true if the pipe context is found and adjusted;
- *          %false if the pipe context is not found.
- */
-bool dc_stream_adjust_vmin_vmax(struct dc *dc,
-               struct dc_stream_state *stream,
-               struct dc_crtc_timing_adjust *adjust)
-{
-       int i;
-
-       /*
-        * Don't adjust DRR while there's bandwidth optimizations pending to
-        * avoid conflicting with firmware updates.
-        */
-       if (dc->ctx->dce_version > DCE_VERSION_MAX) {
-               if (dc->optimized_required &&
-                       (stream->adjust.v_total_max != adjust->v_total_max ||
-                       stream->adjust.v_total_min != adjust->v_total_min)) {
-                       stream->adjust.timing_adjust_pending = true;
-                       return false;
-               }
-       }
-
-       dc_exit_ips_for_hw_access(dc);
-
-       stream->adjust.v_total_max = adjust->v_total_max;
-       stream->adjust.v_total_mid = adjust->v_total_mid;
-       stream->adjust.v_total_mid_frame_num = adjust->v_total_mid_frame_num;
-       stream->adjust.v_total_min = adjust->v_total_min;
-       stream->adjust.allow_otg_v_count_halt = adjust->allow_otg_v_count_halt;
-
-       if (dc->caps.max_v_total != 0 &&
-               (adjust->v_total_max > dc->caps.max_v_total || adjust->v_total_min > dc->caps.max_v_total)) {
-               stream->adjust.timing_adjust_pending = false;
-               if (adjust->allow_otg_v_count_halt)
-                       return set_long_vtotal(dc, stream, adjust);
-               else
-                       return false;
-       }
-
-       for (i = 0; i < MAX_PIPES; i++) {
-               struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-
-               if (pipe->stream == stream && pipe->stream_res.tg) {
-                       dc->hwss.set_drr(&pipe,
-                                       1,
-                                       *adjust);
-                       stream->adjust.timing_adjust_pending = false;
-
-                       if (dc->hwss.notify_cursor_offload_drr_update)
-                               dc->hwss.notify_cursor_offload_drr_update(dc, dc->current_state, stream);
-
-                       return true;
-               }
-       }
-
-       return false;
-}
-
 /**
  * dc_stream_get_last_used_drr_vtotal - Looks up the pipe context of
  * dc_stream_state and gets the last VTOTAL used by DRR (Dynamic Refresh Rate)
@@ -1274,6 +1205,8 @@ static void dc_update_visual_confirm_color(struct dc *dc, struct dc_state *conte
                                get_fams2_visual_confirm_color(dc, context, pipe_ctx, &(pipe_ctx->visual_confirm_color));
                        else if (dc->debug.visual_confirm == VISUAL_CONFIRM_VABC)
                                get_vabc_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
+                       else if (dc->debug.visual_confirm == VISUAL_CONFIRM_BOOSTED_REFRESH_RATE)
+                               get_refresh_rate_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
                }
        }
 }
@@ -1323,6 +1256,83 @@ void dc_get_visual_confirm_for_stream(
        }
 }
 
+/**
+ *  dc_stream_adjust_vmin_vmax - look up pipe context & update parts of DRR
+ *  @dc:     dc reference
+ *  @stream: Initial dc stream state
+ *  @adjust: Updated parameters for vertical_total_min and vertical_total_max
+ *
+ *  Looks up the pipe context of dc_stream_state and updates the
+ *  vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh
+ *  Rate, which is a power-saving feature that targets reducing panel
+ *  refresh rate while the screen is static
+ *
+ *  Return: %true if the pipe context is found and adjusted;
+ *          %false if the pipe context is not found.
+ */
+bool dc_stream_adjust_vmin_vmax(struct dc *dc,
+               struct dc_stream_state *stream,
+               struct dc_crtc_timing_adjust *adjust)
+{
+       int i;
+
+       /*
+        * Don't adjust DRR while there's bandwidth optimizations pending to
+        * avoid conflicting with firmware updates.
+        */
+       if (dc->ctx->dce_version > DCE_VERSION_MAX) {
+               if (dc->optimized_required &&
+                       (stream->adjust.v_total_max != adjust->v_total_max ||
+                       stream->adjust.v_total_min != adjust->v_total_min)) {
+                       stream->adjust.timing_adjust_pending = true;
+                       return false;
+               }
+       }
+
+       dc_exit_ips_for_hw_access(dc);
+
+       stream->adjust.v_total_max = adjust->v_total_max;
+       stream->adjust.v_total_mid = adjust->v_total_mid;
+       stream->adjust.v_total_mid_frame_num = adjust->v_total_mid_frame_num;
+       stream->adjust.v_total_min = adjust->v_total_min;
+       stream->adjust.allow_otg_v_count_halt = adjust->allow_otg_v_count_halt;
+
+       if (dc->caps.max_v_total != 0 &&
+               (adjust->v_total_max > dc->caps.max_v_total || adjust->v_total_min > dc->caps.max_v_total)) {
+               stream->adjust.timing_adjust_pending = false;
+               if (adjust->allow_otg_v_count_halt)
+                       return set_long_vtotal(dc, stream, adjust);
+               else
+                       return false;
+       }
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+               if (pipe->stream == stream && pipe->stream_res.tg) {
+                       dc->hwss.set_drr(&pipe,
+                                       1,
+                                       *adjust);
+                       stream->adjust.timing_adjust_pending = false;
+
+                       if (dc->debug.visual_confirm == VISUAL_CONFIRM_BOOSTED_REFRESH_RATE) {
+                               if (pipe->stream && pipe->plane_state) {
+                                       dc_update_visual_confirm_color(dc, dc->current_state, pipe);
+                                       dc->hwss.update_visual_confirm_color(dc, pipe, pipe->plane_res.hubp->mpcc_id);
+
+                               }
+                       }
+
+                       if (dc->hwss.notify_cursor_offload_drr_update)
+                               dc->hwss.notify_cursor_offload_drr_update(dc, dc->current_state, stream);
+
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
 {
        int i, j;
index b380044416164ebfa0065ccc976dc5d2aadfecb2..5b3695e72e196d451ae0a185fb0d5f4e4667c350 100644 (file)
@@ -4108,3 +4108,24 @@ void hwss_add_tg_get_frame_count(struct block_sequence_state *seq_state,
                (*seq_state->num_steps)++;
        }
 }
+
+
+void get_refresh_rate_confirm_color(struct pipe_ctx *pipe_ctx, struct tg_color *color)
+{
+       uint32_t color_value = MAX_TG_COLOR_VALUE;
+       unsigned int refresh_rate = 0;
+       uint32_t scaling_factor = 0;
+       if (pipe_ctx && pipe_ctx->stream && color) {
+               refresh_rate = (pipe_ctx->stream->timing.pix_clk_100hz * 100) / (pipe_ctx->stream->adjust.v_total_max * pipe_ctx->stream->timing.h_total);
+
+               uint32_t min_refresh_rate = pipe_ctx->stream->timing.min_refresh_in_uhz / 1000000;
+               uint32_t max_refresh_rate = pipe_ctx->stream->timing.max_refresh_in_uhz / 1000000;
+
+               if (max_refresh_rate - min_refresh_rate)
+                       scaling_factor = MAX_TG_COLOR_VALUE * (refresh_rate - min_refresh_rate) / (max_refresh_rate - min_refresh_rate);
+
+               pipe_ctx->visual_confirm_color.color_r_cr = color_value;
+               pipe_ctx->visual_confirm_color.color_g_y = scaling_factor;
+               pipe_ctx->visual_confirm_color.color_b_cb = color_value;
+       }
+}
index d2ea4e03c963a8e3a27968bf6c8a50f10ca52c69..7126dc278a531216b2090f7f486925f12a165bc5 100644 (file)
@@ -581,6 +581,7 @@ enum visual_confirm {
        VISUAL_CONFIRM_HW_CURSOR = 20,
        VISUAL_CONFIRM_VABC = 21,
        VISUAL_CONFIRM_DCC = 22,
+       VISUAL_CONFIRM_BOOSTED_REFRESH_RATE = 23,
        VISUAL_CONFIRM_EXPLICIT = 0x80000000,
 };
 
index d699640ba5b45dd53b4bb9d0b55d307ad9b18084..d1dba7ffcd9b3fb131e59a3e64c76b6dd6fe0fa9 100644 (file)
@@ -1365,6 +1365,10 @@ void get_dcc_visual_confirm_color(
        struct pipe_ctx *pipe_ctx,
        struct tg_color *color);
 
+void get_refresh_rate_confirm_color(
+               struct pipe_ctx *pipe_ctx,
+               struct tg_color *color);
+
 void set_p_state_switch_method(
                struct dc *dc,
                struct dc_state *context,